diff --git a/.drone.yml b/.drone.yml
index 8f06877fbaf88..57c888a7d985d 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -25,7 +25,7 @@ steps:
- make deps-frontend
- name: deps-backend
- image: golang:1.18
+ image: golang:1.19
pull: always
commands:
- make deps-backend
@@ -88,7 +88,7 @@ steps:
depends_on: [deps-frontend]
- name: checks-backend
- image: golang:1.18
+ image: golang:1.19
commands:
- make checks-backend
depends_on: [deps-backend]
@@ -122,7 +122,7 @@ steps:
path: /go
- name: build-backend-arm64
- image: golang:1.18
+ image: golang:1.19
environment:
GO111MODULE: on
GOPROXY: https://goproxy.io
@@ -138,7 +138,7 @@ steps:
path: /go
- name: build-backend-windows
- image: golang:1.18
+ image: golang:1.19
environment:
GO111MODULE: on
GOPROXY: https://goproxy.io
@@ -153,7 +153,7 @@ steps:
path: /go
- name: build-backend-386
- image: golang:1.18
+ image: golang:1.19
environment:
GO111MODULE: on
GOPROXY: https://goproxy.io
@@ -243,7 +243,7 @@ steps:
- pull_request
- name: deps-backend
- image: golang:1.18
+ image: golang:1.19
pull: always
commands:
- make deps-backend
@@ -360,7 +360,7 @@ steps:
path: /go
- name: generate-coverage
- image: golang:1.18
+ image: golang:1.19
commands:
- make coverage
environment:
@@ -436,7 +436,7 @@ steps:
- pull_request
- name: deps-backend
- image: golang:1.18
+ image: golang:1.19
pull: always
commands:
- make deps-backend
@@ -578,7 +578,7 @@ trigger:
steps:
- name: download
- image: golang:1.18
+ image: golang:1.19
pull: always
commands:
- timeout -s ABRT 40m make generate-license generate-gitignore
@@ -640,7 +640,7 @@ steps:
- make deps-frontend
- name: deps-backend
- image: golang:1.18
+ image: golang:1.19
pull: always
commands:
- make deps-backend
@@ -649,10 +649,11 @@ steps:
path: /go
- name: static
- image: techknowlogick/xgo:go-1.18.x
+ image: techknowlogick/xgo:go-1.19.x
pull: always
commands:
- - curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get install -y nodejs
+ # Upgrade to node 18 once https://github.com/techknowlogick/xgo/issues/163 is resolved
+ - curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
- export PATH=$PATH:$GOPATH/bin
- make release
environment:
@@ -759,7 +760,7 @@ steps:
- make deps-frontend
- name: deps-backend
- image: golang:1.18
+ image: golang:1.19
pull: always
commands:
- make deps-backend
@@ -768,10 +769,11 @@ steps:
path: /go
- name: static
- image: techknowlogick/xgo:go-1.18.x
+ image: techknowlogick/xgo:go-1.19.x
pull: always
commands:
- - curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get install -y nodejs
+ # Upgrade to node 18 once https://github.com/techknowlogick/xgo/issues/163 is resolved
+ - curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
- export PATH=$PATH:$GOPATH/bin
- make release
environment:
diff --git a/.editorconfig b/.editorconfig
index 0f8603e5a29e7..c0946ac9975cd 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -26,6 +26,3 @@ indent_style = tab
[*.svg]
insert_final_newline = false
-
-[*.md]
-trim_trailing_whitespace = false
diff --git a/.eslintrc.yaml b/.eslintrc.yaml
index ff62d9cc93b00..4cc4060c5837f 100644
--- a/.eslintrc.yaml
+++ b/.eslintrc.yaml
@@ -11,12 +11,8 @@ parserOptions:
plugins:
- eslint-plugin-unicorn
- eslint-plugin-import
- - eslint-plugin-vue
- - eslint-plugin-html
- eslint-plugin-jquery
-
-extends:
- - plugin:vue/recommended
+ - eslint-plugin-sonarjs
env:
es2022: true
@@ -25,23 +21,16 @@ env:
globals:
__webpack_public_path__: true
-settings:
- html/html-extensions: [".tmpl"]
-
overrides:
- - files: ["web_src/**/*.js", "web_src/**/*.vue", "templates/**/*.tmpl"]
+ - files: ["web_src/**/*.js", "docs/**/*.js"]
env:
browser: true
node: false
- - files: ["templates/**/*.tmpl"]
- rules:
- no-tabs: [0]
- indent: [2, tab, {SwitchCase: 1}]
- files: ["web_src/**/*worker.js"]
env:
worker: true
rules:
- no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top]
+ no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top]
- files: ["build/generate-images.js"]
rules:
import/no-unresolved: [0]
@@ -120,7 +109,7 @@ rules:
import/no-extraneous-dependencies: [2]
import/no-import-module-exports: [0]
import/no-internal-modules: [0]
- import/no-mutable-exports: [2]
+ import/no-mutable-exports: [0]
import/no-named-as-default-member: [0]
import/no-named-as-default: [2]
import/no-named-default: [0]
@@ -132,7 +121,7 @@ rules:
import/no-restricted-paths: [0]
import/no-self-import: [2]
import/no-unassigned-import: [0]
- import/no-unresolved: [2, {commonjs: true}]
+ import/no-unresolved: [2, {commonjs: true, ignore: ["\\?.+$"]}]
import/no-unused-modules: [2, {unusedExports: true}]
import/no-useless-path-segments: [2, {commonjs: true}]
import/no-webpack-loader-syntax: [2]
@@ -222,7 +211,7 @@ rules:
no-compare-neg-zero: [2]
no-cond-assign: [2, except-parens]
no-confusing-arrow: [0]
- no-console: [1, {allow: [info, warn, error]}]
+ no-console: [1, {allow: [debug, info, warn, error]}]
no-const-assign: [2]
no-constant-binary-expression: [2]
no-constant-condition: [0]
@@ -298,7 +287,7 @@ rules:
no-redeclare: [2]
no-regex-spaces: [2]
no-restricted-exports: [0]
- no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top]
+ no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top, __dirname, __filename]
no-restricted-imports: [0]
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement]
no-return-assign: [0]
@@ -332,7 +321,7 @@ rules:
no-unused-labels: [2]
no-unused-private-class-members: [2]
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_, ignoreRestSiblings: false}]
- no-use-before-define: [2, nofunc]
+ no-use-before-define: [2, {functions: false, classes: true, variables: true, allowNamedExports: true}]
no-useless-backreference: [0]
no-useless-call: [2]
no-useless-catch: [2]
@@ -358,7 +347,7 @@ rules:
padded-blocks: [2, never]
padding-line-between-statements: [0]
prefer-arrow-callback: [2, {allowNamedFunctions: true, allowUnboundThis: true}]
- prefer-const: [2, {destructuring: all}]
+ prefer-const: [2, {destructuring: all, ignoreReadBeforeAssign: true}]
prefer-destructuring: [0]
prefer-exponentiation-operator: [2]
prefer-named-capture-group: [0]
@@ -381,6 +370,38 @@ rules:
semi-spacing: [2, {before: false, after: true}]
semi-style: [2, last]
semi: [2, always, {omitLastInOneLineBlock: true}]
+ sonarjs/cognitive-complexity: [0]
+ sonarjs/elseif-without-else: [0]
+ sonarjs/max-switch-cases: [0]
+ sonarjs/no-all-duplicated-branches: [2]
+ sonarjs/no-collapsible-if: [0]
+ sonarjs/no-collection-size-mischeck: [2]
+ sonarjs/no-duplicate-string: [0]
+ sonarjs/no-duplicated-branches: [0]
+ sonarjs/no-element-overwrite: [2]
+ sonarjs/no-empty-collection: [2]
+ sonarjs/no-extra-arguments: [0]
+ sonarjs/no-gratuitous-expressions: [2]
+ sonarjs/no-identical-conditions: [2]
+ sonarjs/no-identical-expressions: [0]
+ sonarjs/no-identical-functions: [0]
+ sonarjs/no-ignored-return: [2]
+ sonarjs/no-inverted-boolean-check: [2]
+ sonarjs/no-nested-switch: [0]
+ sonarjs/no-nested-template-literals: [0]
+ sonarjs/no-one-iteration-loop: [2]
+ sonarjs/no-redundant-boolean: [2]
+ sonarjs/no-redundant-jump: [0]
+ sonarjs/no-same-line-conditional: [2]
+ sonarjs/no-small-switch: [0]
+ sonarjs/no-unused-collection: [2]
+ sonarjs/no-use-of-empty-return-value: [2]
+ sonarjs/no-useless-catch: [0]
+ sonarjs/non-existent-operator: [2]
+ sonarjs/prefer-immediate-return: [0]
+ sonarjs/prefer-object-literal: [0]
+ sonarjs/prefer-single-boolean-return: [0]
+ sonarjs/prefer-while: [2]
sort-imports: [0]
sort-keys: [0]
sort-vars: [0]
@@ -428,7 +449,7 @@ rules:
unicorn/no-new-array: [0]
unicorn/no-new-buffer: [0]
unicorn/no-null: [0]
- unicorn/no-object-as-default-parameter: [2]
+ unicorn/no-object-as-default-parameter: [0]
unicorn/no-process-exit: [0]
unicorn/no-reduce: [2]
unicorn/no-static-only-class: [2]
@@ -454,14 +475,16 @@ rules:
unicorn/prefer-array-index-of: [2]
unicorn/prefer-array-some: [2]
unicorn/prefer-at: [0]
- unicorn/prefer-code-point: [2]
+ unicorn/prefer-code-point: [0]
unicorn/prefer-dataset: [2]
unicorn/prefer-date-now: [2]
unicorn/prefer-default-parameters: [0]
unicorn/prefer-event-key: [2]
+ unicorn/prefer-event-target: [2]
unicorn/prefer-export-from: [2]
unicorn/prefer-includes: [2]
unicorn/prefer-json-parse-buffer: [0]
+ unicorn/prefer-logical-operator-over-ternary: [2]
unicorn/prefer-math-trunc: [2]
unicorn/prefer-modern-dom-apis: [0]
unicorn/prefer-modern-math-apis: [2]
@@ -502,11 +525,6 @@ rules:
use-isnan: [2]
valid-typeof: [2, {requireStringLiterals: true}]
vars-on-top: [0]
- vue/attributes-order: [0]
- vue/component-definition-name-casing: [0]
- vue/html-closing-bracket-spacing: [0]
- vue/max-attributes-per-line: [0]
- vue/one-component-per-file: [0]
wrap-iife: [2, inside]
wrap-regex: [0]
yield-star-spacing: [2, after]
diff --git a/.golangci.yml b/.golangci.yml
index 11c58454a0073..6e80af8c0eb29 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -29,7 +29,7 @@ linters:
fast: false
run:
- go: 1.18
+ go: 1.19
timeout: 10m
skip-dirs:
- node_modules
@@ -75,7 +75,7 @@ linters-settings:
- name: modifies-value-receiver
gofumpt:
extra-rules: true
- lang-version: "1.18"
+ lang-version: "1.19"
depguard:
# TODO: use depguard to replace import checks in gitea-vet
list-type: denylist
diff --git a/.markdownlint.yaml b/.markdownlint.yaml
new file mode 100644
index 0000000000000..7ccdd53e89793
--- /dev/null
+++ b/.markdownlint.yaml
@@ -0,0 +1,18 @@
+commands-show-output: false
+fenced-code-language: false
+first-line-h1: false
+header-increment: false
+line-length: {code_blocks: false, tables: false, stern: true, line_length: -1}
+no-alt-text: false
+no-bare-urls: false
+no-blanks-blockquote: false
+no-duplicate-header: {allow_different_nesting: true}
+no-emphasis-as-header: false
+no-empty-links: false
+no-hard-tabs: {code_blocks: false}
+no-inline-html: false
+no-space-in-code: false
+no-space-in-emphasis: false
+no-trailing-punctuation: false
+no-trailing-spaces: {br_spaces: 0}
+single-h1: false
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 454853fe2918c..ea2380d9b1adf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -155,12 +155,12 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Don't show context cancelled errors in attribute reader (#19006) (#19027)
* Fix update hint bug (#18996) (#19002)
* MISC
- * Fix potential assignee query for repo (#18994) (#18999)
+ * Fix potential assignee query for repo (#18994) (#18999)
## [1.16.3](https://github.com/go-gitea/gitea/releases/tag/v1.16.3) - 2022-03-02
* SECURITY
- * Git backend ignore replace objects (#18979) (#18980)
+* Git backend ignore replace objects (#18979) (#18980)
* ENHANCEMENTS
* Adjust error for already locked db and prevent level db lock on malformed connstr (#18923) (#18938)
* BUGFIXES
@@ -193,7 +193,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Immediately Hammer if second kill is sent (#18823) (#18826)
* Allow mermaid render error to wrap (#18791)
* BUGFIXES
- * Fix ldap user sync missed email in email_address table (#18786) (#18876)
+ * Fix ldap user sync missed email in email_address table (#18786) (#18876)
* Update assignees check to include any writing team and change org sidebar (#18680) (#18873)
* Don't report signal: killed errors in serviceRPC (#18850) (#18865)
* Fix bug where certain LDAP settings were reverted (#18859)
@@ -692,6 +692,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Fix SVG side by side comparison link (#17375) (#17391)
## [1.15.4](https://github.com/go-gitea/gitea/releases/tag/v1.15.4) - 2021-10-08
+
* BUGFIXES
* Raw file API: don't try to interpret 40char filenames as commit SHA (#17185) (#17272)
* Don't allow merged PRs to be reopened (#17192) (#17271)
@@ -1338,7 +1339,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Add size to Save function (#15264) (#15270)
* Monaco improvements (#15333) (#15345)
* Support .mailmap in code activity stats (#15009)
- * Sort release attachments by name (#15008)
+ * Sort release attachments by name (#15008)
* Add ui.explore settings to control view of explore pages (#14094)
* Make internal SSH server host key path configurable (#14918)
* Hide resync all ssh principals when using internal ssh server (#14904)
@@ -1633,6 +1634,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Return original URL of Repositories (#13885) (#13886)
## [1.13.0](https://github.com/go-gitea/gitea/releases/tag/v1.13.0) - 2020-12-01
+
* SECURITY
* Add Allow-/Block-List for Migrate & Mirrors (#13610) (#13776)
* Prevent git operations for inactive users (#13527) (#13536)
@@ -2546,6 +2548,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Blacklist manifest.json & milestones user (#10292) (#10293)
## [1.11.0](https://github.com/go-gitea/gitea/releases/tag/v1.11.0) - 2020-02-10
+
* BREAKING
* Fix followers and following tabs in profile (#10202) (#10203)
* Make CertFile and KeyFile relative to CustomPath (#9868) (#9874)
@@ -2998,7 +3001,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
This is a re-tag version of v1.10.5 and also explicitly built with Go 1.13.
-WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be used.
+WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be used.
## [1.10.5](https://github.com/go-gitea/gitea/releases/tag/v1.10.5) - 2020-03-06
@@ -3019,6 +3022,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Ensure that 2fa is checked on reset-password (#9857) (#9877)
## [1.10.3](https://github.com/go-gitea/gitea/releases/tag/v1.10.3) - 2020-01-17
+
* SECURITY
* Hide credentials when submitting migration (#9102) (#9704)
* Never allow an empty password to validate (#9682) (#9684)
@@ -3037,6 +3041,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Branches not at ref commit ID should not be listed as Merged (#9614) (#9639)
## [1.10.2](https://github.com/go-gitea/gitea/releases/tag/v1.10.2) - 2020-01-02
+
* BUGFIXES
* Allow only specific Columns to be updated on Issue via API (#9539) (#9580)
* Add ErrReactionAlreadyExist error (#9550) (#9564)
@@ -3057,6 +3062,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix File Edit: Author/Committer interchanged (#9297) (#9300)
## [1.10.1](https://github.com/go-gitea/gitea/releases/tag/v1.10.1) - 2019-12-05
+
* BUGFIXES
* Fix max length check and limit in multiple repo forms (#9148) (#9204)
* Properly fix displaying virtual session provider in admin panel (#9137) (#9203)
@@ -3078,6 +3084,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Shadow password correctly for session config (#8984) (#9002)
## [1.10.0](https://github.com/go-gitea/gitea/releases/tag/v1.10.0) - 2019-11-13
+
* BREAKING
* Fix deadline on update issue or PR via API (#8698)
* Hide some user information via API if user doesn't have enough permission (#8655) (#8657)
@@ -3375,6 +3382,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix Statuses API only shows first 10 statuses: Add paging and extend API GetCommitStatuses (#7141)
## [1.9.6](https://github.com/go-gitea/gitea/releases/tag/v1.9.6) - 2019-11-13
+
* BUGFIXES
* Allow to merge if file path contains " or \ (#8629) (#8772)
* Fix 500 when edit hook (#8782) (#8790)
@@ -3383,6 +3391,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Add Close() method to gogitRepository (#8901) (#8958)
## [1.9.5](https://github.com/go-gitea/gitea/releases/tag/v1.9.5) - 2019-10-30
+
* BREAKING
* Hide some user information via API if user doesn't have enough permission (#8655) (#8658)
* BUGFIXES
@@ -3407,6 +3416,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Update heatmap fixtures to restore tests (#8615) (#8617)
## [1.9.4](https://github.com/go-gitea/gitea/releases/tag/v1.9.4) - 2019-10-08
+
* BUGFIXES
* Highlight issue references (#8101) (#8404)
* Fix bug when migrating a private repository #7917 (#8403)
@@ -3433,6 +3443,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Make show private icon when repo avatar set (#8144) (#8175)
## [1.9.3](https://github.com/go-gitea/gitea/releases/tag/v1.9.3) - 2019-09-06
+
* BUGFIXES
* Fix go get from a private repository with Go 1.13 (#8100)
* Strict name matching for Repository.GetTagID() (#8082)
@@ -3448,6 +3459,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Keep blame view buttons sequence consistent with normal view when viewing a file (#8007) (#8009)
## [1.9.2](https://github.com/go-gitea/gitea/releases/tag/v1.9.2) - 2019-08-22
+
* BUGFIXES
* Fix wrong sender when send slack webhook (#7918) (#7924)
* Upload support text/plain; charset=utf8 (#7899)
@@ -3462,6 +3474,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Drone/docker: prepare multi-arch release + provide arm64 image (#7571) (#7884)
## [1.9.1](https://github.com/go-gitea/gitea/releases/tag/v1.9.1) - 2019-08-14
+
* BREAKING
* Add pagination for admin api get orgs and fix only list public orgs bug (#7742) (#7752)
* SECURITY
@@ -3489,6 +3502,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Correct wrong datetime format for git (#7689) (#7690)
## [1.9.0](https://github.com/go-gitea/gitea/releases/tag/v1.9.0) - 2019-07-30
+
* BREAKING
* Better logging (#6038) (#6095)
* SECURITY
@@ -3845,6 +3859,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Added docker example for backup (#5846)
## [1.8.3](https://github.com/go-gitea/gitea/releases/tag/v1.8.3) - 2019-06-17
+
* BUGFIXES
* Always set userID on LFS authentication (#7224) (Part of #6993)
* Fix LFS Locks over SSH (#6999) (#7223)
@@ -3855,6 +3870,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix GCArgs load from ini (#7156) (#7157)
## [1.8.2](https://github.com/go-gitea/gitea/releases/tag/v1.8.2) - 2019-05-29
+
* BUGFIXES
* Fix possbile mysql invalid connnection error (#7051) (#7071)
* Handle invalid administrator username on install page (#7060) (#7063)
@@ -3870,6 +3886,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix wrong init dependency on markup extensions (#7038) (#7074)
## [1.8.1](https://github.com/go-gitea/gitea/releases/tag/v1.8.1) - 2019-05-08
+
* BUGFIXES
* Fix 404 when sending pull requests in some situations (#6871) (#6873)
* Enforce osusergo build tag for releases (#6862) (#6869)
@@ -3896,6 +3913,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix config ui error about cache ttl (#6861) (#6865)
## [1.8.0](https://github.com/go-gitea/gitea/releases/tag/v1.8.0) - 2019-04-20
+
* SECURITY
* Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6594)
* Resolve 2FA bypass on API (#6676) (#6674)
@@ -4130,18 +4148,21 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Migrate database if app.ini found (#5290)
## [1.7.6](https://github.com/go-gitea/gitea/releases/tag/v1.7.6) - 2019-04-12
+
* SECURITY
* Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6595)
* BUGFIXES
* Allow resend of confirmation email when logged in (#6482) (#6487)
## [1.7.5](https://github.com/go-gitea/gitea/releases/tag/v1.7.5) - 2019-03-27
+
* BUGFIXES
* Fix unitTypeCode not being used in accessLevelUnit (#6419) (#6423)
* Fix bug where manifest.json was being requested without cookies and continuously creating new sessions (#6372) (#6383)
* Fix ParsePatch function to work with quoted diff --git strings (#6323) (#6332)
## [1.7.4](https://github.com/go-gitea/gitea/releases/tag/v1.7.4) - 2019-03-12
+
* SECURITY
* Fix potential XSS vulnerability in repository description. (#6306) (#6308)
* BUGFIXES
@@ -4151,6 +4172,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix displaying dashboard even if required to change password (#6214) (#6215)
## [1.7.3](https://github.com/go-gitea/gitea/releases/tag/v1.7.3) - 2019-02-27
+
* BUGFIXES
* Fix server 500 when trying to migrate to an already existing repository (#6188) (#6197)
* Load Issue attributes for API /repos/{owner}/{repo}/issues/{index} (#6122) (#6185)
@@ -4165,6 +4187,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Recover panic in orgmode.Render if bad orgfile (#4982) (#5903) (#6097)
## [1.7.2](https://github.com/go-gitea/gitea/releases/tag/v1.7.2) - 2019-02-14
+
* BUGFIXES
* Remove all CommitStatus when a repo is deleted (#5940) (#5941)
* Fix notifications on pushing with deploy keys by setting hook environment variables (#5935) (#5944)
@@ -4181,6 +4204,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* In basic auth check for tokens before call UserSignIn (#5725) (#6083)
## [1.7.1](https://github.com/go-gitea/gitea/releases/tag/v1.7.1) - 2019-01-31
+
* SECURITY
* Disable redirect for i18n (#5910) (#5916)
* Only allow local login if password is non-empty (#5906) (#5908)
@@ -4202,6 +4226,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Include Go toolchain to --version (#5832) (#5830)
## [1.7.0](https://github.com/go-gitea/gitea/releases/tag/v1.7.0) - 2019-01-22
+
* SECURITY
* Do not display the raw OpenID error in the UI (#5705) (#5712)
* When redirecting clean the path to avoid redirecting to external site (#5669) (#5679)
@@ -4358,18 +4383,21 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Only chown directories during docker setup if necessary. Fix #4425 (#5064)
## [1.6.4](https://github.com/go-gitea/gitea/releases/tag/v1.6.4) - 2019-01-15
+
* BUGFIX
* Fix SSH key now can be reused as public key after deleting as deploy key (#5671) (#5685)
* When redirecting clean the path to avoid redirecting to external site (#5669) (#5703)
* Fix to use correct value for "MSpan Structures Obtained" (#5706) (#5715)
## [1.6.3](https://github.com/go-gitea/gitea/releases/tag/v1.6.3) - 2019-01-04
+
* SECURITY
* Prevent DeleteFilePost doing arbitrary deletion (#5631)
* BUGFIX
* Fix wrong text getting saved on editing second comment on an issue (#5608)
## [1.6.2](https://github.com/go-gitea/gitea/releases/tag/v1.6.2) - 2018-12-21
+
* SECURITY
* Sanitize uploaded file names (#5571) (#5573)
* HTMLEncode user added text (#5570) (#5575)
@@ -4384,6 +4412,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix empty wiki (#5504) (#5508)
## [1.6.1](https://github.com/go-gitea/gitea/releases/tag/v1.6.1) - 2018-12-08
+
* BUGFIXES
* Fix dependent issue searching when gitea is run in subpath (#5392) (#5400)
* API: '/orgs/:org/repos': return private repos with read access (#5393)
@@ -4394,6 +4423,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix topic name length on database (#5493) (#5495)
## [1.6.0](https://github.com/go-gitea/gitea/releases/tag/v1.6.0) - 2018-11-22
+
* BREAKING
* Respect email privacy option in user search via API (#4512)
* Simply remove tidb and deps (#3993)
@@ -4547,10 +4577,12 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix translation (#4355)
## [1.5.3](https://github.com/go-gitea/gitea/releases/tag/v1.5.3) - 2018-10-31
+
* SECURITY
* Fix remote command execution vulnerability in upstream library (#5177) (#5196)
## [1.5.2](https://github.com/go-gitea/gitea/releases/tag/v1.5.2) - 2018-10-09
+
* SECURITY
* Enforce token on api routes (#4840) (#4905)
* BUGFIXES
@@ -4567,6 +4599,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix trimming of markup section names (#4864)
## [1.5.1](https://github.com/go-gitea/gitea/releases/tag/v1.5.1) - 2018-09-03
+
* SECURITY
* Don't disclose emails of all users when sending out emails (#4784)
* Improve URL validation for external wiki and external issues (#4710) (#4740)
@@ -4581,6 +4614,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix incorrect caption of webhook setting (#4701) (#4718)
## [1.5.0](https://github.com/go-gitea/gitea/releases/tag/v1.5.0) - 2018-08-10
+
* SECURITY
* Check that repositories can only be migrated to own user or organizations (#4366) (#4370)
* Limit uploaded avatar image-size to 4096px x 3072px by default (#4353)
@@ -4644,6 +4678,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Sign release binaries (#4188)
## [1.4.3](https://github.com/go-gitea/gitea/releases/tag/v1.4.3) - 2018-06-26
+
* SECURITY
* HTML-escape plain-text READMEs (#4192) (#4214)
* Fix open redirect vulnerability on login screen (#4312) (#4312)
@@ -4656,6 +4691,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix webhook type conflation (#4285) (#4285)
## [1.4.2](https://github.com/go-gitea/gitea/releases/tag/v1.4.2) - 2018-06-04
+
* BUGFIXES
* Adjust z-index for floating labels (#3939) (#3950)
* Add missing token validation on application settings page (#3976) #3978
@@ -4671,6 +4707,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Respository's home page not updated after first push (#4075)
## [1.4.1](https://github.com/go-gitea/gitea/releases/tag/v1.4.1) - 2018-05-03
+
* BREAKING
* Add "error" as reserved username (#3882) (#3886)
* SECURITY
@@ -4688,6 +4725,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Show clipboard button if disable HTTP of git protocol (#3773) (#3774)
## [1.4.0](https://github.com/go-gitea/gitea/releases/tag/v1.4.0) - 2018-03-25
+
* BREAKING
* Drop deprecated GOGS\_WORK\_DIR use (#2946)
* Fix API status code for hook creation (#2814)
@@ -4807,6 +4845,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Add owner to delete repo message (#2886)
## [1.3.1](https://github.com/go-gitea/gitea/releases/tag/v1.3.1) - 2017-12-08
+
* BUGFIXES
* Sanitize logs for mirror sync (#3057, #3082) (#3078)
* Fix missing branch in release bug (#3108) (#3117)
@@ -4817,6 +4856,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix missing password length check when change password (#3039) (#3071)
## [1.3.0](https://github.com/go-gitea/gitea/releases/tag/v1.3.0) - 2017-11-29
+
* BREAKING
* Make URL scheme unambiguous (#2408)
* FEATURES
@@ -5044,11 +5084,13 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Added vendor dir for js/css libs; Documented sources (#1484) (#2241)
## [1.2.3](https://github.com/go-gitea/gitea/releases/tag/v1.2.3) - 2017-11-03
+
* BUGFIXES
* Only require one email when validating GPG key (#2266, #2467, #2663) (#2788)
* Fix order of comments (#2835) (#2839)
## [1.2.2](https://github.com/go-gitea/gitea/releases/tag/v1.2.2) - 2017-10-26
+
* BUGFIXES
* Add checks for commits with missing author and time (#2771) (#2785)
* Fix sending mail with a non-latin display name (#2559) (#2783)
@@ -5057,6 +5099,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix emojify image URL (#2769) (#2773)
## [1.2.1](https://github.com/go-gitea/gitea/releases/tag/v1.2.1) - 2017-10-16
+
* BUGFIXES
* Fix PR, milestone and label functionality if issue unit is disabled (#2710) (#2714)
* Fix plain readme didn't render correctly on repo home page (#2705) (#2712)
@@ -5065,6 +5108,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix slice out of bounds error in mailer (#2479) (#2696)
## [1.2.0](https://github.com/go-gitea/gitea/releases/tag/v1.2.0) - 2017-10-10
+
* SECURITY
* Sanitation fix from Gogs (#1461)
* BREAKING
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 45344a4d7bbb5..61ab3de4b9487 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -81,12 +81,12 @@ Here's how to run the test suite:
|``make lint-frontend`` | lint frontend files |
|``make lint-backend`` | lint backend files |
-- run test code (Suggest run in Linux)
+- run test code (Suggest run in Linux)
| | |
| :------------------------------------- | :----------------------------------------------- |
|``make test[\#TestSpecificName]`` | run unit test |
-|``make test-sqlite[\#TestSpecificName]``| run [integration](integrations) test for SQLite |
+|``make test-sqlite[\#TestSpecificName]``| run [integration](integrations) test for SQLite |
|[More details about integrations](integrations/README.md) |
## Vendoring
@@ -127,14 +127,14 @@ the *[How to get faster PR reviews](https://github.com/kubernetes/community/blob
it has lots of useful tips for any project you may want to contribute.
Some of the key points:
-* Make small pull requests. The smaller, the faster to review and the
+- Make small pull requests. The smaller, the faster to review and the
more likely it will be merged soon.
-* Don't make changes unrelated to your PR. Maybe there are typos on
+- Don't make changes unrelated to your PR. Maybe there are typos on
some comments, maybe refactoring would be welcome on a function... but
if that is not related to your PR, please make *another* PR for that.
-* Split big pull requests into multiple small ones. An incremental change
+- Split big pull requests into multiple small ones. An incremental change
will be faster to review than a huge PR.
-* Use the first comment as a summary explainer of your PR and you should keep this up-to-date as the PR evolves.
+- Use the first comment as a summary explainer of your PR and you should keep this up-to-date as the PR evolves.
If your PR could cause a breaking change you must add a BREAKING section to this comment e.g.:
@@ -146,7 +146,8 @@ To explain how this could affect users and how to mitigate these changes.
## Styleguide
-For imports you should use the following format (_without_ the comments)
+For imports you should use the following format (*without* the comments)
+
```go
import (
// stdlib
@@ -181,11 +182,15 @@ To maintain understandable code and avoid circular dependencies it is important
## API v1
The API is documented by [swagger](http://try.gitea.io/api/swagger) and is based on [GitHub API v3](https://developer.github.com/v3/).
-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.
-If Gitea provides functionality that GitHub does not, a new endpoint can be created.
+
+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.
+
+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 APIv2 (which is currently not planned).
All expected results (errors, success, fail messages) should be documented
@@ -194,28 +199,33 @@ All expected results (errors, success, fail messages) should be documented
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).
+[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))
+([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:
- * **GET** endpoints return requested object and status **OK (200)**
- * **DELETE** endpoints return status **No Content (204)**
- * **POST** endpoints return status **Created (201)**, used to **create** new objects (e.g. a User)
- * **PUT** endpoints return status **No Content (204)**, used to **add/assign** existing Objects (e.g. User) to something (e.g. Org-Team)
- * **PATCH** endpoints return changed object and status **OK (200)**, used to **edit/change** an existing object
+
+- **GET** endpoints return requested object and status **OK (200)**
+- **DELETE** endpoints return status **No Content (204)**
+- **POST** endpoints return status **Created (201)**, used to **create** new objects (e.g. a User)
+- **PUT** endpoints return status **No Content (204)**, used to **add/assign** existing Objects (e.g. User) to something (e.g. Org-Team)
+- **PATCH** endpoints return changed object and status **OK (200)**, used to **edit/change** an existing object
An endpoint which changes/edits an object expects all fields to be optional (except ones to identify the object, which are required).
+
### Endpoints returning lists should
- * 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))
+
+- 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))
## Large Character Comments
@@ -368,35 +378,35 @@ and lead the development of Gitea.
To honor the past owners, 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)
- * [Matti Ranta](https://gitea.com/techknowlogick)
- * [Andrew Thornton](https://gitea.com/zeripath)
+- 2022-01-01 ~ 2022-12-31 - https://github.com/go-gitea/gitea/issues/17872
+ - [Lunny Xiao](https://gitea.com/lunny)
+ - [Matti Ranta](https://gitea.com/techknowlogick)
+ - [Andrew Thornton](https://gitea.com/zeripath)
-* 2021-01-01 ~ 2021-12-31 - https://github.com/go-gitea/gitea/issues/13801
- * [Lunny Xiao](https://gitea.com/lunny)
- * [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks)
- * [Matti Ranta](https://gitea.com/techknowlogick)
+- 2021-01-01 ~ 2021-12-31 - https://github.com/go-gitea/gitea/issues/13801
+ - [Lunny Xiao](https://gitea.com/lunny)
+ - [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks)
+ - [Matti Ranta](https://gitea.com/techknowlogick)
-* 2020-01-01 ~ 2020-12-31 - https://github.com/go-gitea/gitea/issues/9230
- * [Lunny Xiao](https://gitea.com/lunny)
- * [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks)
- * [Matti Ranta](https://gitea.com/techknowlogick)
+- 2020-01-01 ~ 2020-12-31 - https://github.com/go-gitea/gitea/issues/9230
+ - [Lunny Xiao](https://gitea.com/lunny)
+ - [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks)
+ - [Matti Ranta](https://gitea.com/techknowlogick)
-* 2019-01-01 ~ 2019-12-31 - https://github.com/go-gitea/gitea/issues/5572
- * [Lunny Xiao](https://github.com/lunny)
- * [Lauris Bukšis-Haberkorns](https://github.com/lafriks)
- * [Matti Ranta](https://github.com/techknowlogick)
+- 2019-01-01 ~ 2019-12-31 - https://github.com/go-gitea/gitea/issues/5572
+ - [Lunny Xiao](https://github.com/lunny)
+ - [Lauris Bukšis-Haberkorns](https://github.com/lafriks)
+ - [Matti Ranta](https://github.com/techknowlogick)
-* 2018-01-01 ~ 2018-12-31 - https://github.com/go-gitea/gitea/issues/3255
- * [Lunny Xiao](https://github.com/lunny)
- * [Lauris Bukšis-Haberkorns](https://github.com/lafriks)
- * [Kim Carlbäcker](https://github.com/bkcsoft)
+- 2018-01-01 ~ 2018-12-31 - https://github.com/go-gitea/gitea/issues/3255
+ - [Lunny Xiao](https://github.com/lunny)
+ - [Lauris Bukšis-Haberkorns](https://github.com/lafriks)
+ - [Kim Carlbäcker](https://github.com/bkcsoft)
-* 2016-11-04 ~ 2017-12-31
- * [Lunny Xiao](https://github.com/lunny)
- * [Thomas Boerger](https://github.com/tboerger)
- * [Kim Carlbäcker](https://github.com/bkcsoft)
+- 2016-11-04 ~ 2017-12-31
+ - [Lunny Xiao](https://github.com/lunny)
+ - [Thomas Boerger](https://github.com/tboerger)
+ - [Kim Carlbäcker](https://github.com/bkcsoft)
## Versions
@@ -413,20 +423,20 @@ be reviewed by two maintainers and must pass the automatic tests.
## Releasing Gitea
-* Let $vmaj, $vmin and $vpat be Major, Minor and Patch version numbers, $vpat should be rc1, rc2, 0, 1, ...... $vmaj.$vmin will be kept the same as milestones on github or gitea in future.
-* Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody against in about serval hours.
-* If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps:
- * Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`.
- * When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin`
-* If it is bugfix version create PR for changelog on branch `release/v$vmaj.$vmin` and wait till it is reviewed and merged.
-* Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`.
-* 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.
-* 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.io and GitHub releases. Once ACKed:
- * bump the version of https://dl.gitea.io/gitea/version.json
- * merge the blog post PR
- * announce the release in discord `#announcements`
+- Let $vmaj, $vmin and $vpat be Major, Minor and Patch version numbers, $vpat should be rc1, rc2, 0, 1, ...... $vmaj.$vmin will be kept the same as milestones on github or gitea in future.
+- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody against in about serval hours.
+- If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps:
+ - Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`.
+ - When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin`
+- If it is bugfix version create PR for changelog on branch `release/v$vmaj.$vmin` and wait till it is reviewed and merged.
+- Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`.
+- 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.
+- 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.io and GitHub releases. Once ACKed:
+ - bump the version of https://dl.gitea.io/gitea/version.json
+ - merge the blog post PR
+ - announce the release in discord `#announcements`
## Copyright
diff --git a/Dockerfile b/Dockerfile
index e092b5813be49..d5d98e69a83c6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
#Build stage
-FROM golang:1.18-alpine3.16 AS build-env
+FROM golang:1.19-alpine3.16 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}
diff --git a/Dockerfile.rootless b/Dockerfile.rootless
index c597fb29c856d..8c2b8e98c95ac 100644
--- a/Dockerfile.rootless
+++ b/Dockerfile.rootless
@@ -1,5 +1,5 @@
#Build stage
-FROM golang:1.18-alpine3.16 AS build-env
+FROM golang:1.19-alpine3.16 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}
diff --git a/Makefile b/Makefile
index 41d39b4c32328..77aac782e1133 100644
--- a/Makefile
+++ b/Makefile
@@ -23,13 +23,13 @@ SHASUM ?= shasum -a 256
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
COMMA := ,
-XGO_VERSION := go-1.18.x
+XGO_VERSION := go-1.19.x
-AIR_PACKAGE ?= github.com/cosmtrek/air@v1.29.0
-EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.4.0
-ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.0
+AIR_PACKAGE ?= github.com/cosmtrek/air@v1.40.4
+EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.5.0
+ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.1
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.1
-GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.0
+GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.47.0
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.29.0
@@ -201,9 +201,9 @@ help:
.PHONY: go-check
go-check:
- $(eval MIN_GO_VERSION_STR := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2))
- $(eval MIN_GO_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_GO_VERSION_STR)' | tr '.' ' ')))
- $(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
+ $(eval MIN_GO_VERSION_STR := $(shell grep -Eo '^go\s+[0-9]+\.[0-9]+' go.mod | cut -d' ' -f2))
+ $(eval MIN_GO_VERSION := $(shell printf "%03d%03d" $(shell echo '$(MIN_GO_VERSION_STR)' | tr '.' ' ')))
+ $(eval GO_VERSION := $(shell printf "%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9]+' | tr '.' ' ');))
@if [ "$(GO_VERSION)" -lt "$(MIN_GO_VERSION)" ]; then \
echo "Gitea requires Go $(MIN_GO_VERSION_STR) or greater to build. You can get it at https://go.dev/dl/"; \
exit 1; \
@@ -310,9 +310,10 @@ lint: lint-frontend lint-backend
.PHONY: lint-frontend
lint-frontend: node_modules
- npx eslint --color --max-warnings=0 web_src/js build templates *.config.js docs/assets/js
+ npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js docs/assets/js
npx stylelint --color --max-warnings=0 web_src/less
npx spectral lint -q -F hint $(SWAGGER_SPEC)
+ npx markdownlint docs *.md
.PHONY: lint-backend
lint-backend: golangci-lint vet editorconfig-checker
diff --git a/README.md b/README.md
index 6c5952894aca9..80f1159aea1fa 100644
--- a/README.md
+++ b/README.md
@@ -45,21 +45,21 @@
## Purpose
The goal of this project is to make the easiest, fastest, and most
painless way of setting up a self-hosted Git service.
-Using Go, this can be done with an independent binary distribution across
-**all platforms** which Go supports, including Linux, macOS, and Windows
-on x86, amd64, ARM and PowerPC architectures.
-Want to try it before doing anything else?
-Do it [with the online demo](https://try.gitea.io/)!
+
+As Gitea is written in Go, it works across **all** the platforms and
+architectures that are supported by Go, including Linux, macOS, and
+Windows on x86, amd64, ARM and PowerPC architectures.
+You can try it out using [the online demo](https://try.gitea.io/).
This project has been
[forked](https://blog.gitea.io/2016/12/welcome-to-gitea/) from
-[Gogs](https://gogs.io) since 2016.11 but changed a lot.
+[Gogs](https://gogs.io) since November of 2016, but a lot has changed.
## Building
@@ -100,7 +100,7 @@ NOTES:
## Translating
-Translations are done through Crowdin. If you want to translate to a new language ask one of the managers in the Crowdin project to add a new language there.
+Translations are done through Crowdin. If you want to translate to a new language ask one of the managers in the Crowdin project to add a new language there.
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.
@@ -113,15 +113,17 @@ https://docs.gitea.io/en-us/translation-guidelines/
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/).
-We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea).
-The hugo-based documentation theme is hosted at [gitea/theme](https://gitea.com/gitea/theme).
+We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea).
+
+The Hugo-based documentation theme is hosted at [gitea/theme](https://gitea.com/gitea/theme).
+
The official Gitea CLI is developed at [gitea/tea](https://gitea.com/gitea/tea).
## Authors
-* [Maintainers](https://github.com/orgs/go-gitea/people)
-* [Contributors](https://github.com/go-gitea/gitea/graphs/contributors)
-* [Translators](options/locale/TRANSLATORS)
+- [Maintainers](https://github.com/orgs/go-gitea/people)
+- [Contributors](https://github.com/go-gitea/gitea/graphs/contributors)
+- [Translators](options/locale/TRANSLATORS)
## Backers
@@ -161,6 +163,7 @@ See the [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) file
for the full license text.
## Screenshots
+
Looking for an overview of the interface? Check it out!
|![Dashboard](https://dl.gitea.io/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.io/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.io/screenshots/global_issues.png)|
diff --git a/README_ZH.md b/README_ZH.md
index 904b3a4fb6373..2be35742672fd 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -45,7 +45,7 @@
## 目标
diff --git a/SECURITY.md b/SECURITY.md
index 9795e3168ed52..ef98a2a8ac688 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -1,6 +1,7 @@
# Reporting security issues
-The Gitea maintainers take security seriously.
+The Gitea maintainers take security seriously.
+
If you discover a security issue, please bring it to their attention right away!
## Reporting a Vulnerability
@@ -11,12 +12,16 @@ Please **DO NOT** file a public issue, instead send your report privately to `se
Due to the sensitive nature of security information, you can use below GPG public key encrypt your mail body.
-The PGP key is valid until June 24, 2024.
-Key ID: 6FCD2D5B
-Key Type: RSA
-Expires: 6/24/2024
-Key Size: 4096/4096
-Fingerprint: 3DE0 3D1E 144A 7F06 9359 99DC AAFD 2381 6FCD 2D5B
+The PGP key is valid until June 24, 2024.
+
+```
+Key ID: 6FCD2D5B
+Key Type: RSA
+Expires: 6/24/2024
+Key Size: 4096/4096
+Fingerprint: 3DE0 3D1E 144A 7F06 9359 99DC AAFD 2381 6FCD 2D5B
+```
+
UserID: Gitea Security
```
diff --git a/cmd/admin.go b/cmd/admin.go
index 32f9a95a66581..6c2a8626c41a4 100644
--- a/cmd/admin.go
+++ b/cmd/admin.go
@@ -157,6 +157,10 @@ var (
Name: "email,e",
Usage: "Email of the user to delete",
},
+ cli.BoolFlag{
+ Name: "purge",
+ Usage: "Purge user, all their repositories, organizations and comments",
+ },
},
Action: runDeleteUser,
}
@@ -410,9 +414,9 @@ var (
Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN",
},
cli.StringFlag{
- Name: "host",
+ Name: "addr",
Value: "",
- Usage: "SMTP Host",
+ Usage: "SMTP Addr",
},
cli.IntFlag{
Name: "port",
@@ -628,9 +632,10 @@ func runListUsers(c *cli.Context) error {
}
}
} else {
- fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\n")
+ twofa := user_model.UserList(users).GetTwoFaStatus()
+ fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n")
for _, u := range users {
- fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin)
+ fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\t%t\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin, twofa[u.ID])
}
}
@@ -675,7 +680,7 @@ func runDeleteUser(c *cli.Context) error {
return fmt.Errorf("The user %s does not match the provided id %d", user.Name, c.Int64("id"))
}
- return user_service.DeleteUser(user)
+ return user_service.DeleteUser(ctx, user, c.Bool("purge"))
}
func runGenerateAccessToken(c *cli.Context) error {
@@ -951,8 +956,8 @@ func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
}
conf.Auth = c.String("auth-type")
}
- if c.IsSet("host") {
- conf.Host = c.String("host")
+ if c.IsSet("addr") {
+ conf.Addr = c.String("addr")
}
if c.IsSet("port") {
conf.Port = c.Int("port")
diff --git a/cmd/dump.go b/cmd/dump.go
index d807cb0587c13..73c2251b92bdf 100644
--- a/cmd/dump.go
+++ b/cmd/dump.go
@@ -92,7 +92,7 @@ func (o outputType) String() string {
}
var outputTypeEnum = &outputType{
- Enum: []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4"},
+ Enum: []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4", "tar.zst"},
Default: "zip",
}
diff --git a/cmd/dump_repo.go b/cmd/dump_repo.go
index c9d24c6c8367a..72456c61d3398 100644
--- a/cmd/dump_repo.go
+++ b/cmd/dump_repo.go
@@ -7,6 +7,8 @@ package cmd
import (
"context"
"errors"
+ "fmt"
+ "os"
"strings"
"code.gitea.io/gitea/modules/convert"
@@ -15,6 +17,7 @@ import (
base "code.gitea.io/gitea/modules/migration"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/migrations"
"github.com/urfave/cli"
@@ -159,9 +162,23 @@ func runDumpRepository(ctx *cli.Context) error {
}
}
+ // the repo_dir will be removed if error occurs in DumpRepository
+ // make sure the directory doesn't exist or is empty, prevent from deleting user files
+ repoDir := ctx.String("repo_dir")
+ if exists, err := util.IsExist(repoDir); err != nil {
+ return fmt.Errorf("unable to stat repo_dir %q: %v", repoDir, err)
+ } else if exists {
+ if isDir, _ := util.IsDir(repoDir); !isDir {
+ return fmt.Errorf("repo_dir %q already exists but it's not a directory", repoDir)
+ }
+ if dir, _ := os.ReadDir(repoDir); len(dir) > 0 {
+ return fmt.Errorf("repo_dir %q is not empty", repoDir)
+ }
+ }
+
if err := migrations.DumpRepository(
context.Background(),
- ctx.String("repo_dir"),
+ repoDir,
ctx.String("owner_name"),
opts,
); err != nil {
diff --git a/cmd/web.go b/cmd/web.go
index 43bb0ada911e7..3bc61b04433f4 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -148,8 +148,9 @@ func runWeb(ctx *cli.Context) error {
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("%v", http.ListenAndServe("localhost:6060", nil))
+ log.Info("Stopped pprof server: %v", http.ListenAndServe("localhost:6060", nil))
finished()
}()
}
diff --git a/contrib/systemd/gitea.service b/contrib/systemd/gitea.service
index d6a4377ec8091..79c34564bc977 100644
--- a/contrib/systemd/gitea.service
+++ b/contrib/systemd/gitea.service
@@ -78,6 +78,13 @@ Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
#AmbientCapabilities=CAP_NET_BIND_SERVICE
###
+# In some cases, when using CapabilityBoundingSet and AmbientCapabilities option, you may want to
+# set the following value to false to allow capabilities to be applied on gitea process. The following
+# value if set to true sandboxes gitea service and prevent any processes from running with privileges
+# in the host user namespace.
+###
+#PrivateUsers=false
+###
[Install]
WantedBy=multi-user.target
diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini
index 08708948940fa..83b3048bc6b5c 100644
--- a/custom/conf/app.example.ini
+++ b/custom/conf/app.example.ini
@@ -313,6 +313,7 @@ USER = root
;DB_TYPE = sqlite3
;PATH= ; defaults to data/gitea.db
;SQLITE_TIMEOUT = ; Query timeout defaults to: 500
+;SQLITE_JOURNAL_MODE = ; defaults to sqlite database default (often DELETE), can be used to enable WAL mode. https://www.sqlite.org/pragma.html#pragma_journal_mode
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@@ -631,6 +632,7 @@ ROUTER = console
;GC_ARGS =
;;
;; If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1
+;; To enable this for Git over SSH when using a OpenSSH server, add `AcceptEnv GIT_PROTOCOL` to your sshd_config file.
;ENABLE_AUTO_GIT_WIRE_PROTOCOL = true
;;
;; Respond to pushes to a non-default branch with a URL for creating a Pull Request (if the repository has them enabled)
@@ -878,6 +880,9 @@ ROUTER = console
;; Allow deletion of unadopted repositories
;ALLOW_DELETION_OF_UNADOPTED_REPOSITORIES = false
+;; Don't allow download source archive files from UI
+;DISABLE_DOWNLOAD_SOURCE_ARCHIVES = false
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository.editor]
@@ -1078,7 +1083,7 @@ ROUTER = console
;EXPLORE_PAGING_NUM = 20
;;
;; Number of issues that are displayed on one page
-;ISSUE_PAGING_NUM = 10
+;ISSUE_PAGING_NUM = 20
;;
;; Number of maximum commits displayed in one activity feed
;FEED_MAX_COMMIT_NUM = 5
@@ -1499,30 +1504,42 @@ ROUTER = console
;; Prefix displayed before subject in mail
;SUBJECT_PREFIX =
;;
-;; Mail server
-;; Gmail: smtp.gmail.com:587
-;; QQ: smtp.qq.com:465
-;; As per RFC 8314 using Implicit TLS/SMTPS on port 465 (if supported) is recommended,
-;; otherwise STARTTLS on port 587 should be used.
-;HOST =
-;;
-;; Disable HELO operation when hostnames are different.
-;DISABLE_HELO =
-;;
-;; Custom hostname for HELO operation, if no value is provided, one is retrieved from system.
+;; Mail server protocol. One of "smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy".
+;; - sendmail: use the operating system's `sendmail` command instead of SMTP. This is common on Linux systems.
+;; - dummy: send email messages to the log as a testing phase.
+;; If your provider does not explicitly say which protocol it uses but does provide a port,
+;; you can set SMTP_PORT instead and this will be inferred.
+;; (Before 1.18, this was controlled via MAILER_TYPE and IS_TLS_ENABLED.)
+;PROTOCOL =
+;;
+;; Mail server address, e.g. smtp.gmail.com.
+;; For smtp+unix, this should be a path to a unix socket instead.
+;; (Before 1.18, this was combined with SMTP_PORT as HOST.)
+;SMTP_ADDR =
+;;
+;; Mail server port. Common ports are:
+;; 25: insecure SMTP
+;; 465: SMTP Secure
+;; 587: StartTLS
+;; If no protocol is specified, it will be inferred by this setting.
+;; (Before 1.18, this was combined with SMTP_ADDR as HOST.)
+;SMTP_PORT =
+;;
+;; Enable HELO operation. Defaults to true.
+;ENABLE_HELO = true
+;;
+;; Custom hostname for HELO operation.
+;; If no value is provided, one is retrieved from system.
;HELO_HOSTNAME =
;;
-;; Whether or not to skip verification of certificates; `true` to disable verification. This option is unsafe. Consider adding the certificate to the system trust store instead.
-;SKIP_VERIFY = false
-;;
-;; Use client certificate
-;USE_CERTIFICATE = false
-;CERT_FILE = custom/mailer/cert.pem
-;KEY_FILE = custom/mailer/key.pem
+;; If set to `true`, completely ignores server certificate validation errors.
+;; This option is unsafe. Consider adding the certificate to the system trust store instead.
+;FORCE_TRUST_SERVER_CERT = false
;;
-;; Should SMTP connect with TLS, (if port ends with 465 TLS will always be used.)
-;; If this is false but STARTTLS is supported the connection will be upgraded to TLS opportunistically.
-;IS_TLS_ENABLED = false
+;; Use client certificate in connection.
+;USE_CLIENT_CERT = false
+;CLIENT_CERT_FILE = custom/mailer/cert.pem
+;CLIENT_KEY_FILE = custom/mailer/key.pem
;;
;; Mail from address, RFC 5322. This can be just an email address, or the `"Name" ` format
;FROM =
@@ -1530,19 +1547,15 @@ ROUTER = console
;; Sometimes it is helpful to use a different address on the envelope. Set this to use ENVELOPE_FROM as the from on the envelope. Set to `<>` to send an empty address.
;ENVELOPE_FROM =
;;
-;; Mailer user name and password
-;; Please Note: Authentication is only supported when the SMTP server communication is encrypted with TLS (this can be via STARTTLS) or `HOST=localhost`.
+;; Mailer user name and password, if required by provider.
;USER =
;;
;; Use PASSWD = `your password` for quoting if you use special characters in the password.
;PASSWD =
;;
-;; Send mails as plain text
+;; Send mails only in plain text, without HTML alternative
;SEND_AS_PLAIN_TEXT = false
;;
-;; Set Mailer Type (either SMTP, sendmail or dummy to just send to the log)
-;MAILER_TYPE = smtp
-;;
;; Specify an alternative sendmail binary
;SENDMAIL_PATH = sendmail
;;
diff --git a/docs/config.yaml b/docs/config.yaml
index 2d15e774eb7ff..88406da5df9da 100644
--- a/docs/config.yaml
+++ b/docs/config.yaml
@@ -20,7 +20,7 @@ params:
website: https://docs.gitea.io
version: 1.16.9
minGoVersion: 1.18
- goVersion: 1.18
+ goVersion: 1.19
minNodeVersion: 14
outputs:
diff --git a/docs/content/doc/advanced/clone-filter.en-us.md b/docs/content/doc/advanced/clone-filter.en-us.md
index ba2fdf104cc89..58675d2e941df 100644
--- a/docs/content/doc/advanced/clone-filter.en-us.md
+++ b/docs/content/doc/advanced/clone-filter.en-us.md
@@ -30,7 +30,6 @@ see Git version of the server.
By default, clone filters are enabled, unless `DISABLE_PARTIAL_CLONE` under
`[git]` is set to `true`.
-
See [GitHub blog post: Get up to speed with partial clone](https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/)
for common use cases of clone filters (blobless and treeless clones), and
[GitLab docs for partial clone](https://docs.gitlab.com/ee/topics/git/partial_clone.html)
diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
index a0e6fb8f13b1b..6b050e12b81ff 100644
--- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md
+++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
@@ -78,6 +78,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `DEFAULT_BRANCH`: **main**: Default branch name of all repositories.
- `ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES`: **false**: Allow non-admin users to adopt unadopted repositories
- `ALLOW_DELETION_OF_UNADOPTED_REPOSITORIES`: **false**: Allow non-admin users to delete unadopted repositories
+- `DISABLE_DOWNLOAD_SOURCE_ARCHIVES`: **false**: Don't allow download source archive files from UI
### Repository - Editor (`repository.editor`)
@@ -130,9 +131,9 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `always`: Always sign
- Options other than `never` and `always` can be combined as a comma separated list.
- `DEFAULT_TRUST_MODEL`: **collaborator**: \[collaborator, committer, collaboratorcommitter\]: The default trust model used for verifying commits.
- - `collaborator`: Trust signatures signed by keys of collaborators.
- - `committer`: Trust signatures that match committers (This matches GitHub and will force Gitea signed commits to have Gitea as the committer).
- - `collaboratorcommitter`: Trust signatures signed by keys of collaborators which match the committer.
+ - `collaborator`: Trust signatures signed by keys of collaborators.
+ - `committer`: Trust signatures that match committers (This matches GitHub and will force Gitea signed commits to have Gitea as the committer).
+ - `collaboratorcommitter`: Trust signatures signed by keys of collaborators which match the committer.
- `WIKI`: **never**: \[never, pubkey, twofa, always, parentsigned\]: Sign commits to wiki.
- `CRUD_ACTIONS`: **pubkey, twofa, parentsigned**: \[never, pubkey, twofa, parentsigned, always\]: Sign CRUD actions.
- Options as above, with the addition of:
@@ -152,6 +153,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
Configuration for set the expected MIME type based on file extensions of downloadable files. Configuration presents in key-value pairs and file extensions starts with leading `.`.
The following configuration set `Content-Type: application/vnd.android.package-archive` header when downloading files with `.apk` file extension.
+
```ini
.apk=application/vnd.android.package-archive
```
@@ -170,7 +172,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
## UI (`ui`)
- `EXPLORE_PAGING_NUM`: **20**: Number of repositories that are shown in one explore page.
-- `ISSUE_PAGING_NUM`: **10**: Number of issues that are shown in one page (for all pages that list issues).
+- `ISSUE_PAGING_NUM`: **20**: Number of issues that are shown in one page (for all pages that list issues, milestones, projects).
- `MEMBERS_PAGING_NUM`: **20**: Number of members that are shown in organization members.
- `FEED_MAX_COMMIT_NUM`: **5**: Number of maximum commits shown in one activity feed.
- `FEED_PAGING_NUM`: **20**: Number of items that are displayed in home feed.
@@ -248,11 +250,11 @@ The following configuration set `Content-Type: application/vnd.android.package-a
Requests are then made as `%(ROOT_URL)s/static/css/index.css` and `https://cdn.example.com/css/index.css` respective.
The static files are located in the `public/` directory of the Gitea source repository.
- `HTTP_ADDR`: **0.0.0.0**: HTTP listen address.
- - If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket
+ - If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket
defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings.
- - If `PROTOCOL` is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use. Relative paths will be made absolute against the AppWorkPath.
+ - If `PROTOCOL` is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use. Relative paths will be made absolute against the AppWorkPath.
- `HTTP_PORT`: **3000**: HTTP listen port.
- - If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket
+ - If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket
defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings.
- `UNIX_SOCKET_PERMISSION`: **666**: Permissions for the Unix socket.
- `LOCAL_ROOT_URL`: **%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/**: Local
@@ -300,7 +302,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data.
- `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. Note that this cache is disabled when `RUN_MODE` is "dev".
- `ENABLE_GZIP`: **false**: Enable gzip compression for runtime-generated content, static resources excluded.
-- `ENABLE_PPROF`: **false**: Application profiling (memory and cpu). For "web" command it listens on localhost:6060. For "serv" command it dumps to disk at `PPROF_DATA_PATH` as `(cpuprofile|memprofile)__`
+- `ENABLE_PPROF`: **false**: Application profiling (memory and cpu). For "web" command it listens on `localhost:6060`. For "serv" command it dumps to disk at `PPROF_DATA_PATH` as `(cpuprofile|memprofile)__`
- `PPROF_DATA_PATH`: **data/tmp/pprof**: `PPROF_DATA_PATH`, use an absolute path when you start Gitea as service
- `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login, **custom**\]. Where custom would instead be any URL such as "/org/repo" or even `https://anotherwebsite.com`
- `LFS_START_SERVER`: **false**: Enables Git LFS support.
@@ -370,17 +372,18 @@ The following configuration set `Content-Type: application/vnd.android.package-a
(e.g. `ALTER USER user SET SEARCH_PATH = schema_name,"$user",public;`).
- `SSL_MODE`: **disable**: SSL/TLS encryption mode for connecting to the database. This option is only applied for PostgreSQL and MySQL.
- Valid values for MySQL:
- - `true`: Enable TLS with verification of the database server certificate against its root certificate. When selecting this option make sure that the root certificate required to validate the database server certificate (e.g. the CA certificate) is on the system certificate store of both the database and Gitea servers. See your system documentation for instructions on how to add a CA certificate to the certificate store.
- - `false`: Disable TLS.
- - `disable`: Alias for `false`, for compatibility with PostgreSQL.
- - `skip-verify`: Enable TLS without database server certificate verification. Use this option if you have self-signed or invalid certificate on the database server.
- - `prefer`: Enable TLS with fallback to non-TLS connection.
+ - `true`: Enable TLS with verification of the database server certificate against its root certificate. When selecting this option make sure that the root certificate required to validate the database server certificate (e.g. the CA certificate) is on the system certificate store of both the database and Gitea servers. See your system documentation for instructions on how to add a CA certificate to the certificate store.
+ - `false`: Disable TLS.
+ - `disable`: Alias for `false`, for compatibility with PostgreSQL.
+ - `skip-verify`: Enable TLS without database server certificate verification. Use this option if you have self-signed or invalid certificate on the database server.
+ - `prefer`: Enable TLS with fallback to non-TLS connection.
- Valid values for PostgreSQL:
- - `disable`: Disable TLS.
- - `require`: Enable TLS without any verifications.
- - `verify-ca`: Enable TLS with verification of the database server certificate against its root certificate.
- - `verify-full`: Enable TLS and verify the database server name matches the given certificate in either the `Common Name` or `Subject Alternative Name` fields.
+ - `disable`: Disable TLS.
+ - `require`: Enable TLS without any verifications.
+ - `verify-ca`: Enable TLS with verification of the database server certificate against its root certificate.
+ - `verify-full`: Enable TLS and verify the database server name matches the given certificate in either the `Common Name` or `Subject Alternative Name` fields.
- `SQLITE_TIMEOUT`: **500**: Query timeout for SQLite3 only.
+- `SQLITE_JOURNAL_MODE`: **""**: Change journal mode for SQlite3. Can be used to enable [WAL mode](https://www.sqlite.org/wal.html) when high load causes write congestion. See [SQlite3 docs](https://www.sqlite.org/pragma.html#pragma_journal_mode) for possible values. Defaults to the default for the database file, often DELETE.
- `ITERATE_BUFFER_SIZE`: **50**: Internal buffer size for iterating.
- `CHARSET`: **utf8mb4**: For MySQL only, either "utf8" or "utf8mb4". NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this.
- `PATH`: **data/gitea.db**: For SQLite3 only, the database file path.
@@ -509,11 +512,11 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o
- `CSRF_COOKIE_HTTP_ONLY`: **true**: Set false to allow JavaScript to read CSRF cookie.
- `MIN_PASSWORD_LENGTH`: **6**: Minimum password length for new users.
- `PASSWORD_COMPLEXITY`: **off**: Comma separated list of character classes required to pass minimum complexity. If left empty or no valid values are specified, checking is disabled (off):
- - lower - use one or more lower latin characters
- - upper - use one or more upper latin characters
- - digit - use one or more digits
- - spec - use one or more special characters as ``!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~``
- - off - do not check password complexity
+ - lower - use one or more lower latin characters
+ - upper - use one or more upper latin characters
+ - digit - use one or more digits
+ - spec - use one or more special characters as ``!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~``
+ - off - do not check password complexity
- `PASSWORD_CHECK_PWN`: **false**: Check [HaveIBeenPwned](https://haveibeenpwned.com/Passwords) to see if a password has been exposed.
- `SUCCESSFUL_TOKENS_CACHE_SIZE`: **20**: Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations. This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
@@ -535,18 +538,18 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o
## OAuth2 Client (`oauth2_client`)
-- `REGISTER_EMAIL_CONFIRM`: *[service]* **REGISTER\_EMAIL\_CONFIRM**: Set this to enable or disable email confirmation of OAuth2 auto-registration. (Overwrites the REGISTER\_EMAIL\_CONFIRM setting of the `[service]` section)
+- `REGISTER_EMAIL_CONFIRM`: _[service]_ **REGISTER\_EMAIL\_CONFIRM**: Set this to enable or disable email confirmation of OAuth2 auto-registration. (Overwrites the REGISTER\_EMAIL\_CONFIRM setting of the `[service]` section)
- `OPENID_CONNECT_SCOPES`: **\**: List of additional openid connect scopes. (`openid` is implicitly added)
- `ENABLE_AUTO_REGISTRATION`: **false**: Automatically create user accounts for new oauth2 users.
- `USERNAME`: **nickname**: The source of the username for new oauth2 accounts:
- - userid - use the userid / sub attribute
- - nickname - use the nickname attribute
- - email - use the username part of the email attribute
+ - userid - use the userid / sub attribute
+ - nickname - use the nickname attribute
+ - email - use the username part of the email attribute
- `UPDATE_AVATAR`: **false**: Update avatar if available from oauth2 provider. Update will be performed on each login.
- `ACCOUNT_LINKING`: **login**: How to handle if an account / email already exists:
- - disabled - show an error
- - login - show an account linking login
- - auto - automatically link with the account (Please be aware that this will grant access to an existing account just because the same username or email is provided. You must make sure that this does not cause issues with your authentication providers.)
+ - disabled - show an error
+ - login - show an account linking login
+ - auto - automatically link with the account (Please be aware that this will grant access to an existing account just because the same username or email is provided. You must make sure that this does not cause issues with your authentication providers.)
## Service (`service`)
@@ -644,41 +647,35 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
## Mailer (`mailer`)
- `ENABLED`: **false**: Enable to use a mail service.
-- `DISABLE_HELO`: **\**: Disable HELO operation.
-- `HELO_HOSTNAME`: **\**: Custom hostname for HELO operation.
-- `HOST`: **\**: SMTP mail host address and port (example: smtp.gitea.io:587).
- - As per RFC 8314, if supported, Implicit TLS/SMTPS on port 465 is recommended, otherwise opportunistic TLS via STARTTLS on port 587 should be used.
-- `IS_TLS_ENABLED` : **false** : Forcibly use TLS to connect even if not on a default SMTPS port.
- - Note, if the port ends with `465` Implicit TLS/SMTPS/SMTP over TLS will be used despite this setting.
- - Otherwise if `IS_TLS_ENABLED=false` and the server supports `STARTTLS` this will be used. Thus if `STARTTLS` is preferred you should set `IS_TLS_ENABLED=false`.
-- `FROM`: **\**: Mail from address, RFC 5322. This can be just an email address, or
- the "Name" \ format.
-- `ENVELOPE_FROM`: **\**: Address set as the From address on the SMTP mail envelope. Set to `<>` to send an empty address.
+- `PROTOCOL`: **\**: Mail server protocol. One of "smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy". _Before 1.18, this was inferred from a combination of `MAILER_TYPE` and `IS_TLS_ENABLED`._
+ - SMTP family, if your provider does not explicitly say which protocol it uses but does provide a port, you can set SMTP_PORT instead and this will be inferred.
+ - **sendmail** Use the operating system's `sendmail` command instead of SMTP. This is common on Linux systems.
+ - **dummy** Send email messages to the log as a testing phase.
+ - Note that enabling sendmail will ignore all other `mailer` settings except `ENABLED`, `FROM`, `SUBJECT_PREFIX` and `SENDMAIL_PATH`.
+ - Enabling dummy will ignore all settings except `ENABLED`, `SUBJECT_PREFIX` and `FROM`.
+- `SMTP_ADDR`: **\**: Mail server address. e.g. smtp.gmail.com. For smtp+unix, this should be a path to a unix socket instead. _Before 1.18, this was combined with `SMTP_PORT` under the name `HOST`._
+- `SMTP_PORT`: **\**: Mail server port. If no protocol is specified, it will be inferred by this setting. Common ports are listed below. _Before 1.18, this was combined with `SMTP_ADDR` under the name `HOST`._
+ - 25: insecure SMTP
+ - 465: SMTP Secure
+ - 587: StartTLS
+- `USE_CLIENT_CERT`: **false**: Use client certificate for TLS/SSL.
+- `CLIENT_CERT_FILE`: **custom/mailer/cert.pem**: Client certificate file.
+- `CLIENT_KEY_FILE`: **custom/mailer/key.pem**: Client key file.
+- `FORCE_TRUST_SERVER_CERT`: **false**: If set to `true`, completely ignores server certificate validation errors. This option is unsafe. Consider adding the certificate to the system trust store instead.
- `USER`: **\**: Username of mailing user (usually the sender's e-mail address).
- `PASSWD`: **\**: Password of mailing user. Use \`your password\` for quoting if you use special characters in the password.
- - Please note: authentication is only supported when the SMTP server communication is encrypted with TLS (this can be via `STARTTLS`) or `HOST=localhost`. See [Email Setup]({{< relref "doc/usage/email-setup.en-us.md" >}}) for more information.
-- `SEND_AS_PLAIN_TEXT`: **false**: Send mails as plain text.
-- `SKIP_VERIFY`: **false**: Whether or not to skip verification of certificates; `true` to disable verification.
- - **Warning:** This option is unsafe. Consider adding the certificate to the system trust store instead.
- - **Note:** Gitea only supports SMTP with STARTTLS.
-- `USE_CERTIFICATE`: **false**: Use client certificate.
-- `CERT_FILE`: **custom/mailer/cert.pem**
-- `KEY_FILE`: **custom/mailer/key.pem**
+ - Please note: authentication is only supported when the SMTP server communication is encrypted with TLS (this can be via `STARTTLS`) or SMTP host is localhost. See [Email Setup]({{< relref "doc/usage/email-setup.en-us.md" >}}) for more information.
+- `ENABLE_HELO`: **true**: Enable HELO operation.
+- `HELO_HOSTNAME`: **(retrieved from system)**: HELO hostname.
+- `FROM`: **\**: Mail from address, RFC 5322. This can be just an email address, or the "Name" \ format.
+- `ENVELOPE_FROM`: **\**: Address set as the From address on the SMTP mail envelope. Set to `<>` to send an empty address.
- `SUBJECT_PREFIX`: **\**: Prefix to be placed before e-mail subject lines.
-- `MAILER_TYPE`: **smtp**: \[smtp, sendmail, dummy\]
- - **smtp** Use SMTP to send mail
- - **sendmail** Use the operating system's `sendmail` command instead of SMTP.
- This is common on Linux systems.
- - **dummy** Send email messages to the log as a testing phase.
- - Note that enabling sendmail will ignore all other `mailer` settings except `ENABLED`,
- `FROM`, `SUBJECT_PREFIX` and `SENDMAIL_PATH`.
- - Enabling dummy will ignore all settings except `ENABLED`, `SUBJECT_PREFIX` and `FROM`.
-- `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be
- command or full path).
-- `SENDMAIL_ARGS`: **_empty_**: Specify any extra sendmail arguments. (NOTE: you should be aware that email addresses can look like options - if your `sendmail` command takes options you must set the option terminator `--`)
+- `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be command or full path).
+- `SENDMAIL_ARGS`: **\**: Specify any extra sendmail arguments. (NOTE: you should be aware that email addresses can look like options - if your `sendmail` command takes options you must set the option terminator `--`)
- `SENDMAIL_TIMEOUT`: **5m**: default timeout for sending email through sendmail
- `SENDMAIL_CONVERT_CRLF`: **true**: Most versions of sendmail prefer LF line endings rather than CRLF line endings. Set this to false if your version of sendmail requires CRLF line endings.
- `SEND_BUFFER_LEN`: **100**: Buffer length of mailing queue. **DEPRECATED** use `LENGTH` in `[queue.mailer]`
+- `SEND_AS_PLAIN_TEXT`: **false**: Send mails only in plain text, without HTML alternative.
## Cache (`cache`)
@@ -686,9 +683,9 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, `twoqueue` or `memcache`. (`twoqueue` represents a size limited LRU cache.)
- `INTERVAL`: **60**: Garbage Collection interval (sec), for memory and twoqueue cache only.
- `HOST`: **\**: Connection string for `redis` and `memcache`. For `twoqueue` sets configuration for the queue.
- - Redis: `redis://:macaron@127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
- - Memcache: `127.0.0.1:9090;127.0.0.1:9091`
- - TwoQueue LRU cache: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000` representing the maximum number of objects stored in the cache.
+ - Redis: `redis://:macaron@127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
+ - Memcache: `127.0.0.1:9090;127.0.0.1:9091`
+ - TwoQueue LRU cache: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000` representing the maximum number of objects stored in the cache.
- `ITEM_TTL`: **16h**: Time to keep items in cache if not used, Setting it to -1 disables caching.
## Cache - LastCommitCache settings (`cache.last_commit`)
@@ -731,7 +728,6 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
- image = default image will be used (which is set in `REPOSITORY_AVATAR_FALLBACK_IMAGE`)
- `REPOSITORY_AVATAR_FALLBACK_IMAGE`: **/img/repo_default.png**: Image used as default repository avatar (if `REPOSITORY_AVATAR_FALLBACK` is set to image and none was uploaded)
-
## Project (`project`)
Default templates for project boards:
@@ -766,11 +762,13 @@ Default templates for project boards:
- `ENABLE_XORM_LOG`: **true**: Set whether to perform XORM logging. Please note SQL statement logging can be disabled by setting `LOG_SQL` to false in the `[database]` section.
### Router Log (`log`)
+
- `DISABLE_ROUTER_LOG`: **false**: Mute printing of the router log.
- `ROUTER`: **console**: The mode or name of the log the router should log to. (If you set this to `,` it will log to default Gitea logger.)
NB: You must have `DISABLE_ROUTER_LOG` set to `false` for this option to take effect. Configure each mode in per mode log subsections `\[log.modename.router\]`.
### Access Log (`log`)
+
- `ENABLE_ACCESS_LOG`: **false**: Creates an access.log in NCSA common log format, or as per the following template
- `ACCESS`: **file**: Logging mode for the access logger, use a comma to separate values. Configure each mode in per mode log subsections `\[log.modename.access\]`. By default the file mode will log to `$ROOT_PATH/access.log`. (If you set this to `,` it will log to the default Gitea logger.)
- `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}}"`**: Sets the template used to create the access log.
@@ -828,9 +826,9 @@ Default templates for project boards:
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
- `SCHEDULE` accept formats
- - Full crontab specs, e.g. `* * * * * ?`
- - Descriptors, e.g. `@midnight`, `@every 1h30m` ...
- - See more: [cron decument](https://pkg.go.dev/github.com/gogs/cron@v0.0.0-20171120032916-9f6c956d3e14)
+ - Full crontab specs, e.g. `* * * * * ?`
+ - Descriptors, e.g. `@midnight`, `@every 1h30m` ...
+ - See more: [cron decument](https://pkg.go.dev/github.com/gogs/cron@v0.0.0-20171120032916-9f6c956d3e14)
### Basic cron tasks - enabled by default
@@ -887,6 +885,7 @@ Default templates for project boards:
### Extended cron tasks (not enabled by default)
#### Cron - Garbage collect all repositories ('cron.git_gc_repos')
+
- `ENABLED`: **false**: Enable service.
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
@@ -895,36 +894,42 @@ Default templates for project boards:
- `ARGS`: **\**: Arguments for command `git gc`, e.g. `--aggressive --auto`. The default value is same with [git] -> GC_ARGS
#### Cron - Update the '.ssh/authorized_keys' file with Gitea SSH keys ('cron.resync_all_sshkeys')
+
- `ENABLED`: **false**: Enable service.
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
#### Cron - Resynchronize pre-receive, update and post-receive hooks of all repositories ('cron.resync_all_hooks')
+
- `ENABLED`: **false**: Enable service.
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
#### Cron - Reinitialize all missing Git repositories for which records exist ('cron.reinit_missing_repos')
+
- `ENABLED`: **false**: Enable service.
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
#### Cron - Delete all repositories missing their Git files ('cron.delete_missing_repos')
+
- `ENABLED`: **false**: Enable service.
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
#### Cron - Delete generated repository avatars ('cron.delete_generated_repository_avatars')
+
- `ENABLED`: **false**: Enable service.
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`.
#### Cron - Delete all old actions from database ('cron.delete_old_actions')
+
- `ENABLED`: **false**: Enable service.
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
- `NOTICE_ON_SUCCESS`: **false**: Set to true to switch on success notices.
@@ -932,6 +937,7 @@ Default templates for project boards:
- `OLDER_THAN`: **@every 8760h**: any action older than this expression will be deleted from database, suggest using `8760h` (1 year) because that's the max length of heatmap.
#### Cron - Check for new Gitea versions ('cron.update_checker')
+
- `ENABLED`: **false**: Enable service.
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
- `ENABLE_SUCCESS_NOTICE`: **true**: Set to false to switch off success notices.
@@ -939,6 +945,7 @@ Default templates for project boards:
- `HTTP_ENDPOINT`: **https://dl.gitea.io/gitea/version.json**: the endpoint that Gitea will check for newer versions
#### Cron - Delete all old system notices from database ('cron.delete_old_system_notices')
+
- `ENABLED`: **false**: Enable service.
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices.
@@ -949,7 +956,7 @@ Default templates for project boards:
- `PATH`: **""**: The path of Git executable. If empty, Gitea searches through the PATH environment.
- `HOME_PATH`: **%(APP_DATA_PATH)/home**: The HOME directory for Git.
- This directory will be used to contain the `.gitconfig` and possible `.gnupg` directories that Gitea's git calls will use. If you can confirm Gitea is the only application running in this environment, you can set it to the normal home directory for Gitea user.
+ This directory will be used to contain the `.gitconfig` and possible `.gnupg` directories that Gitea's git calls will use. If you can confirm Gitea is the only application running in this environment, you can set it to the normal home directory for Gitea user.
- `DISABLE_DIFF_HIGHLIGHT`: **false**: Disables highlight of added and removed changes.
- `MAX_GIT_DIFF_LINES`: **1000**: Max number of lines allowed of a single file in diff view.
- `MAX_GIT_DIFF_LINE_CHARACTERS`: **5000**: Max character count per line highlighted in diff view.
@@ -957,7 +964,8 @@ Default templates for project boards:
- `COMMITS_RANGE_SIZE`: **50**: Set the default commits range size
- `BRANCHES_RANGE_SIZE`: **20**: Set the default branches range size
- `GC_ARGS`: **\**: Arguments for command `git gc`, e.g. `--aggressive --auto`. See more on http://git-scm.com/docs/git-gc/
-- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use Git wire protocol version 2 when Git version >= 2.18, default is true, set to false when you always want Git wire protocol version 1
+- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use Git wire protocol version 2 when Git version >= 2.18, default is true, set to false when you always want Git wire protocol version 1.
+ To enable this for Git over SSH when using a OpenSSH server, add `AcceptEnv GIT_PROTOCOL` to your sshd_config file.
- `PULL_REQUEST_PUSH_MESSAGE`: **true**: Respond to pushes to a non-default branch with a URL for creating a Pull Request (if the repository has them enabled)
- `VERBOSE_PUSH`: **true**: Print status information about pushes as they are being processed.
- `VERBOSE_PUSH_DELAY`: **5s**: Only print verbose information if push takes longer than this delay.
@@ -966,6 +974,7 @@ Default templates for project boards:
- `DISABLE_PARTIAL_CLONE`: **false** Disable the usage of using partial clones for git.
## Git - Timeout settings (`git.timeout`)
+
- `DEFAUlT`: **360**: Git operations default timeout seconds.
- `MIGRATE`: **600**: Migrate external repositories timeout seconds.
- `MIRROR`: **300**: Mirror external repositories timeout seconds.
@@ -1032,6 +1041,7 @@ IS_INPUT_FILE = false
- iframe: Render the content in a separate standalone page and embed it into current page by iframe. The iframe is in sandbox mode with same-origin disabled, and the JS code are safely isolated from parent page.
Two special environment variables are passed to the render command:
+
- `GITEA_PREFIX_SRC`, which contains the current URL prefix in the `src` path tree. To be used as prefix for links.
- `GITEA_PREFIX_RAW`, which contains the current URL prefix in the `raw` path tree. To be used as prefix for image paths.
@@ -1047,10 +1057,10 @@ REGEXP = ^\s*((math(\s+|$)|inline(\s+|$)|display(\s+|$)))+
ALLOW_DATA_URI_IMAGES = true
```
- - `ELEMENT`: The element this policy applies to. Must be non-empty.
- - `ALLOW_ATTR`: The attribute this policy allows. Must be non-empty.
- - `REGEXP`: A regex to match the contents of the attribute against. Must be present but may be empty for unconditional whitelisting of this attribute.
- - `ALLOW_DATA_URI_IMAGES`: **false** Allow data uri images (``).
+- `ELEMENT`: The element this policy applies to. Must be non-empty.
+- `ALLOW_ATTR`: The attribute this policy allows. Must be non-empty.
+- `REGEXP`: A regex to match the contents of the attribute against. Must be present but may be empty for unconditional whitelisting of this attribute.
+- `ALLOW_DATA_URI_IMAGES`: **false** Allow data uri images (``).
Multiple sanitisation rules can be defined by adding unique subsections, e.g. `[markup.sanitizer.TeX-2]`.
To apply a sanitisation rules only for a specify external renderer they must use the renderer name, e.g. `[markup.sanitizer.asciidoc.rule-1]`.
@@ -1186,6 +1196,7 @@ is `data/repo-archive` and the default of `MINIO_BASE_PATH` is `repo-archive/`.
- `PROXY_HOSTS`: **\**: Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts.
i.e.
+
```ini
PROXY_ENABLED = true
PROXY_URL = socks://127.0.0.1:1080
diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
index 33c693083d02f..c2dff2aeca371 100644
--- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
+++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
@@ -173,8 +173,8 @@ menu:
- `ADAPTER`: **memory**: 缓存引擎,可以为 `memory`, `redis` 或 `memcache`。
- `INTERVAL`: **60**: 只对内存缓存有效,GC间隔,单位秒。
- `HOST`: **\**: 针对redis和memcache有效,主机地址和端口。
- - Redis: `network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180`
- - Memache: `127.0.0.1:9090;127.0.0.1:9091`
+ - Redis: `network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180`
+ - Memache: `127.0.0.1:9090;127.0.0.1:9091`
- `ITEM_TTL`: **16h**: 缓存项目失效时间,设置为 -1 则禁用缓存。
## Cache - LastCommitCache settings (`cache.last_commit`)
@@ -239,7 +239,6 @@ file -I test01.xls
test01.xls: application/vnd.ms-excel; charset=binary
```
-
## Log (`log`)
- `ROOT_PATH`: 日志文件根目录。
@@ -251,10 +250,9 @@ test01.xls: application/vnd.ms-excel; charset=binary
- `ENABLED`: 是否在后台运行定期任务。
- `RUN_AT_START`: 是否启动时自动运行。
- `SCHEDULE` 所接受的格式
- - 完整 crontab 控制, 例如 `* * * * * ?`
- - 描述符, 例如 `@midnight`, `@every 1h30m` ...
- - 更多细节参见 [cron api文档](https://pkg.go.dev/github.com/gogs/cron@v0.0.0-20171120032916-9f6c956d3e14)
-
+ - 完整 crontab 控制, 例如 `* * * * * ?`
+ - 描述符, 例如 `@midnight`, `@every 1h30m` ...
+ - 更多细节参见 [cron api文档](https://pkg.go.dev/github.com/gogs/cron@v0.0.0-20171120032916-9f6c956d3e14)
### Cron - Update Mirrors (`cron.update_mirrors`)
@@ -440,6 +438,7 @@ Repository archive 的存储配置。 如果 `STORAGE_TYPE` 为空,则此配
- `PROXY_HOSTS`: **\**: 逗号分隔的多个需要代理的网址,支持 * 号匹配符号, ** 表示匹配所有网站
i.e.
+
```ini
PROXY_ENABLED = true
PROXY_URL = socks://127.0.0.1:1080
diff --git a/docs/content/doc/advanced/customizing-gitea.en-us.md b/docs/content/doc/advanced/customizing-gitea.en-us.md
index 8f23fc33462c1..038ce16a8dde8 100644
--- a/docs/content/doc/advanced/customizing-gitea.en-us.md
+++ b/docs/content/doc/advanced/customizing-gitea.en-us.md
@@ -149,13 +149,13 @@ copy javascript files from https://gitea.com/davidsvantesson/plantuml-code-highl
You can then add blocks like the following to your markdown:
- ```plantuml
- Alice -> Bob: Authentication Request
- Bob --> Alice: Authentication Response
+```plantuml
+Alice -> Bob: Authentication Request
+Bob --> Alice: Authentication Response
- Alice -> Bob: Another authentication Request
- Alice <-- Bob: Another authentication Response
- ```
+Alice -> Bob: Another authentication Request
+Alice <-- Bob: Another authentication Response
+```
The script will detect tags with `class="language-plantuml"`, but you can change this by providing a second argument to `parsePlantumlCodeBlocks`.
diff --git a/docs/content/doc/advanced/environment-variables.zh-cn.md b/docs/content/doc/advanced/environment-variables.zh-cn.md
index 63ee4c69357f0..3de8dcfbc7418 100644
--- a/docs/content/doc/advanced/environment-variables.zh-cn.md
+++ b/docs/content/doc/advanced/environment-variables.zh-cn.md
@@ -25,31 +25,31 @@ GITEA_CUSTOM=/home/gitea/custom ./gitea web
因为 Gitea 使用 Go 语言编写,因此它使用了一些相关的 Go 的配置参数:
- * `GOOS`
- * `GOARCH`
- * [`GOPATH`](https://golang.org/cmd/go/#hdr-GOPATH_environment_variable)
+* `GOOS`
+* `GOARCH`
+* [`GOPATH`](https://golang.org/cmd/go/#hdr-GOPATH_environment_variable)
您可以在[官方文档](https://golang.org/cmd/go/#hdr-Environment_variables)中查阅这些配置参数的详细信息。
## Gitea 的文件目录
- * `GITEA_WORK_DIR`:工作目录的绝对路径
- * `GITEA_CUSTOM`:默认情况下 Gitea 使用默认目录 `GITEA_WORK_DIR`/custom,您可以使用这个参数来配置 *custom* 目录
- * `GOGS_WORK_DIR`: 已废弃,请使用 `GITEA_WORK_DIR` 替代
- * `GOGS_CUSTOM`: 已废弃,请使用 `GITEA_CUSTOM` 替代
+* `GITEA_WORK_DIR`:工作目录的绝对路径
+* `GITEA_CUSTOM`:默认情况下 Gitea 使用默认目录 `GITEA_WORK_DIR`/custom,您可以使用这个参数来配置 *custom* 目录
+* `GOGS_WORK_DIR`: 已废弃,请使用 `GITEA_WORK_DIR` 替代
+* `GOGS_CUSTOM`: 已废弃,请使用 `GITEA_CUSTOM` 替代
## 操作系统配置
- * `USER`:Gitea 运行时使用的系统用户,它将作为一些 repository 的访问地址的一部分
- * `USERNAME`: 如果没有配置 `USER`, Gitea 将使用 `USERNAME`
- * `HOME`: 用户的 home 目录,在 Windows 中会使用 `USERPROFILE` 环境变量
+* `USER`:Gitea 运行时使用的系统用户,它将作为一些 repository 的访问地址的一部分
+* `USERNAME`: 如果没有配置 `USER`, Gitea 将使用 `USERNAME`
+* `HOME`: 用户的 home 目录,在 Windows 中会使用 `USERPROFILE` 环境变量
### 仅限于 Windows 的配置
- * `USERPROFILE`: 用户的主目录,如果未配置则会使用 `HOMEDRIVE` + `HOMEPATH`
- * `HOMEDRIVE`: 用于访问 home 目录的主驱动器路径(C盘)
- * `HOMEPATH`:在指定主驱动器下的 home 目录相对路径
+* `USERPROFILE`: 用户的主目录,如果未配置则会使用 `HOMEDRIVE` + `HOMEPATH`
+* `HOMEDRIVE`: 用于访问 home 目录的主驱动器路径(C盘)
+* `HOMEPATH`:在指定主驱动器下的 home 目录相对路径
## Miscellaneous
- * `SKIP_MINWINSVC`:如果设置为 1,在 Windows 上不会以 service 的形式运行。
+* `SKIP_MINWINSVC`:如果设置为 1,在 Windows 上不会以 service 的形式运行。
diff --git a/docs/content/doc/advanced/external-renderers.en-us.md b/docs/content/doc/advanced/external-renderers.en-us.md
index 34329408a1d5b..4e5e72554d9d3 100644
--- a/docs/content/doc/advanced/external-renderers.en-us.md
+++ b/docs/content/doc/advanced/external-renderers.en-us.md
@@ -127,6 +127,7 @@ ALLOW_ATTR = class
### Example: Office DOCX
Display Office DOCX files with [`pandoc`](https://pandoc.org/):
+
```ini
[markup.docx]
ENABLED = true
@@ -138,6 +139,7 @@ ALLOW_DATA_URI_IMAGES = true
```
The template file has the following content:
+
```
$body$
```
@@ -145,6 +147,7 @@ $body$
### Example: Jupyter Notebook
Display Jupyter Notebook files with [`nbconvert`](https://github.com/jupyter/nbconvert):
+
```ini
[markup.jupyter]
ENABLED = true
@@ -156,9 +159,11 @@ ALLOW_DATA_URI_IMAGES = true
```
## Customizing CSS
-The external renderer is specified in the .ini in the format `[markup.XXXXX]` and the HTML supplied by your external renderer will be wrapped in a `
` with classes `markup` and `XXXXX`. The `markup` class provides out of the box styling (as does `markdown` if `XXXXX` is `markdown`). Otherwise you can use these classes to specifically target the contents of your rendered HTML.
+
+The external renderer is specified in the .ini in the format `[markup.XXXXX]` and the HTML supplied by your external renderer will be wrapped in a `
` with classes `markup` and `XXXXX`. The `markup` class provides out of the box styling (as does `markdown` if `XXXXX` is `markdown`). Otherwise you can use these classes to specifically target the contents of your rendered HTML.
And so you could write some CSS:
+
```css
.markup.XXXXX html {
font-size: 100%;
@@ -184,6 +189,7 @@ And so you could write some CSS:
```
Add your stylesheet to your custom directory e.g `custom/public/css/my-style-XXXXX.css` and import it using a custom header file `custom/templates/custom/header.tmpl`:
+
```html
```
diff --git a/docs/content/doc/advanced/mail-templates-us.md b/docs/content/doc/advanced/mail-templates-us.md
index e73bb01e299db..bd419a617b856 100644
--- a/docs/content/doc/advanced/mail-templates-us.md
+++ b/docs/content/doc/advanced/mail-templates-us.md
@@ -251,7 +251,7 @@ This template produces something along these lines:
>
> \_********************************\_********************************
>
-> Mike, I think we should tone down the blues a little.
+> Mike, I think we should tone down the blues a little.
> \_********************************\_********************************
>
> [View it on Gitea](#).
diff --git a/docs/content/doc/advanced/protected-tags.en-us.md b/docs/content/doc/advanced/protected-tags.en-us.md
index 0ddbedd9a14db..8ed2afc418320 100644
--- a/docs/content/doc/advanced/protected-tags.en-us.md
+++ b/docs/content/doc/advanced/protected-tags.en-us.md
@@ -15,7 +15,7 @@ menu:
# Protected tags
-Protected tags allow control over who has permission to create or update Git tags. Each rule allows you to match either an individual tag name, or use an appropriate pattern to control multiple tags at once.
+Protected tags allow control over who has permission to create or update Git tags. Each rule allows you to match either an individual tag name, or use an appropriate pattern to control multiple tags at once.
**Table of Contents**
diff --git a/docs/content/doc/advanced/repo-mirror.en-us.md b/docs/content/doc/advanced/repo-mirror.en-us.md
index bda5b0fa5594c..c1d794762a170 100644
--- a/docs/content/doc/advanced/repo-mirror.en-us.md
+++ b/docs/content/doc/advanced/repo-mirror.en-us.md
@@ -37,7 +37,7 @@ For an existing remote repository, you can set up pull mirroring as follows:
3. Enter a repository URL.
4. If the repository needs authentication fill in your authentication information.
5. Check the box **This repository will be a mirror**.
-5. Select **Migrate repository** to save the configuration.
+6. Select **Migrate repository** to save the configuration.
The repository now gets mirrored periodically from the remote repository. You can force a sync by selecting **Synchronize Now** in the repository settings.
diff --git a/docs/content/doc/advanced/search-engines-indexation.en-us.md b/docs/content/doc/advanced/search-engines-indexation.en-us.md
index 5d5e4dab5a2bf..ec367b74deac9 100644
--- a/docs/content/doc/advanced/search-engines-indexation.en-us.md
+++ b/docs/content/doc/advanced/search-engines-indexation.en-us.md
@@ -25,7 +25,6 @@ create a file called `robots.txt` in the [`custom` folder or `CustomPath`]({{< r
Examples on how to configure the `robots.txt` can be found at [https://moz.com/learn/seo/robotstxt](https://moz.com/learn/seo/robotstxt).
-
```txt
User-agent: *
Disallow: /
diff --git a/docs/content/doc/advanced/third-party-tools.zh-cn.md b/docs/content/doc/advanced/third-party-tools.zh-cn.md
index d25bc400e46c5..e961e9ec1fa19 100644
--- a/docs/content/doc/advanced/third-party-tools.zh-cn.md
+++ b/docs/content/doc/advanced/third-party-tools.zh-cn.md
@@ -14,23 +14,26 @@ menu:
---
# 第三方工具列表
+
**注意:** 这些工具并没有经过Gitea的检验,在这里列出它们只是为了便捷.
*此列表并不是完整的列表,可以随时咨询如何添加!*
### 持续集成
-[BuildKite 连接器](https://github.com/techknowlogick/gitea-buildkite-connector)
-[Jenkins 插件](https://github.com/jenkinsci/gitea-plugin)
-[Gitea搭配Drone](https://docs.drone.io/installation/gitea)
+[BuildKite 连接器](https://github.com/techknowlogick/gitea-buildkite-connector)
+[Jenkins 插件](https://github.com/jenkinsci/gitea-plugin)
+[Gitea搭配Drone](https://docs.drone.io/installation/gitea)
### 迁移
-[Gitea安装脚本](https://git.coolaj86.com/coolaj86/gitea-installer.sh)
-[GitHub迁移](https://gitea.com/gitea/migrator)
+[Gitea安装脚本](https://git.coolaj86.com/coolaj86/gitea-installer.sh)
+[GitHub迁移](https://gitea.com/gitea/migrator)
### 移动端
+
[安卓客户端GitNex](https://gitlab.com/mmarif4u/gitnex)
-### 编辑器扩展
- - [Gitea的Visual Studio扩展](https://github.com/maikebing/Gitea.VisualStudio) 从 [Visual Studio 扩展市场](https://marketplace.visualstudio.com/items?itemName=MysticBoy.GiteaExtensionforVisualStudio) 下载
+### 编辑器扩展
+
+- [Gitea的Visual Studio扩展](https://github.com/maikebing/Gitea.VisualStudio) 从 [Visual Studio 扩展市场](https://marketplace.visualstudio.com/items?itemName=MysticBoy.GiteaExtensionforVisualStudio) 下载
diff --git a/docs/content/doc/developers/api-usage.en-us.md b/docs/content/doc/developers/api-usage.en-us.md
index 57702a6ee8554..dd2822e9f1361 100644
--- a/docs/content/doc/developers/api-usage.en-us.md
+++ b/docs/content/doc/developers/api-usage.en-us.md
@@ -48,7 +48,6 @@ A new token can be generated with a `POST` request to
Note that `/users/:name/tokens` is a special endpoint and requires you
to authenticate using `BasicAuth` and a password, as follows:
-
```sh
$ curl -XPOST -H "Content-Type: application/json" -k -d '{"name":"test"}' -u username:password https://gitea.your.host/api/v1/users//tokens
{"id":1,"name":"test","sha1":"9fcb1158165773dd010fca5f0cf7174316c3e37d","token_last_eight":"16c3e37d"}
diff --git a/docs/content/doc/developers/guidelines-backend.md b/docs/content/doc/developers/guidelines-backend.md
index 1248d4143233f..4280aa80fbd0c 100644
--- a/docs/content/doc/developers/guidelines-backend.md
+++ b/docs/content/doc/developers/guidelines-backend.md
@@ -21,8 +21,8 @@ menu:
## Background
-Gitea uses Golang as the backend programming language. It uses many third-party packages and also write some itself.
-For example, Gitea uses [Chi](https://github.com/go-chi/chi) as basic web framework. [Xorm](https://xorm.io) is an ORM framework that is used to interact with the database.
+Gitea uses Golang as the backend programming language. It uses many third-party packages and also write some itself.
+For example, Gitea uses [Chi](https://github.com/go-chi/chi) as basic web framework. [Xorm](https://xorm.io) is an ORM framework that is used to interact with the database.
So it's very important to manage these packages. Please take the below guidelines before you start to write backend code.
## Package Design Guideline
@@ -43,9 +43,9 @@ To maintain understandable code and avoid circular dependencies it is important
- `modules/git`: Package to interactive with `Git` command line or Gogit package.
- `public`: Compiled frontend files (javascript, images, css, etc.)
- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) must not depend on routers.
- - `routers/api` Contains routers for `/api/v1` aims to handle RESTful API requests.
- - `routers/install` Could only respond when system is in INSTALL mode (INSTALL_LOCK=false).
- - `routers/private` will only be invoked by internal sub commands, especially `serv` and `hooks`.
+ - `routers/api` Contains routers for `/api/v1` aims to handle RESTful API requests.
+ - `routers/install` Could only respond when system is in INSTALL mode (INSTALL_LOCK=false).
+ - `routers/private` will only be invoked by internal sub commands, especially `serv` and `hooks`.
- `routers/web` will handle HTTP requests from web browsers or Git SMART HTTP protocols.
- `services`: Support functions for common routing operations or command executions. Uses `models` and `modules` to handle the requests.
- `templates`: Golang templates for generating the html output.
@@ -61,7 +61,7 @@ From left to right, left packages could depend on right packages, but right pack
**NOTICE**
Why do we need database transactions outside of `models`? And how?
-Some actions should allow for rollback when database record insertion/update/deletion failed.
+Some actions should allow for rollback when database record insertion/update/deletion failed.
So services must be allowed to create a database transaction. Here is some example,
```go
@@ -84,7 +84,7 @@ func CreateXXXX() error {\
}
```
-You should **not** use `db.GetEngine(ctx)` in `services` directly, but just write a function under `models/`.
+You should **not** use `db.GetEngine(ctx)` in `services` directly, but just write a function under `models/`.
If the function will be used in the transaction, just let `context.Context` as the function's first parameter.
```go
diff --git a/docs/content/doc/developers/guidelines-frontend.md b/docs/content/doc/developers/guidelines-frontend.md
index 0fced64b14cb7..87272d023fd3d 100644
--- a/docs/content/doc/developers/guidelines-frontend.md
+++ b/docs/content/doc/developers/guidelines-frontend.md
@@ -26,6 +26,7 @@ Gitea uses [Less CSS](https://lesscss.org), [Fomantic-UI](https://fomantic-ui.co
The HTML pages are rendered by [Go HTML Template](https://pkg.go.dev/html/template).
The source files can be found in the following directories:
+
* **Less styles:** `web_src/less/`
* **JavaScript files:** `web_src/js/`
* **Vue components:** `web_src/js/components/`
@@ -41,36 +42,37 @@ We recommend [Google HTML/CSS Style Guide](https://google.github.io/styleguide/h
2. HTML ids and classes should use kebab-case.
3. HTML ids and classes used in JavaScript should be unique for the whole project, and should contain 2-3 feature related keywords. We recommend to use the `js-` prefix for classes that are only used in JavaScript.
4. jQuery events across different features could use their own namespaces if there are potential conflicts.
-5. CSS styling for classes provided by frameworks should not be overwritten. Always use new class-names with 2-3 feature related keywords to overwrite framework styles.
+5. CSS styling for classes provided by frameworks should not be overwritten. Always use new class-names with 2-3 feature related keywords to overwrite framework styles.
6. The backend can pass complex data to the frontend by using `ctx.PageData["myModuleData"] = map[]{}`
7. Simple pages and SEO-related pages use Go HTML Template render to generate static Fomantic-UI HTML output. Complex pages can use Vue2 (or Vue3 in future).
-
### Framework Usage
Mixing different frameworks together is discouraged, it makes the code difficult to be maintained.
A JavaScript module should follow one major framework and follow the framework's best practice.
Recommended implementations:
+
* Vue + Vanilla JS
* Fomantic-UI (jQuery)
* Vanilla JS
Discouraged implementations:
+
* Vue + Fomantic-UI (jQuery)
* jQuery + Vanilla JS
To make UI consistent, Vue components can use Fomantic-UI CSS classes.
-Although mixing different frameworks is discouraged,
-it should also work if the mixing is necessary and the code is well-designed and maintainable.
+Although mixing different frameworks is discouraged,
+it should also work if the mixing is necessary and the code is well-designed and maintainable.
### `async` Functions
-Only mark a function as `async` if and only if there are `await` calls
+Only mark a function as `async` if and only if there are `await` calls
or `Promise` returns inside the function.
It's not recommended to use `async` event listeners, which may lead to problems.
-The reason is that the code after await is executed outside the event dispatch.
+The reason is that the code after await is executed outside the event dispatch.
Reference: https://github.com/github/eslint-plugin-github/blob/main/docs/rules/async-preventdefault.md
If we want to call an `async` function in a non-async context,
@@ -88,10 +90,9 @@ However, there are still some special cases, so the current guideline is:
* `$.data()` can be used to bind some non-string data to elements in rare cases, but it is highly discouraged.
* For new code:
- * `node.dataset` should not be used, use `node.getAttribute` instead.
+ * `node.dataset` should not be used, use `node.getAttribute` instead.
* never bind any user data to a DOM node, use a suitable design pattern to describe the relation between node and data.
-
### Legacy Code
A lot of legacy code already existed before this document's written. It's recommended to refactor legacy code to follow the guidelines.
diff --git a/docs/content/doc/developers/hacking-on-gitea.en-us.md b/docs/content/doc/developers/hacking-on-gitea.en-us.md
index 9d15f66dace10..abefb1ca96b38 100644
--- a/docs/content/doc/developers/hacking-on-gitea.en-us.md
+++ b/docs/content/doc/developers/hacking-on-gitea.en-us.md
@@ -35,7 +35,7 @@ on the executable path. If you don't add the go bin directory to the
executable path you will have to manage this yourself.
**Note 2**: Go version {{< min-go-version >}} or higher is required.
-Gitea uses `gofmt` to format source code. However, the results of
+Gitea uses `gofmt` to format source code. However, the results of
`gofmt` can differ by the version of `go`. Therefore it is
recommended to install the version of Go that our continuous integration is
running. As of last update, the Go version should be {{< go-version >}}.
@@ -69,7 +69,7 @@ One of these three distributions of Make will run on Windows:
- [32-bits version](http://www.equation.com/ftpdir/make/32/make.exe)
- [64-bits version](http://www.equation.com/ftpdir/make/64/make.exe)
- [MinGW-w64](https://www.mingw-w64.org) / [MSYS2](https://www.msys2.org/).
- - MSYS2 is a collection of tools and libraries providing you with an easy-to-use environment for building, installing and running native Windows software, it includes MinGW-w64.
+ - MSYS2 is a collection of tools and libraries providing you with an easy-to-use environment for building, installing and running native Windows software, it includes MinGW-w64.
- In MingGW-w64, the binary is called `mingw32-make.exe` instead of `make.exe`. Add the `bin` folder to `PATH`.
- In MSYS2, you can use `make` directly. See [MSYS2 Porting](https://www.msys2.org/wiki/Porting/).
- To compile Gitea with CGO_ENABLED (eg: SQLite3), you might need to use [tdm-gcc](https://jmeubank.github.io/tdm-gcc/) instead of MSYS2 gcc, because MSYS2 gcc headers lack some Windows-only CRT functions like `_beginthread`.
@@ -212,7 +212,7 @@ SVG icons are built using the `make svg` target which compiles the icon sources
### Building the Logo
-The PNG and SVG versions of the Gitea logo are built from a single SVG source file `assets/logo.svg` using the `TAGS="gitea" make generate-images` target. To run it, Node.js and npm must be available.
+The PNG and SVG versions of the Gitea logo are built from a single SVG source file `assets/logo.svg` using the `TAGS="gitea" make generate-images` target. To run it, Node.js and npm must be available.
The same process can also be used to generate custom logo PNGs from a SVG source file by updating `assets/logo.svg` and running `make generate-images`. Omitting the `gitea` tag will update only the user-designated logo files.
@@ -312,7 +312,6 @@ may need adjustment to the local environment.
Take a look at [`integrations/README.md`](https://github.com/go-gitea/gitea/blob/main/integrations/README.md)
for more information and how to run a single test.
-
### Testing for a PR
Our continuous integration will test the code passes its unit tests and that
@@ -345,13 +344,13 @@ for more information.
## GoLand
-Clicking the `Run Application` arrow on the function `func main()` in `/main.go`
+Clicking the `Run Application` arrow on the function `func main()` in `/main.go`
can quickly start a debuggable Gitea instance.
-The `Output Directory` in `Run/Debug Configuration` MUST be set to the
-gitea project directory (which contains `main.go` and `go.mod`),
-otherwise, the started instance's working directory is a GoLand's temporary directory
-and prevents Gitea from loading dynamic resources (eg: templates) in a development environment.
+The `Output Directory` in `Run/Debug Configuration` MUST be set to the
+gitea project directory (which contains `main.go` and `go.mod`),
+otherwise, the started instance's working directory is a GoLand's temporary directory
+and prevents Gitea from loading dynamic resources (eg: templates) in a development environment.
To run unit tests with SQLite in GoLand, set `-tags sqlite,sqlite_unlock_notify`
in `Go tool arguments` of `Run/Debug Configuration`.
diff --git a/docs/content/doc/developers/migrations.en-us.md b/docs/content/doc/developers/migrations.en-us.md
index b749f4f604fd0..168af1f7fa00a 100644
--- a/docs/content/doc/developers/migrations.en-us.md
+++ b/docs/content/doc/developers/migrations.en-us.md
@@ -16,11 +16,11 @@ menu:
# Migration Features
Complete migrations were introduced in Gitea 1.9.0. It defines two interfaces to support migrating
-repository data from other Git host platforms to Gitea or, in the future, migrating Gitea data to other
-Git host platforms.
+repository data from other Git host platforms to Gitea or, in the future, migrating Gitea data to other Git host platforms.
+
Currently, migrations from GitHub, GitLab, and other Gitea instances are implemented.
-First of all, Gitea defines some standard objects in packages [modules/migration](https://github.com/go-gitea/gitea/tree/main/modules/migration).
+First of all, Gitea defines some standard objects in packages [modules/migration](https://github.com/go-gitea/gitea/tree/main/modules/migration).
They are `Repository`, `Milestone`, `Release`, `ReleaseAsset`, `Label`, `Issue`, `Comment`, `PullRequest`, `Reaction`, `Review`, `ReviewComment`.
## Downloader Interfaces
@@ -29,7 +29,7 @@ To migrate from a new Git host platform, there are two steps to be updated.
- You should implement a `Downloader` which will be used to get repository information.
- You should implement a `DownloaderFactory` which will be used to detect if the URL matches and create the above `Downloader`.
- - You'll need to register the `DownloaderFactory` via `RegisterDownloaderFactory` on `init()`.
+ - You'll need to register the `DownloaderFactory` via `RegisterDownloaderFactory` on `init()`.
You can find these interfaces in [downloader.go](https://github.com/go-gitea/gitea/blob/main/modules/migration/downloader.go).
diff --git a/docs/content/doc/developers/migrations.zh-tw.md b/docs/content/doc/developers/migrations.zh-tw.md
index 0d892cae91152..173c01a464cd7 100644
--- a/docs/content/doc/developers/migrations.zh-tw.md
+++ b/docs/content/doc/developers/migrations.zh-tw.md
@@ -18,7 +18,7 @@ menu:
完整的遷移從 Gitea 1.9.0 開始提供。它定義了兩個介面用來從其它 Git 託管平臺遷移儲存庫資料到 Gitea,未來或許會提供遷移到其它 git 託管平臺。
目前已實作了從 Github, Gitlab 和其它 Gitea 遷移資料。
-Gitea 定義了一些基本物件於套件 [modules/migration](https://github.com/go-gitea/gitea/tree/master/modules/migration)。
+Gitea 定義了一些基本物件於套件 [modules/migration](https://github.com/go-gitea/gitea/tree/master/modules/migration)。
分別是 `Repository`, `Milestone`, `Release`, `ReleaseAsset`, `Label`, `Issue`, `Comment`, `PullRequest`, `Reaction`, `Review`, `ReviewComment`。
## Downloader 介面
diff --git a/docs/content/doc/developers/oauth2-provider.md b/docs/content/doc/developers/oauth2-provider.md
index ce6e9aad8cbe5..9e6ab11742fb5 100644
--- a/docs/content/doc/developers/oauth2-provider.md
+++ b/docs/content/doc/developers/oauth2-provider.md
@@ -34,6 +34,7 @@ Gitea supports acting as an OAuth2 provider to allow third party applications to
## Supported OAuth2 Grants
At the moment Gitea only supports the [**Authorization Code Grant**](https://tools.ietf.org/html/rfc6749#section-1.3.1) standard with additional support of the following extensions:
+
- [Proof Key for Code Exchange (PKCE)](https://tools.ietf.org/html/rfc7636)
- [OpenID Connect (OIDC)](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth)
diff --git a/docs/content/doc/features/authentication.en-us.md b/docs/content/doc/features/authentication.en-us.md
index 4b02679388a36..7d555d1dcc4b0 100644
--- a/docs/content/doc/features/authentication.en-us.md
+++ b/docs/content/doc/features/authentication.en-us.md
@@ -203,7 +203,7 @@ configure this, set the fields below:
- Force SMTPS
- - SMTPS will be used by default for connections to port 465, if you wish to use SMTPS
+ - SMTPS will be used by default for connections to port 465, if you wish to use SMTPS
for other ports. Set this value.
- Otherwise if the server provides the `STARTTLS` extension this will be used.
diff --git a/docs/content/doc/features/comparison.zh-cn.md b/docs/content/doc/features/comparison.zh-cn.md
index 98a50f5dc2abd..15ff4a6560841 100644
--- a/docs/content/doc/features/comparison.zh-cn.md
+++ b/docs/content/doc/features/comparison.zh-cn.md
@@ -46,7 +46,7 @@ _表格中的符号含义:_
| Git 驱动的集成化 wiki | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ |
| 部署令牌 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 仓库写权限令牌 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✓ |
-| 内置容器 Registry | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
+| 内置容器 Registry | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| 外部 Git 镜像 | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ |
| WebAuthn (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ? |
| 内置 CI/CD | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
@@ -62,7 +62,7 @@ _表格中的符号含义:_
| Git LFS 2.0 | ✓ | ✘ | ✓ | ✓ | ✓ | ⁄ | ✓ |
| 组织里程碑 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| 细粒度用户角色 (例如 Code, Issues, Wiki) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
-| 提交人的身份验证 | ✘ | ✘ | ? | ✓ | ✓ | ✓ | ✘ |
+| 提交人的身份验证 | ⁄ | ✘ | ? | ✓ | ✓ | ✓ | ✘ |
| GPG 签名的提交 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
| SSH 签名的提交 | ✓ | ✘ | ✘ | ✘ | ✘ | ? | ? |
| 拒绝未用通过验证的提交 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✓ |
@@ -71,6 +71,7 @@ _表格中的符号含义:_
| 建立新分支 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
| 在线代码编辑 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 提交的统计图表 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| 模板仓库 | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✘ |
#### Issue 管理
@@ -84,9 +85,9 @@ _表格中的符号含义:_
| 关联的 issues | ✘ | ✘ | ⁄ | ✘ | ✓ | ✘ | ✘ |
| 私密 issues | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| 评论反馈 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
-| 锁定讨论 | ✘ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
+| 锁定讨论 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
| Issue 批量处理 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
-| Issue 看板 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
+| Issue 看板 | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| 从 issues 创建分支 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| Issue 搜索 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
| 全局 Issue 搜索 | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
@@ -108,7 +109,7 @@ _表格中的符号含义:_
| 回退某些 commits 或 merge request | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
| Pull/Merge requests 模板 | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
| 查看 Cherry-picking 的更改 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
-
+| 下载 Patch | ✓ | ✘ | ✓ | ✓ | ✓ | / | ✘ |
#### 第三方集成
@@ -125,4 +126,5 @@ _表格中的符号含义:_
| 二次验证 (2FA) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ |
| 集成 Mattermost/Slack | ✓ | ✓ | ⁄ | ✓ | ✓ | ⁄ | ✓ |
| 集成 Discord | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
+| 集成 Microsoft Teams | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
| 显示外部 CI/CD 的状态 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
diff --git a/docs/content/doc/features/localization.en-us.md b/docs/content/doc/features/localization.en-us.md
index a5b7a52f89891..e57233a62255c 100644
--- a/docs/content/doc/features/localization.en-us.md
+++ b/docs/content/doc/features/localization.en-us.md
@@ -26,6 +26,8 @@ For changes to a **non-English** translation, refer to the Crowdin project above
Any language listed in the above Crowdin project will be supported as long as 25% or more has been translated.
-After a translation has been accepted, it will be reflected in the main repository after the next Crowdin sync, which is generally after any PR is merged.
-At the time of writing, this means that a changed translation may not appear until the following Gitea release.
+After a translation has been accepted, it will be reflected in the main repository after the next Crowdin sync, which is generally after any PR is merged.
+
+At the time of writing, this means that a changed translation may not appear until the following Gitea release.
+
If you use a bleeding edge build, it should appear as soon as you update after the change is synced.
diff --git a/docs/content/doc/features/localization.zh-tw.md b/docs/content/doc/features/localization.zh-tw.md
index e1000636069ab..7bb3a6e6a2ddf 100644
--- a/docs/content/doc/features/localization.zh-tw.md
+++ b/docs/content/doc/features/localization.zh-tw.md
@@ -25,6 +25,8 @@ menu:
上述 Crowdin 專案中列出的語言在翻譯超過 25% 後將被支援。
-翻譯被認可後將在下次 Crowdin 同步後進入到主儲存庫,通常是在任何合併請求被合併之後。
-這表示更改的翻譯要到下次 Gitea 發佈後才會出現。
+翻譯被認可後將在下次 Crowdin 同步後進入到主儲存庫,通常是在任何合併請求被合併之後。
+
+這表示更改的翻譯要到下次 Gitea 發佈後才會出現。
+
如果您使用的是最新建置,它將會在同步完成、您更新後出現。
diff --git a/docs/content/doc/help/faq.en-us.md b/docs/content/doc/help/faq.en-us.md
index a64cccfa66f4c..17983da695389 100644
--- a/docs/content/doc/help/faq.en-us.md
+++ b/docs/content/doc/help/faq.en-us.md
@@ -15,7 +15,8 @@ menu:
# Frequently Asked Questions
-This page contains some common questions and answers.
+This page contains some common questions and answers.
+
For more help resources, check all [Support Options]({{< relref "doc/help/seek-help.en-us.md" >}}).
**Table of Contents**
@@ -24,14 +25,18 @@ For more help resources, check all [Support Options]({{< relref "doc/help/seek-h
## Difference between 1.x and 1.x.x downloads
-Version 1.7.x will be used for this example.
+Version 1.7.x will be used for this example.
+
**NOTE:** this example applies to Docker images as well!
-On our [downloads page](https://dl.gitea.io/gitea/) you will see a 1.7 directory, as well as directories for 1.7.0, 1.7.1, 1.7.2, 1.7.3, 1.7.4, 1.7.5, and 1.7.6.
-The 1.7 and 1.7.0 directories are **not** the same. The 1.7 directory is built on each merged commit to the [`release/v1.7`](https://github.com/go-gitea/gitea/tree/release/v1.7) branch.
+On our [downloads page](https://dl.gitea.io/gitea/) you will see a 1.7 directory, as well as directories for 1.7.0, 1.7.1, 1.7.2, 1.7.3, 1.7.4, 1.7.5, and 1.7.6.
+
+The 1.7 and 1.7.0 directories are **not** the same. The 1.7 directory is built on each merged commit to the [`release/v1.7`](https://github.com/go-gitea/gitea/tree/release/v1.7) branch.
+
The 1.7.0 directory, however, is a build that was created when the [`v1.7.0`](https://github.com/go-gitea/gitea/releases/tag/v1.7.0) tag was created.
-This means that 1.x downloads will change as commits are merged to their respective branch (think of it as a separate "main" branch for each release).
+This means that 1.x downloads will change as commits are merged to their respective branch (think of it as a separate "main" branch for each release).
+
On the other hand, 1.x.x downloads should never change.
## How to migrate from Gogs/GitHub/etc. to Gitea
@@ -41,11 +46,14 @@ To migrate from Gogs to Gitea:
- [Gogs version 0.9.146 or less]({{< relref "doc/upgrade/from-gogs.en-us.md" >}})
- [Gogs version 0.11.46.0418](https://github.com/go-gitea/gitea/issues/4286)
-To migrate from GitHub to Gitea, you can use Gitea's built-in migration form.
-In order to migrate items such as issues, pull requests, etc. you will need to input at least your username.
+To migrate from GitHub to Gitea, you can use Gitea's built-in migration form.
+
+In order to migrate items such as issues, pull requests, etc. you will need to input at least your username.
+
[Example (requires login)](https://try.gitea.io/repo/migrate)
-To migrate from GitLab to Gitea, you can use this non-affiliated tool:
+To migrate from GitLab to Gitea, you can use this non-affiliated tool:
+
https://github.com/loganinak/MigrateGitlabToGogs
## Where does Gitea store what file
@@ -83,9 +91,9 @@ There are a few places that could make this show incorrectly.
If certain clone options aren't showing up (HTTP/S or SSH), the following options can be checked in your `app.ini`
-`DISABLE_HTTP_GIT`: if set to true, there will be no HTTP/HTTPS link
-`DISABLE_SSH`: if set to true, there will be no SSH link
-`SSH_EXPOSE_ANONYMOUS`: if set to false, SSH links will be hidden for anonymous users
+- `DISABLE_HTTP_GIT`: if set to true, there will be no HTTP/HTTPS link
+- `DISABLE_SSH`: if set to true, there will be no SSH link
+- `SSH_EXPOSE_ANONYMOUS`: if set to false, SSH links will be hidden for anonymous users
## File upload fails with: 413 Request Entity Too Large
@@ -95,19 +103,21 @@ See the [reverse proxy guide]({{< relref "doc/usage/reverse-proxies.en-us.md" >}
## Custom Templates not loading or working incorrectly
-Gitea's custom templates must be added to the correct location or Gitea will not find and use them.
+Gitea's custom templates must be added to the correct location or Gitea will not find and use them.
+
The correct path for the template(s) will be relative to the `CustomPath`
1. To find `CustomPath`, look for Custom File Root Path in Site Administration -> Configuration
-- If that doesn't exist, you can try `echo $GITEA_CUSTOM`
+ If that doesn't exist, you can try `echo $GITEA_CUSTOM`
-2. If you are still unable to find a path, the default can be [calculated above](#where-does-gitea-store-x-file)
+2. If you are still unable to find a path, the default can be [calculated above](#where-does-gitea-store-what-file)
3. Once you have figured out the correct custom path, you can refer to the [customizing Gitea]({{< relref "doc/advanced/customizing-gitea.en-us.md" >}}) page to add your template to the correct location.
## Active user vs login prohibited user
-In Gitea, an "active" user refers to a user that has activated their account via email.
+In Gitea, an "active" user refers to a user that has activated their account via email.
+
A "login prohibited" user is a user that is not allowed to log in to Gitea anymore
## Setting up logging
@@ -116,8 +126,10 @@ A "login prohibited" user is a user that is not allowed to log in to Gitea anymo
## What is Swagger?
-[Swagger](https://swagger.io/) is what Gitea uses for its API.
-All Gitea instances have the built-in API, though it can be disabled by setting `ENABLE_SWAGGER` to `false` in the `api` section of your `app.ini`
+[Swagger](https://swagger.io/) is what Gitea uses for its API.
+
+All Gitea instances have the built-in API, though it can be disabled by setting `ENABLE_SWAGGER` to `false` in the `api` section of your `app.ini`
+
For more information, refer to Gitea's [API docs]({{< relref "doc/developers/api-usage.en-us.md" >}})
[Swagger Example](https://try.gitea.io/api/swagger)
@@ -139,7 +151,8 @@ You can configure `EMAIL_DOMAIN_WHITELIST` or `EMAIL_DOMAIN_BLOCKLIST` in your a
### Only allow/block certain OpenID providers
-You can configure `WHITELISTED_URIS` or `BLACKLISTED_URIS` under `[openid]` in your `app.ini`
+You can configure `WHITELISTED_URIS` or `BLACKLISTED_URIS` under `[openid]` in your `app.ini`
+
**NOTE:** whitelisted takes precedence, so if it is non-blank then blacklisted is ignored
### Issue only users
@@ -163,38 +176,48 @@ Use [Fail2Ban]({{< relref "doc/usage/fail2ban-setup.en-us.md" >}}) to monitor an
Gitea supports three official themes right now, `gitea` (light), `arc-green` (dark), and `auto` (automatically switches between the previous two depending on operating system settings).
To add your own theme, currently the only way is to provide a complete theme (not just color overrides)
-As an example, let's say our theme is `arc-blue` (this is a real theme, and can be found [in this issue](https://github.com/go-gitea/gitea/issues/6011))
-Name the `.css` file `theme-arc-blue.css` and add it to your custom folder in `custom/public/css`
+As an example, let's say our theme is `arc-blue` (this is a real theme, and can be found [in this issue](https://github.com/go-gitea/gitea/issues/6011))
+
+Name the `.css` file `theme-arc-blue.css` and add it to your custom folder in `custom/public/css`
+
Allow users to use it by adding `arc-blue` to the list of `THEMES` in your `app.ini`
## SSHD vs built-in SSH
-SSHD is the built-in SSH server on most Unix systems.
+SSHD is the built-in SSH server on most Unix systems.
+
Gitea also provides its own SSH server, for usage when SSHD is not available.
## Gitea is running slow
-The most common culprit for this is loading federated avatars.
-This can be turned off by setting `ENABLE_FEDERATED_AVATAR` to `false` in your `app.ini`
+The most common culprit for this is loading federated avatars.
+
+This can be turned off by setting `ENABLE_FEDERATED_AVATAR` to `false` in your `app.ini`
+
Another option that may need to be changed is setting `DISABLE_GRAVATAR` to `true` in your `app.ini`
## Can't create repositories/files
-Make sure that Gitea has sufficient permissions to write to its home directory and data directory.
-See [AppDataPath and RepoRootPath](#where-does-gitea-store-x-file)
+Make sure that Gitea has sufficient permissions to write to its home directory and data directory.
+
+See [AppDataPath and RepoRootPath](#where-does-gitea-store-what-file)
**Note for Arch users:** At the time of writing this, there is an issue with the Arch package's systemd file including this line:
-`ReadWritePaths=/etc/gitea/app.ini`
+
+`ReadWritePaths=/etc/gitea/app.ini`
+
Which makes all other paths non-writeable to Gitea.
## Translation is incorrect/how to add more translations
-Our translations are currently crowd-sourced on our [Crowdin project](https://crowdin.com/project/gitea)
+Our translations are currently crowd-sourced on our [Crowdin project](https://crowdin.com/project/gitea)
+
Whether you want to change a translation or add a new one, it will need to be there as all translations are overwritten in our CI via the Crowdin integration.
## Hooks aren't running
-If Gitea is not running hooks, a common cause is incorrect setup of SSH keys.
+If Gitea is not running hooks, a common cause is incorrect setup of SSH keys.
+
See [SSH Issues](#ssh-issues) for more information.
You can also try logging into the administration panel and running the `Resynchronize pre-receive, update and post-receive hooks of all repositories.` option.
@@ -203,7 +226,8 @@ You can also try logging into the administration panel and running the `Resynchr
If you cannot reach repositories over `ssh`, but `https` works fine, consider looking into the following.
-First, make sure you can access Gitea via SSH.
+First, make sure you can access Gitea via SSH.
+
`ssh git@myremote.example`
If the connection is successful, you should receive an error message like the following:
@@ -236,7 +260,8 @@ following things:
- On the server:
- Make sure the repository exists and is correctly named.
- Check the permissions of the `.ssh` directory in the system user's home directory.
- - Verify that the correct public keys are added to `.ssh/authorized_keys`.
+ - Verify that the correct public keys are added to `.ssh/authorized_keys`.
+
Try to run `Rewrite '.ssh/authorized_keys' file (for Gitea SSH keys)` on the
Gitea admin panel.
- Read Gitea logs.
@@ -289,7 +314,8 @@ Check that you have proper access to the repository
error: failed to push some refs to ''
```
-Check the value of `LFS_HTTP_AUTH_EXPIRY` in your `app.ini` file.
+Check the value of `LFS_HTTP_AUTH_EXPIRY` in your `app.ini` file.
+
By default, your LFS token will expire after 20 minutes. If you have a slow connection or a large file (or both), it may not finish uploading within the time limit.
You may want to set this value to `60m` or `120m`.
@@ -306,17 +332,21 @@ There is no setting for password resets. It is enabled when a [mail service]({{<
- As an **admin**, you can change any user's password (and optionally force them to change it on next login)...
- By navigating to your `Site Administration -> User Accounts` page and editing a user.
- - By using the [admin CLI commands]({{< relref "doc/usage/command-line.en-us.md#admin" >}}).
+ - By using the [admin CLI commands]({{< relref "doc/usage/command-line.en-us.md#admin" >}}).
+
Keep in mind most commands will also need a [global flag]({{< relref "doc/usage/command-line.en-us.md#global-options" >}}) to point the CLI at the correct configuration.
- As a **user** you can change it...
- In your account `Settings -> Account` page (this method **requires** you to know your current password).
- - By using the `Forgot Password` link.
+ - By using the `Forgot Password` link.
+
If the `Forgot Password/Account Recovery` page is disabled, please contact your administrator to configure a [mail service]({{< relref "doc/usage/email-setup.en-us.md" >}}).
## Why is my markdown broken
-In Gitea version `1.11` we moved to [goldmark](https://github.com/yuin/goldmark) for markdown rendering, which is [CommonMark](https://commonmark.org/) compliant.
-If you have markdown that worked as you expected prior to version `1.11` and after upgrading it's not working anymore, please look through the CommonMark spec to see whether the problem is due to a bug or non-compliant syntax.
+In Gitea version `1.11` we moved to [goldmark](https://github.com/yuin/goldmark) for markdown rendering, which is [CommonMark](https://commonmark.org/) compliant.
+
+If you have markdown that worked as you expected prior to version `1.11` and after upgrading it's not working anymore, please look through the CommonMark spec to see whether the problem is due to a bug or non-compliant syntax.
+
If it is the latter, _usually_ there is a compliant alternative listed in the spec.
## Upgrade errors with MySQL
@@ -332,8 +362,10 @@ is too small. Gitea requires that the `ROWFORMAT` for its tables is `DYNAMIC`.
If you are receiving an error line containing `Error 1071: Specified key was too long; max key length is 1000 bytes...`
then you are attempting to run Gitea on tables which use the ISAM engine. While this may have worked by chance in previous versions of Gitea, it has never been officially supported and
-you must use InnoDB. You should run `ALTER TABLE table_name ENGINE=InnoDB;` for each table in the database.
+you must use InnoDB. You should run `ALTER TABLE table_name ENGINE=InnoDB;` for each table in the database.
+
If you are using MySQL 5, another possible fix is
+
```mysql
SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
@@ -403,3 +435,9 @@ gitea doctor recreate-table
```
It is highly recommended to back-up your database before running these commands.
+
+## Why are tabs/indents wrong when viewing files
+
+If you are using Cloudflare, turn off the auto-minify option in the dashboard.
+
+`Speed` -> `Optimization` -> Uncheck `HTML` within the `Auto-Minify` settings.
diff --git a/docs/content/doc/help/seek-help.en-us.md b/docs/content/doc/help/seek-help.en-us.md
index 3ee160f4316fd..fe898e34b90d9 100644
--- a/docs/content/doc/help/seek-help.en-us.md
+++ b/docs/content/doc/help/seek-help.en-us.md
@@ -22,9 +22,10 @@ menu:
1. Your `app.ini` (with any sensitive data scrubbed as necessary).
2. The Gitea logs, and any other appropriate log files for the situation.
- * The logs are likely to be outputted to console. If you need to collect logs from files,
+ - The logs are likely to be outputted to console. If you need to collect logs from files,
you could copy the following config into your `app.ini` (remove all other `[log]` sections),
then you can find the `*.log` files in Gitea's log directory (default: `%(GITEA_WORK_DIR)/log`).
+
```ini
; To show all SQL logs, you can also set LOG_SQL=true in the [database] section
[log]
@@ -38,18 +39,22 @@ menu:
FILE_NAME=router.log
[log.file.xorm]
FILE_NAME=xorm.log
- ```
+ ```
+
3. Any error messages you are seeing.
4. When possible, try to replicate the issue on [try.gitea.io](https://try.gitea.io) and include steps so that others can reproduce the issue.
- * This will greatly improve the chance that the root of the issue can be quickly discovered and resolved.
+ - This will greatly improve the chance that the root of the issue can be quickly discovered and resolved.
5. If you meet slow/hanging/deadlock problems, please report the stack trace when the problem occurs:
1. Enable pprof in `app.ini` and restart Gitea
- ```
- [server]
- ENABLE_PPROF = true
- ```
- 2. Trigger the bug, when Gitea gets stuck, use curl or browser to visit: `http://127.0.0.1:6060/debug/pprof/goroutine?debug=1` (IP is `127.0.0.1` and port is `6060`)
- 3. Report the output (the stack trace doesn't contain sensitive data)
+
+ ```ini
+ [server]
+ ENABLE_PPROF = true
+ ```
+
+ 2. Trigger the bug, when Gitea gets stuck, use curl or browser to visit: `http://127.0.0.1:6060/debug/pprof/goroutine?debug=1` (IP must be `127.0.0.1` and port must be `6060`).
+ 3. If you are using Docker, please use `docker exec -it curl "http://127.0.0.1:6060/debug/pprof/goroutine?debug=1"`.
+ 4. Report the output (the stack trace doesn't contain sensitive data)
## Bugs
diff --git a/docs/content/doc/help/seek-help.zh-tw.md b/docs/content/doc/help/seek-help.zh-tw.md
index 3d45e6c3b2554..f9107a026b1bd 100644
--- a/docs/content/doc/help/seek-help.zh-tw.md
+++ b/docs/content/doc/help/seek-help.zh-tw.md
@@ -22,10 +22,10 @@ menu:
1. 您的 `app.ini` (必要時清除掉任何機密資訊)
2. `gitea.log` (以及任何有關的日誌檔案)
- * 例:如果錯誤和資料庫相關,提供 `xorm.log` 可能會有幫助
+ - 例:如果錯誤和資料庫相關,提供 `xorm.log` 可能會有幫助
3. 您看到的任何錯誤訊息
4. 儘可能地在 [try.gitea.io](https://try.gitea.io) 觸發您的問題並記下步驟,以便其他人能重現那個問題。
- * 這將讓我們更有機會快速地找出問題的根源並解決它。
+ - 這將讓我們更有機會快速地找出問題的根源並解決它。
5. 堆棧跟踪,[請參考英文文檔](https://docs.gitea.io/en-us/seek-help/)
## 錯誤回報
diff --git a/docs/content/doc/installation/database-preparation.en-us.md b/docs/content/doc/installation/database-preparation.en-us.md
index 13a215d81483c..b8ad5d6859fb0 100644
--- a/docs/content/doc/installation/database-preparation.en-us.md
+++ b/docs/content/doc/installation/database-preparation.en-us.md
@@ -27,13 +27,13 @@ Note: All steps below requires that the database engine of your choice is instal
## MySQL
-1. For remote database setup, you will need to make MySQL listen to your IP address. Edit `bind-address` option on `/etc/mysql/my.cnf` on database instance to:
+1. For remote database setup, you will need to make MySQL listen to your IP address. Edit `bind-address` option on `/etc/mysql/my.cnf` on database instance to:
```ini
bind-address = 203.0.113.3
```
-2. On database instance, login to database console as root:
+2. On database instance, login to database console as root:
```
mysql -u root -p
@@ -41,7 +41,7 @@ Note: All steps below requires that the database engine of your choice is instal
Enter the password as prompted.
-3. Create database user which will be used by Gitea, authenticated by password. This example uses `'gitea'` as password. Please use a secure password for your instance.
+3. Create database user which will be used by Gitea, authenticated by password. This example uses `'gitea'` as password. Please use a secure password for your instance.
For local database:
@@ -61,7 +61,7 @@ Note: All steps below requires that the database engine of your choice is instal
Replace username and password above as appropriate.
-4. Create database with UTF-8 charset and collation. Make sure to use `utf8mb4` charset instead of `utf8` as the former supports all Unicode characters (including emojis) beyond _Basic Multilingual Plane_. Also, collation chosen depending on your expected content. When in doubt, use either `unicode_ci` or `general_ci`.
+4. Create database with UTF-8 charset and collation. Make sure to use `utf8mb4` charset instead of `utf8` as the former supports all Unicode characters (including emojis) beyond _Basic Multilingual Plane_. Also, collation chosen depending on your expected content. When in doubt, use either `unicode_ci` or `general_ci`.
```sql
CREATE DATABASE giteadb CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
@@ -69,7 +69,7 @@ Note: All steps below requires that the database engine of your choice is instal
Replace database name as appropriate.
-5. Grant all privileges on the database to database user created above.
+5. Grant all privileges on the database to database user created above.
For local database:
@@ -85,9 +85,9 @@ Note: All steps below requires that the database engine of your choice is instal
FLUSH PRIVILEGES;
```
-6. Quit from database console by `exit`.
+6. Quit from database console by `exit`.
-7. On your Gitea server, test connection to the database:
+7. On your Gitea server, test connection to the database:
```
mysql -u gitea -h 203.0.113.3 -p giteadb
@@ -99,13 +99,13 @@ Note: All steps below requires that the database engine of your choice is instal
## PostgreSQL
-1. For remote database setup, configure PostgreSQL on database instance to listen to your IP address by editing `listen_addresses` on `postgresql.conf` to:
+1. For remote database setup, configure PostgreSQL on database instance to listen to your IP address by editing `listen_addresses` on `postgresql.conf` to:
```ini
listen_addresses = 'localhost, 203.0.113.3'
```
-2. PostgreSQL uses `md5` challenge-response encryption scheme for password authentication by default. Nowadays this scheme is not considered secure anymore. Use SCRAM-SHA-256 scheme instead by editing the `postgresql.conf` configuration file on the database server to:
+2. PostgreSQL uses `md5` challenge-response encryption scheme for password authentication by default. Nowadays this scheme is not considered secure anymore. Use SCRAM-SHA-256 scheme instead by editing the `postgresql.conf` configuration file on the database server to:
```ini
password_encryption = scram-sha-256
@@ -113,13 +113,13 @@ Note: All steps below requires that the database engine of your choice is instal
Restart PostgreSQL to apply the setting.
-3. On the database server, login to the database console as superuser:
+3. On the database server, login to the database console as superuser:
```
su -c "psql" - postgres
```
-4. Create database user (role in PostgreSQL terms) with login privilege and password. Please use a secure, strong password instead of `'gitea'` below:
+4. Create database user (role in PostgreSQL terms) with login privilege and password. Please use a secure, strong password instead of `'gitea'` below:
```sql
CREATE ROLE gitea WITH LOGIN PASSWORD 'gitea';
@@ -127,7 +127,7 @@ Note: All steps below requires that the database engine of your choice is instal
Replace username and password as appropriate.
-5. Create database with UTF-8 charset and owned by the database user created earlier. Any `libc` collations can be specified with `LC_COLLATE` and `LC_CTYPE` parameter, depending on expected content:
+5. Create database with UTF-8 charset and owned by the database user created earlier. Any `libc` collations can be specified with `LC_COLLATE` and `LC_CTYPE` parameter, depending on expected content:
```sql
CREATE DATABASE giteadb WITH OWNER gitea TEMPLATE template0 ENCODING UTF8 LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';
@@ -135,7 +135,7 @@ Note: All steps below requires that the database engine of your choice is instal
Replace database name as appropriate.
-6. Allow the database user to access the database created above by adding the following authentication rule to `pg_hba.conf`.
+6. Allow the database user to access the database created above by adding the following authentication rule to `pg_hba.conf`.
For local database:
@@ -155,7 +155,7 @@ Note: All steps below requires that the database engine of your choice is instal
Restart PostgreSQL to apply new authentication rules.
-7. On your Gitea server, test connection to the database.
+7. On your Gitea server, test connection to the database.
For local database:
@@ -188,13 +188,13 @@ If the communication between Gitea and your database instance is performed throu
The PostgreSQL driver used by Gitea supports two-way TLS. In two-way TLS, both database client and server authenticate each other by sending their respective certificates to their respective opposite for validation. In other words, the server verifies client certificate, and the client verifies server certificate.
-1. On the server with the database instance, place the following credentials:
+1. On the server with the database instance, place the following credentials:
- `/path/to/postgresql.crt`: Database instance certificate
- `/path/to/postgresql.key`: Database instance private key
- `/path/to/root.crt`: CA certificate chain to validate client certificates
-2. Add following options to `postgresql.conf`:
+2. Add following options to `postgresql.conf`:
```ini
ssl = on
@@ -204,14 +204,14 @@ The PostgreSQL driver used by Gitea supports two-way TLS. In two-way TLS, both d
ssl_min_protocol_version = 'TLSv1.2'
```
-3. Adjust credentials ownership and permission, as required by PostgreSQL:
+3. Adjust credentials ownership and permission, as required by PostgreSQL:
```
chown postgres:postgres /path/to/root.crt /path/to/postgresql.crt /path/to/postgresql.key
chmod 0600 /path/to/root.crt /path/to/postgresql.crt /path/to/postgresql.key
```
-4. Edit `pg_hba.conf` rule to only allow Gitea database user to connect over SSL, and to require client certificate verification.
+4. Edit `pg_hba.conf` rule to only allow Gitea database user to connect over SSL, and to require client certificate verification.
For PostgreSQL 12:
@@ -227,9 +227,9 @@ The PostgreSQL driver used by Gitea supports two-way TLS. In two-way TLS, both d
Replace database name, user, and IP address of Gitea instance as appropriate.
-5. Restart PostgreSQL to apply configurations above.
+5. Restart PostgreSQL to apply configurations above.
-6. On the server running the Gitea instance, place the following credentials under the home directory of the user who runs Gitea (e.g. `git`):
+6. On the server running the Gitea instance, place the following credentials under the home directory of the user who runs Gitea (e.g. `git`):
- `~/.postgresql/postgresql.crt`: Database client certificate
- `~/.postgresql/postgresql.key`: Database client private key
@@ -237,14 +237,14 @@ The PostgreSQL driver used by Gitea supports two-way TLS. In two-way TLS, both d
Note: Those file names above are hardcoded in PostgreSQL and it is not possible to change them.
-7. Adjust credentials, ownership and permission as required:
+7. Adjust credentials, ownership and permission as required:
```
chown git:git ~/.postgresql/postgresql.crt ~/.postgresql/postgresql.key ~/.postgresql/root.crt
chown 0600 ~/.postgresql/postgresql.crt ~/.postgresql/postgresql.key ~/.postgresql/root.crt
```
-8. Test the connection to the database:
+8. Test the connection to the database:
```
psql "postgres://gitea@example.db/giteadb?sslmode=verify-full"
@@ -258,13 +258,13 @@ While the MySQL driver used by Gitea also supports two-way TLS, Gitea currently
In one-way TLS, the database client verifies the certificate sent from server during the connection handshake, and the server assumes that the connected client is legitimate, since client certificate verification doesn't take place.
-1. On the database instance, place the following credentials:
+1. On the database instance, place the following credentials:
- `/path/to/mysql.crt`: Database instance certificate
- `/path/to/mysql.key`: Database instance key
- `/path/to/ca.crt`: CA certificate chain. This file isn't used on one-way TLS, but is used to validate client certificates on two-way TLS.
-2. Add following options to `my.cnf`:
+2. Add following options to `my.cnf`:
```ini
[mysqld]
@@ -274,16 +274,16 @@ In one-way TLS, the database client verifies the certificate sent from server du
tls-version = TLSv1.2,TLSv1.3
```
-3. Adjust credentials ownership and permission:
+3. Adjust credentials ownership and permission:
```
chown mysql:mysql /path/to/ca.crt /path/to/mysql.crt /path/to/mysql.key
chmod 0600 /path/to/ca.crt /path/to/mysql.crt /path/to/mysql.key
```
-4. Restart MySQL to apply the setting.
+4. Restart MySQL to apply the setting.
-5. The database user for Gitea may have been created earlier, but it would authenticate only against the IP addresses of the server running Gitea. To authenticate against its domain name, recreate the user, and this time also set it to require TLS for connecting to the database:
+5. The database user for Gitea may have been created earlier, but it would authenticate only against the IP addresses of the server running Gitea. To authenticate against its domain name, recreate the user, and this time also set it to require TLS for connecting to the database:
```sql
DROP USER 'gitea'@'192.0.2.10';
@@ -294,9 +294,9 @@ In one-way TLS, the database client verifies the certificate sent from server du
Replace database user name, password, and Gitea instance domain as appropriate.
-6. Make sure that the CA certificate chain required to validate the database server certificate is on the system certificate store of both the database and Gitea servers. Consult your system documentation for instructions on adding a CA certificate to the certificate store.
+6. Make sure that the CA certificate chain required to validate the database server certificate is on the system certificate store of both the database and Gitea servers. Consult your system documentation for instructions on adding a CA certificate to the certificate store.
-7. On the server running Gitea, test connection to the database:
+7. On the server running Gitea, test connection to the database:
```
mysql -u gitea -h example.db -p --ssl
diff --git a/docs/content/doc/installation/from-binary.en-us.md b/docs/content/doc/installation/from-binary.en-us.md
index d3486d8150996..f603fe37cfd0a 100644
--- a/docs/content/doc/installation/from-binary.en-us.md
+++ b/docs/content/doc/installation/from-binary.en-us.md
@@ -24,14 +24,31 @@ embedded assets. This can be different for older releases.
## Download
-Choose the file matching the destination platform from the [downloads page](https://dl.gitea.io/gitea/), copy the URL and replace the URL within the commands below:
+You can find the file matching your platform from the [downloads page](https://dl.gitea.io/gitea/) after navigating to the version you want to download.
+
+### Choosing the right file
+
+**For Linux**, you will likely want `linux-amd64`. It's for 64-bit Intel/AMD platforms, but there are other platforms available, including `arm64` (e.g. Raspberry PI 4), `386` (i.e. 32-bit), `arm-5`, and `arm-6`.
+
+**For Windows**, you will likely want `windows-4.0-amd64`. It's for all modern versions of Windows, but there is also a `386` platform available designed for older, 32-bit versions of Windows.
+
+*Note: there is also a `gogit-windows` file available that was created to help with some [performance problems](https://github.com/go-gitea/gitea/pull/15482) reported by some Windows users on older systems/versions. You should consider using this file if you're experiencing performance issues, and let us know if it improves performance.*
+
+**For macOS**, you should choose `darwin-arm64` if your hardware uses Apple Silicon, or `darwin-amd64` for Intel.
+
+### Downloading with wget
+
+Copy the commands below and replace the URL within the one you wish to download.
```sh
wget -O gitea https://dl.gitea.io/gitea/{{< version >}}/gitea-{{< version >}}-linux-amd64
chmod +x gitea
```
+Note that the above command will download Gitea {{< version >}} for 64-bit Linux.
+
## Verify GPG signature
+
Gitea signs all binaries with a [GPG key](https://keys.openpgp.org/search?q=teabot%40gitea.io) to prevent against unwanted modification of binaries.
To validate the binary, download the signature file which ends in `.asc` for the binary you downloaded and use the GPG command line tool.
@@ -56,7 +73,8 @@ Check that Git is installed on the server. If it is not, install it first. Gitea
git --version
```
-Create user to run Gitea (ex. `git`)
+Create a user to run Gitea (e.g. `git`)
+
```sh
adduser \
--system \
@@ -79,29 +97,39 @@ chown root:git /etc/gitea
chmod 770 /etc/gitea
```
-**NOTE:** `/etc/gitea` is temporary set with write rights for user `git` so that Web installer could write configuration file. After installation is done, it is recommended to set rights to read-only using:
-```
+**NOTE:** `/etc/gitea` is temporarily set with write permissions for user `git` so that the web installer can write the configuration file. After the installation is finished, it is recommended to set permissions to read-only using:
+
+```sh
chmod 750 /etc/gitea
chmod 640 /etc/gitea/app.ini
```
-If you don't want the web installer to be able to write the config file at all, it is also possible to make the config file read-only for the Gitea user (owner/group `root:git`, mode `0640`), and set `INSTALL_LOCK = true`. In that case all database configuration details must be set beforehand in the config file, as well as the `SECRET_KEY` and `INTERNAL_TOKEN` values. See the [command line documentation]({{< relref "doc/usage/command-line.en-us.md" >}}) for information on using `gitea generate secret INTERNAL_TOKEN`.
+
+If you don't want the web installer to be able to write to the config file, it is possible to make the config file read-only for the Gitea user (owner/group `root:git`, mode `0640`) however you will need to edit your config file manually to:
+
+* Set `INSTALL_LOCK= true`,
+* Ensure all database configuration details are set correctly
+* Ensure that the `SECRET_KEY` and `INTERNAL_TOKEN` values are set. (You may want to use the `gitea generate secret` to generate these secret keys.)
+* Ensure that any other secret keys you need are set.
+
+See the [command line documentation]({{< relref "doc/usage/command-line.en-us.md" >}}) for information on using `gitea generate secret`.
### Configure Gitea's working directory
-**NOTE:** If you plan on running Gitea as a Linux service, you can skip this step as the service file allows you to set `WorkingDirectory`. Otherwise, consider setting this environment variable (semi-)permanently so that Gitea consistently uses the correct working directory.
-```
+**NOTE:** If you plan on running Gitea as a Linux service, you can skip this step, as the service file allows you to set `WorkingDirectory`. Otherwise, consider setting this environment variable (semi-)permanently so that Gitea consistently uses the correct working directory.
+
+```sh
export GITEA_WORK_DIR=/var/lib/gitea/
```
-### Copy Gitea binary to global location
+### Copy the Gitea binary to a global location
-```
+```sh
cp gitea /usr/local/bin/gitea
```
## Running Gitea
-After the above steps, two options to run Gitea are:
+After you complete the above steps, you can run Gitea two ways:
### 1. Creating a service file to start Gitea automatically (recommended)
@@ -109,32 +137,31 @@ See how to create [Linux service]({{< relref "run-as-service-in-ubuntu.en-us.md"
### 2. Running from command-line/terminal
-```
+```sh
GITEA_WORK_DIR=/var/lib/gitea/ /usr/local/bin/gitea web -c /etc/gitea/app.ini
```
## Updating to a new version
You can update to a new version of Gitea by stopping Gitea, replacing the binary at `/usr/local/bin/gitea` and restarting the instance.
-The binary file name should not be changed during the update to avoid problems
-in existing repositories.
+The binary file name should not be changed during the update to avoid problems in existing repositories.
-It is recommended you do a [backup]({{< relref "doc/usage/backup-and-restore.en-us.md" >}}) before updating your installation.
+It is recommended that you make a [backup]({{< relref "doc/usage/backup-and-restore.en-us.md" >}}) before updating your installation.
If you have carried out the installation steps as described above, the binary should
have the generic name `gitea`. Do not change this, i.e. to include the version number.
### 1. Restarting Gitea with systemd (recommended)
-As explained before, we recommend to use systemd as service manager. In this case ```systemctl restart gitea``` should be enough.
+As we explained before, we recommend to use systemd as the service manager. In this case, `systemctl restart gitea` should be fine.
### 2. Restarting Gitea without systemd
-To restart your Gitea instance, we recommend to use SIGHUP signal. If you know your Gitea PID use ```kill -1 $GITEA_PID``` otherwise you can use ```killall -1 gitea``` or ```pkill -1 gitea```
+To restart your Gitea instance, we recommend to use SIGHUP signal. If you know your Gitea PID, use `kill -1 $GITEA_PID`, otherwise you can use `killall -1 gitea`.
-To gracefully stop the Gitea instance, a simple ```kill $GITEA_PID``` or ```killall gitea``` is enough.
+To gracefully stop the Gitea instance, a simple `kill $GITEA_PID` or `killall gitea` is enough.
-**NOTE:** We don't recommend to use SIGKILL signal (know also as `-9`), you may be forcefully stopping some of Gitea internal tasks and it will not gracefully stop (tasks in queues, indexers processes, etc.)
+**NOTE:** We don't recommend to use the SIGKILL signal (`-9`); you may be forcefully stopping some of Gitea's internal tasks, and it will not gracefully stop (tasks in queues, indexers, etc.)
See below for troubleshooting instructions to repair broken repositories after
an update of your Gitea version.
@@ -144,31 +171,31 @@ an update of your Gitea version.
### Old glibc versions
Older Linux distributions (such as Debian 7 and CentOS 6) may not be able to load the
-Gitea binary, usually producing an error such as ```./gitea: /lib/x86_64-linux-gnu/libc.so.6:
-version `GLIBC\_2.14' not found (required by ./gitea)```. This is due to the integrated
+Gitea binary, usually producing an error such as `./gitea: /lib/x86_64-linux-gnu/libc.so.6:
+version 'GLIBC\_2.14' not found (required by ./gitea)`. This is due to the integrated
SQLite support in the binaries provided by dl.gitea.io. In this situation, it is usually
-possible to [install from source]({{< relref "from-source.en-us.md" >}}) without SQLite
-support.
+possible to [install from source]({{< relref "from-source.en-us.md" >}}), without including
+SQLite support.
### Running Gitea on another port
For errors like `702 runWeb()] [E] Failed to start server: listen tcp 0.0.0.0:3000:
-bind: address already in use` Gitea needs to be started on another free port. This
+bind: address already in use`, Gitea needs to be started on another free port. This
is possible using `./gitea web -p $PORT`. It's possible another instance of Gitea
is already running.
### Running Gitea on Raspbian
-As of v1.8, there is a problem with the arm7 version of Gitea and it doesn't run on Raspberry Pi and similar devices.
+As of v1.8, there is a problem with the arm7 version of Gitea, and it doesn't run on Raspberry Pis and similar devices.
-It is therefore recommended to switch to the arm6 version which has been tested and shown to work on Raspberry Pi and similar devices.
+It is recommended to switch to the arm6 version, which has been tested and shown to work on Raspberry Pis and similar devices.
### Git error after updating to a new version of Gitea
-If the binary file name has been changed during the update to a new version of Gitea,
+If during the update, the binary file name has been changed to a new version of Gitea,
Git Hooks in existing repositories will not work any more. In that case, a Git
error will be displayed when pushing to the repository.
@@ -181,9 +208,9 @@ binary.
To solve this, go to the admin options and run the task `Resynchronize pre-receive,
update and post-receive hooks of all repositories` to update all hooks to contain
-the new binary path. Please note that this overwrite all Git Hooks including ones
+the new binary path. Please note that this overwrites all Git Hooks, including ones
with customizations made.
-If you aren't using the built-in to Gitea SSH server you will also need to re-write
+If you aren't using the Gitea built-in SSH server, you will also need to re-write
the authorized key file by running the `Update the '.ssh/authorized_keys' file with
Gitea SSH keys.` task in the admin options.
diff --git a/docs/content/doc/installation/from-package.en-us.md b/docs/content/doc/installation/from-package.en-us.md
index e4081024bd0e7..3f75f26a53d0a 100644
--- a/docs/content/doc/installation/from-package.en-us.md
+++ b/docs/content/doc/installation/from-package.en-us.md
@@ -47,13 +47,13 @@ pacman -S gitea
There is a [Gitea Snap](https://snapcraft.io/gitea) package which follows the latest stable version.
-``sh
+```sh
snap install gitea
-``
+```
## SUSE and openSUSE
-OpenSUSE build service provides packages for [openSUSE and SLE](https://software.opensuse.org/download/package?package=gitea&project=devel%3Atools%3Ascm)
+OpenSUSE build service provides packages for [openSUSE and SLE](https://software.opensuse.org/download/package?package=gitea&project=devel%3Atools%3Ascm)
in the Development Software Configuration Management Repository
## Windows
diff --git a/docs/content/doc/installation/from-source.en-us.md b/docs/content/doc/installation/from-source.en-us.md
index 54e79769ea143..660f996b1e707 100644
--- a/docs/content/doc/installation/from-source.en-us.md
+++ b/docs/content/doc/installation/from-source.en-us.md
@@ -101,7 +101,7 @@ Depending on requirements, the following build tags can be included.
- `pam`: Enable support for PAM (Linux Pluggable Authentication Modules). Can
be used to authenticate local users or extend authentication to methods
available to PAM.
-* `gogit`: (EXPERIMENTAL) Use go-git variants of Git commands.
+- `gogit`: (EXPERIMENTAL) Use go-git variants of Git commands.
Bundling assets into the binary using the `bindata` build tag is recommended for
production deployments. It is possible to serve the static assets directly via a reverse proxy,
diff --git a/docs/content/doc/installation/from-source.fr-fr.md b/docs/content/doc/installation/from-source.fr-fr.md
index 4afbd137731ef..00f67eab55f2f 100644
--- a/docs/content/doc/installation/from-source.fr-fr.md
+++ b/docs/content/doc/installation/from-source.fr-fr.md
@@ -30,7 +30,6 @@ cd $GOPATH/src/code.gitea.io/gitea
Maintenant, il est temps de décider quelle version de Gitea vous souhaitez compiler et installer. Actuellement, ils existent plusieurs options possibles. Si vous voulez compiler notre branche `master`, vous pouvez directement passer à la [section compilation](#compilation), cette branche représente la dernière version en cours de développement et n'a pas vocation à être utiliser en production.
-
Si vous souhaitez compiler la dernière version stable, utilisez les étiquettes ou les différentes branches disponibles. Vous pouvez voir les branches disponibles et comment utiliser cette branche avec ces commandes:
```
diff --git a/docs/content/doc/installation/from-source.zh-cn.md b/docs/content/doc/installation/from-source.zh-cn.md
index 7d08033603d65..275b0c2f74799 100644
--- a/docs/content/doc/installation/from-source.zh-cn.md
+++ b/docs/content/doc/installation/from-source.zh-cn.md
@@ -26,7 +26,7 @@ go get -d -u code.gitea.io/gitea
cd $GOPATH/src/code.gitea.io/gitea
```
-然后你可以选择编译和安装的版本,当前你有多个选择。如果你想编译 `master` 版本,你可以直接跳到 [编译](#build) 部分,这是我们的开发分支,虽然也很稳定但不建议您在正式产品中使用。
+然后你可以选择编译和安装的版本,当前你有多个选择。如果你想编译 `master` 版本,你可以直接跳到 [编译](#编译) 部分,这是我们的开发分支,虽然也很稳定但不建议您在正式产品中使用。
如果你想编译最新稳定分支,你可以执行以下命令签出源码:
@@ -55,9 +55,9 @@ git checkout v{{< version >}}
按照您的编译需求,以下 tags 可以使用:
-* `bindata`: 这个编译选项将会把运行Gitea所需的所有外部资源都打包到可执行文件中,这样部署将非常简单因为除了可执行程序将不再需要任何其他文件。
-* `sqlite sqlite_unlock_notify`: 这个编译选项将启用SQLite3数据库的支持,建议只在少数人使用时使用这个模式。
-* `pam`: 这个编译选项将会启用 PAM (Linux Pluggable Authentication Modules) 认证,如果你使用这一认证模式的话需要开启这个选项。
+- `bindata`: 这个编译选项将会把运行Gitea所需的所有外部资源都打包到可执行文件中,这样部署将非常简单因为除了可执行程序将不再需要任何其他文件。
+- `sqlite sqlite_unlock_notify`: 这个编译选项将启用SQLite3数据库的支持,建议只在少数人使用时使用这个模式。
+- `pam`: 这个编译选项将会启用 PAM (Linux Pluggable Authentication Modules) 认证,如果你使用这一认证模式的话需要开启这个选项。
使用 bindata 可以打包资源文件到二进制可以使开发和测试更容易,你可以根据自己的需求决定是否打包资源文件。
要包含资源文件,请使用 `bindata` tag:
diff --git a/docs/content/doc/installation/from-source.zh-tw.md b/docs/content/doc/installation/from-source.zh-tw.md
index 39c9878309452..2b65d554ab7f0 100644
--- a/docs/content/doc/installation/from-source.zh-tw.md
+++ b/docs/content/doc/installation/from-source.zh-tw.md
@@ -26,7 +26,7 @@ go get -d -u code.gitea.io/gitea
cd $GOPATH/src/code.gitea.io/gitea
```
-現在該決定您要編譯或安裝的 Gitea 版本,您有很多可以選擇。如果您想編譯 `master` 版本,你可以直接跳到[編譯章節](#build),這是我們開發分支,雖然很穩定,但是不建議用在正式環境。
+現在該決定您要編譯或安裝的 Gitea 版本,您有很多可以選擇。如果您想編譯 `master` 版本,你可以直接跳到[編譯章節](#編譯),這是我們開發分支,雖然很穩定,但是不建議用在正式環境。
假如您想要編譯最新穩定版本,可以執行底下命令切換到正確版本:
diff --git a/docs/content/doc/installation/on-kubernetes.zh-tw.md b/docs/content/doc/installation/on-kubernetes.zh-tw.md
index 5ea412aa000d3..345ff7ac2c300 100644
--- a/docs/content/doc/installation/on-kubernetes.zh-tw.md
+++ b/docs/content/doc/installation/on-kubernetes.zh-tw.md
@@ -26,7 +26,7 @@ helm install gitea gitea-charts/gitea
若您想自訂安裝(包括使用 kubernetes ingress),請前往完整的 [Gitea helm chart configuration details](https://gitea.com/gitea/helm-chart/)
-##運行狀況檢查終端節點
+## 運行狀況檢查終端節點
Gitea 附帶了一個運行狀況檢查端點 `/api/healthz`,你可以像這樣在 kubernetes 中配置它:
diff --git a/docs/content/doc/installation/run-as-service-in-ubuntu.en-us.md b/docs/content/doc/installation/run-as-service-in-ubuntu.en-us.md
index 471377e9fcf64..9f65eaca9f9a8 100644
--- a/docs/content/doc/installation/run-as-service-in-ubuntu.en-us.md
+++ b/docs/content/doc/installation/run-as-service-in-ubuntu.en-us.md
@@ -27,12 +27,14 @@ Change the user, home directory, and other required startup values. Change the
PORT or remove the -p flag if default port is used.
Enable and start Gitea at boot:
+
```
sudo systemctl enable gitea
sudo systemctl start gitea
```
If you have systemd version 220 or later, you can enable and immediately start Gitea at once by:
+
```
sudo systemctl enable gitea --now
```
@@ -40,11 +42,13 @@ sudo systemctl enable gitea --now
#### Using supervisor
Install supervisor by running below command in terminal:
+
```
sudo apt install supervisor
```
Create a log dir for the supervisor logs:
+
```
# assuming Gitea is installed in /home/git/gitea/
mkdir /home/git/gitea/log/supervisor
@@ -58,12 +62,14 @@ Using your favorite editor, change the user (`git`) and home
or remove the -p flag if default port is used.
Lastly enable and start supervisor at boot:
+
```
sudo systemctl enable supervisor
sudo systemctl start supervisor
```
If you have systemd version 220 or later, you can enable and immediately start supervisor by:
+
```
sudo systemctl enable supervisor --now
```
diff --git a/docs/content/doc/installation/run-as-service-in-ubuntu.zh-cn.md b/docs/content/doc/installation/run-as-service-in-ubuntu.zh-cn.md
index 02cd032b67738..c76350ecdcfb4 100644
--- a/docs/content/doc/installation/run-as-service-in-ubuntu.zh-cn.md
+++ b/docs/content/doc/installation/run-as-service-in-ubuntu.zh-cn.md
@@ -18,6 +18,7 @@ menu:
#### systemd 方式
在 terminal 中执行以下命令:
+
```
sudo vim /etc/systemd/system/gitea.service
```
@@ -27,26 +28,29 @@ sudo vim /etc/systemd/system/gitea.service
修改 user,home 目录以及其他必须的初始化参数,如果使用自定义端口,则需修改 PORT 参数,反之如果使用默认端口则需删除 -p 标记。
激活 gitea 并将它作为系统自启动服务:
+
```
sudo systemctl enable gitea
sudo systemctl start gitea
```
-
#### 使用 supervisor
在 terminal 中执行以下命令安装 supervisor:
+
```
sudo apt install supervisor
```
为 supervisor 配置日志路径:
+
```
# assuming gitea is installed in /home/git/gitea/
mkdir /home/git/gitea/log/supervisor
```
在文件编辑器中打开 supervisor 的配置文件:
+
```
sudo vim /etc/supervisor/supervisord.conf
```
@@ -57,6 +61,7 @@ sudo vim /etc/supervisor/supervisord.conf
将 user(git) 和 home(/home/git) 设置为与上文部署中匹配的值。如果使用自定义端口,则需修改 PORT 参数,反之如果使用默认端口则需删除 -p 标记。
最后激活 supervisor 并将它作为系统自启动服务:
+
```
sudo systemctl enable supervisor
sudo systemctl start supervisor
diff --git a/docs/content/doc/installation/with-docker-rootless.en-us.md b/docs/content/doc/installation/with-docker-rootless.en-us.md
index 634e08a72ec42..3cae65c2b2fc2 100644
--- a/docs/content/doc/installation/with-docker-rootless.en-us.md
+++ b/docs/content/doc/installation/with-docker-rootless.en-us.md
@@ -247,6 +247,7 @@ files; for named volumes, this is done through another container or by direct ac
:exclamation::exclamation: **Make sure you have volumed data to somewhere outside Docker container** :exclamation::exclamation:
To upgrade your installation to the latest release:
+
```
# Edit `docker-compose.yml` to update the version, if you have one specified
# Pull new images
diff --git a/docs/content/doc/installation/with-docker.en-us.md b/docs/content/doc/installation/with-docker.en-us.md
index c2e7a817c932a..895f04804e2bc 100644
--- a/docs/content/doc/installation/with-docker.en-us.md
+++ b/docs/content/doc/installation/with-docker.en-us.md
@@ -255,7 +255,7 @@ favorite browser to finalize the installation. Visit http://server-ip:3000 and f
installation wizard. If the database was started with the `docker-compose` setup as
documented above, please note that `db` must be used as the database hostname.
-## Configure the user inside Gitea using environment variables
+## Configure the user inside Gitea using environment variables
- `USER`: **git**: The username of the user that runs Gitea within the container.
- `USER_UID`: **1000**: The UID (Unix user ID) of the user that runs Gitea within the container. Match this to the UID of the owner of the `/data` volume if using host volumes (this is not necessary with named volumes).
@@ -303,12 +303,30 @@ services:
- GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}"""
```
-To set required TOKEN and SECRET values, consider using Gitea's built-in [generate utility functions](https://docs.gitea.io/en-us/command-line/#generate).
+Gitea will generate new secrets/tokens for every new installation automatically and write them into the app.ini. If you want to set the secrets/tokens manually, you can use the following docker commands to use of Gitea's built-in [generate utility functions](https://docs.gitea.io/en-us/command-line/#generate). Do not lose/change your SECRET_KEY after the installation, otherwise the encrypted data can not be decrypted anymore.
+
+The following commands will output a new `SECRET_KEY` and `INTERNAL_TOKEN` to `stdout`, which you can then place in your environment variables.
+
+```bash
+docker run -it --rm gitea/gitea:1 gitea generate secret SECRET_KEY
+docker run -it --rm gitea/gitea:1 gitea generate secret INTERNAL_TOKEN
+```
+
+```yaml
+...
+services:
+ server:
+ environment:
+ - GITEA__security__SECRET_KEY=[value returned by generate secret SECRET_KEY]
+ - GITEA__security__INTERNAL_TOKEN=[value returned by generate secret INTERNAL_TOKEN]
+```
## SSH Container Passthrough
Since SSH is running inside the container, SSH needs to be passed through from the host to the container if SSH support is desired. One option would be to run the container SSH on a non-standard port (or moving the host port to a non-standard port). Another option which might be more straightforward is for Gitea users to ssh to a Gitea user on the host which will then relay those connections to the docker.
+### Understanding SSH access to Gitea (without passthrough)
+
To understand what needs to happen, you first need to understand what happens without passthrough. So we will try to explain this:
1. The client adds their SSH public key to Gitea using the webpage.
@@ -392,9 +410,9 @@ In this option, the idea is that the host simply uses the `authorized_keys` that
Here is a detailed explanation what is happening when a SSH request is made:
1. The client adds their SSH public key to Gitea using the webpage.
-2. Gitea in the container will add an entry for this key to the `.ssh/authorized_keys` file of its running user, `git`.
+2. Gitea in the container will add an entry for this key to the `.ssh/authorized_keys` file of its running user, `git`.
- However, because `/home/git/.ssh/` on the host is mounted as `/data/git/.ssh` this means that the key has been added to the host `git` user's `authorized_keys` file too.
-3. This entry has the public key, but also has a `command=` option.
+3. This entry has the public key, but also has a `command=` option.
- This command matches the location of the Gitea binary on the container, but also the location of the shim on the host.
4. The client then makes an SSH request to the host SSH server using the `git` user, e.g. `git clone git@domain:user/repo.git`.
5. The client will attempt to authenticate with the server, passing one or more public keys in turn to the host.
@@ -439,7 +457,7 @@ we create a new shell for the git user. As an administrative user on the host ru
Here is a detailed explanation what is happening when a SSH request is made:
1. The client adds their SSH public key to Gitea using the webpage.
-2. Gitea in the container will add an entry for this key to the `.ssh/authorized_keys` file of its running user, `git`.
+2. Gitea in the container will add an entry for this key to the `.ssh/authorized_keys` file of its running user, `git`.
- However, because `/home/git/.ssh/` on the host is mounted as `/data/git/.ssh` this means that the key has been added to the host `git` user's `authorized_keys` file too.
3. This entry has the public key, but also has a `command=` option.
- This command matches the location of the Gitea binary on the container.
@@ -480,7 +498,7 @@ sudo usermod -s /home/git/docker-shell git
Here is a detailed explanation what is happening when a SSH request is made:
1. The client adds their SSH public key to Gitea using the webpage.
-2. Gitea in the container will add an entry for this key to the `.ssh/authorized_keys` file of its running user, `git`.
+2. Gitea in the container will add an entry for this key to the `.ssh/authorized_keys` file of its running user, `git`.
- However, because `/home/git/.ssh/` on the host is mounted as `/data/git/.ssh` this means that the key has been added to the host `git` user's `authorized_keys` file too.
3. This entry has the public key, but also has a `command=` option.
- This command matches the location of the Gitea binary on the container.
@@ -529,7 +547,7 @@ In this option, the idea is that the host SSH uses an `AuthorizedKeysCommand` in
Now all attempts to login as the `git` user on the host will be forwarded to the docker - including the `SSH_ORIGINAL_COMMAND`. We now need to set-up SSH authentication on the host.
-We will do this by leveraging the [SSH AuthorizedKeysCommand](https://docs.gitea.io/en-us/command-line/#keys) to match the keys against those accepted by Gitea.
+We will do this by leveraging the [SSH AuthorizedKeysCommand](https://docs.gitea.io/en-us/command-line/#keys) to match the keys against those accepted by Gitea.
Add the following block to `/etc/ssh/sshd_config`, on the host:
diff --git a/docs/content/doc/installation/with-docker.zh-cn.md b/docs/content/doc/installation/with-docker.zh-cn.md
index 9122ee84264f7..91892fdaf95c0 100644
--- a/docs/content/doc/installation/with-docker.zh-cn.md
+++ b/docs/content/doc/installation/with-docker.zh-cn.md
@@ -301,7 +301,7 @@ volumes:
sudo -u git ssh-keygen -t rsa -b 4096 -C "Gitea Host Key"
```
-在下一步中,需要在主机上创建一个名为 `/user/local/bin/gitea` 的文件(具有可执行权限)。该文件将发出从主机到容器的 SSH 转发。将以下内容添加到 `/user/local/bin/gitea`:
+在下一步中,需要在主机上创建一个名为 `/usr/local/bin/gitea` 的文件(具有可执行权限)。该文件将发出从主机到容器的 SSH 转发。将以下内容添加到 `/usr/local/bin/gitea`:
```bash
ssh -p 2222 -o StrictHostKeyChecking=no git@127.0.0.1 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@"
@@ -324,14 +324,14 @@ ports:
ssh-rsa
# other keys from users
-command="/user/local/bin/gitea --config=/data/gitea/conf/app.ini serv key-1",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
+command="/usr/local/bin/gitea --config=/data/gitea/conf/app.ini serv key-1",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
```
这是详细的说明,当发出 SSH 请求时会发生什么:
1. 使用 `git` 用户向主机发出 SSH 请求,例如 `git clone git@domain:user/repo.git`。
-2. 在 `/home/git/.ssh/authorized_keys` 中,该命令执行 `/user/local/bin/gitea` 脚本。
-3. `/user/local/bin/gitea` 将 SSH 请求转发到端口 2222,该端口已映射到容器的 SSH 端口(22)。
+2. 在 `/home/git/.ssh/authorized_keys` 中,该命令执行 `/usr/local/bin/gitea` 脚本。
+3. `/usr/local/bin/gitea` 将 SSH 请求转发到端口 2222,该端口已映射到容器的 SSH 端口(22)。
4. 由于 `/home/git/.ssh/authorized_keys` 中存在 `git` 用户的公钥,因此身份验证主机 → 容器成功,并且 SSH 请求转发到在 docker 容器中运行的 Gitea。
如果在 Gitea Web 界面中添加了新的 SSH 密钥,它将以与现有密钥相同的方式附加到 `.ssh/authorized_keys` 中。
diff --git a/docs/content/doc/packages/composer.en-us.md b/docs/content/doc/packages/composer.en-us.md
index 2502ee45b509b..47b03781f06e5 100644
--- a/docs/content/doc/packages/composer.en-us.md
+++ b/docs/content/doc/packages/composer.en-us.md
@@ -60,6 +60,8 @@ curl --user your_username:your_password_or_token \
https://gitea.example.com/api/packages/testuser/composer?version=1.0.3
```
+If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}) instead of the password.
+
The server responds with the following HTTP Status codes.
| HTTP Status Code | Meaning |
diff --git a/docs/content/doc/packages/conan.en-us.md b/docs/content/doc/packages/conan.en-us.md
index c650e9d7ea491..fb104f34f43b2 100644
--- a/docs/content/doc/packages/conan.en-us.md
+++ b/docs/content/doc/packages/conan.en-us.md
@@ -37,7 +37,7 @@ conan user --remote {remote} --password {password} {username}
| -----------| ----------- |
| `remote` | The remote name. |
| `username` | Your Gitea username. |
-| `password` | Your Gitea password or a personal access token. |
+| `password` | Your Gitea password. If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}) instead of the password. |
| `owner` | The owner of the package. |
For example:
diff --git a/docs/content/doc/packages/container.en-us.md b/docs/content/doc/packages/container.en-us.md
index 28559eb22b8d5..77dbbafd02cb5 100644
--- a/docs/content/doc/packages/container.en-us.md
+++ b/docs/content/doc/packages/container.en-us.md
@@ -34,6 +34,8 @@ To push an image or if the image is in a private registry, you have to authentic
docker login gitea.example.com
```
+If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}) instead of the password.
+
## Image naming convention
Images must follow this naming convention:
diff --git a/docs/content/doc/packages/generic.en-us.md b/docs/content/doc/packages/generic.en-us.md
index afef323938d4f..a82058da8ac5c 100644
--- a/docs/content/doc/packages/generic.en-us.md
+++ b/docs/content/doc/packages/generic.en-us.md
@@ -37,7 +37,7 @@ PUT https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{packa
| ----------------- | ----------- |
| `owner` | The owner of the package. |
| `package_name` | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`). |
-| `package_version` | The package version as described in the [SemVer](https://semver.org/) spec. |
+| `package_version` | The package version, a non-empty string. |
| `file_name` | The filename. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`). |
Example request using HTTP Basic authentication:
@@ -48,6 +48,8 @@ curl --user your_username:your_password_or_token \
https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0/file.bin
```
+If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}) instead of the password.
+
The server reponds with the following HTTP Status codes.
| HTTP Status Code | Meaning |
diff --git a/docs/content/doc/packages/helm.en-us.md b/docs/content/doc/packages/helm.en-us.md
index 9c43b08bf4298..89b929f9bc848 100644
--- a/docs/content/doc/packages/helm.en-us.md
+++ b/docs/content/doc/packages/helm.en-us.md
@@ -42,7 +42,7 @@ helm cm-push ./{chart_file}.tgz {repo}
| Parameter | Description |
| ------------ | ----------- |
| `username` | Your Gitea username. |
-| `password` | Your Gitea password or a personal access token. |
+| `password` | Your Gitea password. If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}) instead of the password. |
| `repo` | The name for the repository. |
| `chart_file` | The Helm Chart archive. |
| `owner` | The owner of the package. |
diff --git a/docs/content/doc/packages/maven.en-us.md b/docs/content/doc/packages/maven.en-us.md
index 837c8434ae4d5..22da3c16d2945 100644
--- a/docs/content/doc/packages/maven.en-us.md
+++ b/docs/content/doc/packages/maven.en-us.md
@@ -81,6 +81,16 @@ To publish a package simply run:
mvn deploy
```
+If you want to publish a prebuild package to the registry, you can use [`mvn deploy:deploy-file`](https://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html):
+
+```shell
+mvn deploy:deploy-file -Durl=https://gitea.example.com/api/packages/{owner}/maven -DrepositoryId=gitea -Dfile=/path/to/package.jar
+```
+
+| Parameter | Description |
+| -------------- | ----------- |
+| `owner` | The owner of the package. |
+
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
## Install a package
@@ -107,4 +117,4 @@ mvn install
mvn install
mvn deploy
mvn dependency:get:
-```
\ No newline at end of file
+```
diff --git a/docs/content/doc/packages/nuget.en-us.md b/docs/content/doc/packages/nuget.en-us.md
index 421faf9ee6503..a4435fa99f01a 100644
--- a/docs/content/doc/packages/nuget.en-us.md
+++ b/docs/content/doc/packages/nuget.en-us.md
@@ -38,7 +38,7 @@ dotnet nuget add source --name {source_name} --username {username} --password {p
| ------------- | ----------- |
| `source_name` | The desired source name. |
| `username` | Your Gitea username. |
-| `password` | Your Gitea password or a personal access token. |
+| `password` | Your Gitea password. If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}) instead of the password. |
| `owner` | The owner of the package. |
For example:
diff --git a/docs/content/doc/packages/overview.en-us.md b/docs/content/doc/packages/overview.en-us.md
index 81575b9ade7c7..5e03b710170f1 100644
--- a/docs/content/doc/packages/overview.en-us.md
+++ b/docs/content/doc/packages/overview.en-us.md
@@ -34,6 +34,7 @@ The following package managers are currently supported:
| [Maven]({{< relref "doc/packages/maven.en-us.md" >}}) | Java | `mvn`, `gradle` |
| [npm]({{< relref "doc/packages/npm.en-us.md" >}}) | JavaScript | `npm`, `yarn` |
| [NuGet]({{< relref "doc/packages/nuget.en-us.md" >}}) | .NET | `nuget` |
+| [Pub]({{< relref "doc/packages/pub.en-us.md" >}}) | Dart | `dart`, `flutter` |
| [PyPI]({{< relref "doc/packages/pypi.en-us.md" >}}) | Python | `pip`, `twine` |
| [RubyGems]({{< relref "doc/packages/rubygems.en-us.md" >}}) | Ruby | `gem`, `Bundler` |
diff --git a/docs/content/doc/packages/pub.en-us.md b/docs/content/doc/packages/pub.en-us.md
new file mode 100644
index 0000000000000..4d37662208332
--- /dev/null
+++ b/docs/content/doc/packages/pub.en-us.md
@@ -0,0 +1,83 @@
+---
+date: "2022-07-31T00:00:00+00:00"
+title: "Pub Packages Repository"
+slug: "packages/pub"
+draft: false
+toc: false
+menu:
+ sidebar:
+ parent: "packages"
+ name: "Pub"
+ weight: 90
+ identifier: "pub"
+---
+
+# Pub Packages Repository
+
+Publish [Pub](https://dart.dev/guides/packages) packages for your user or organization.
+
+**Table of Contents**
+
+{{< toc >}}
+
+## Requirements
+
+To work with the Pub package registry, you need to use the tools [dart](https://dart.dev/tools/dart-tool) and/or [flutter](https://docs.flutter.dev/reference/flutter-cli).
+
+The following examples use dart.
+
+## Configuring the package registry
+
+To register the package registry and provide credentials, execute:
+
+```shell
+dart pub token add https://gitea.example.com/api/packages/{owner}/pub
+```
+
+| Placeholder | Description |
+| ------------ | ----------- |
+| `owner` | The owner of the package. |
+
+You need to provide your [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}).
+
+## Publish a package
+
+To publish a package, edit the `pubspec.yaml` and add the following line:
+
+```yaml
+publish_to: https://gitea.example.com/api/packages/{owner}/pub
+```
+
+| Placeholder | Description |
+| ------------ | ----------- |
+| `owner` | The owner of the package. |
+
+Now you can publish the package by running the following command:
+
+```shell
+dart pub publish
+```
+
+You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
+
+## Install a package
+
+To install a Pub package from the package registry, execute the following command:
+
+```shell
+dart pub add {package_name} --hosted-url=https://gitea.example.com/api/packages/{owner}/pub/
+```
+
+| Parameter | Description |
+| ----------------- | ----------- |
+| `owner` | The owner of the package. |
+| `package_name` | The package name. |
+
+For example:
+
+```shell
+# use latest version
+dart pub add mypackage --hosted-url=https://gitea.example.com/api/packages/testuser/pub/
+# specify version
+dart pub add mypackage:1.0.8 --hosted-url=https://gitea.example.com/api/packages/testuser/pub/
+```
diff --git a/docs/content/doc/packages/pypi.en-us.md b/docs/content/doc/packages/pypi.en-us.md
index d9f4872dca4c8..588df71d60c27 100644
--- a/docs/content/doc/packages/pypi.en-us.md
+++ b/docs/content/doc/packages/pypi.en-us.md
@@ -8,7 +8,7 @@ menu:
sidebar:
parent: "packages"
name: "PyPI"
- weight: 90
+ weight: 100
identifier: "pypi"
---
@@ -42,7 +42,7 @@ password = {password}
| ------------ | ----------- |
| `owner` | The owner of the package. |
| `username` | Your Gitea username. |
-| `password` | Your Gitea password or a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}). |
+| `password` | Your Gitea password. If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}) instead of the password. |
## Publish a package
@@ -82,4 +82,4 @@ pip install --index-url https://testuser:password123@gitea.example.com/api/packa
```
pip install
twine upload
-```
\ No newline at end of file
+```
diff --git a/docs/content/doc/packages/rubygems.en-us.md b/docs/content/doc/packages/rubygems.en-us.md
index 9d9ce09b1c6da..d4ae30bbcecc1 100644
--- a/docs/content/doc/packages/rubygems.en-us.md
+++ b/docs/content/doc/packages/rubygems.en-us.md
@@ -8,7 +8,7 @@ menu:
sidebar:
parent: "packages"
name: "RubyGems"
- weight: 100
+ weight: 110
identifier: "rubygems"
---
@@ -36,7 +36,7 @@ https://gitea.example.com/api/packages/{owner}/rubygems: Bearer {token}
| Parameter | Description |
| ------------- | ----------- |
| `owner` | The owner of the package. |
-| `token` | Your personal access token. |
+| `token` | Your [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}). |
For example:
@@ -124,4 +124,4 @@ gem install --host https://gitea.example.com/api/packages/testuser/rubygems test
gem install
bundle install
gem push
-```
\ No newline at end of file
+```
diff --git a/docs/content/doc/translation/guidelines.de-de.md b/docs/content/doc/translation/guidelines.de-de.md
index 9f4b84ca9b3ed..eee031a54ed11 100644
--- a/docs/content/doc/translation/guidelines.de-de.md
+++ b/docs/content/doc/translation/guidelines.de-de.md
@@ -15,10 +15,12 @@ menu:
## Allgemeines
Anrede: Wenig förmlich:
+
* "Du"-Form
* Keine "Amtsdeusch"-Umschreibungen, einfach so als ob man den Nutzer direkt persönlich ansprechen würde
Genauer definiert:
+
* "falsch" anstatt "nicht korrekt/inkorrekt"
* Benutzerkonto oder Konto? Oder Account?
* "Wende dich an ..." anstatt "kontaktiere ..."
diff --git a/docs/content/doc/upgrade/from-gitea.en-us.md b/docs/content/doc/upgrade/from-gitea.en-us.md
index 2f64e0fac6bf6..0d22a32439c85 100644
--- a/docs/content/doc/upgrade/from-gitea.en-us.md
+++ b/docs/content/doc/upgrade/from-gitea.en-us.md
@@ -20,14 +20,20 @@ menu:
{{< toc >}}
To update Gitea, download a newer version, stop the old one, perform a backup, and run the new one.
-Every time a Gitea instance starts up, it checks whether a database migration should be run.
+Every time a Gitea instance starts up, it checks whether a database migration should be run.
If a database migration is required, Gitea will take some time to complete the upgrade and then serve.
+## Check the Changelog for breaking changes
+
+To make Gitea better, some breaking changes are unavoidable, especially for big milestone releases.
+Before upgrade, please read the [Changelog on Gitea blog](https://blog.gitea.io/)
+and check whether the breaking changes affect your Gitea instance.
+
## Backup for downgrade
-Gitea keeps compatibility for patch versions whose first two fields are the same (`a.b.x` -> `a.b.y`),
-these patch versions can be upgraded and downgraded with the same database structure.
-Otherwise (`a.b.?` -> `a.c.?`), a newer Gitea version will upgrade the old database
+Gitea keeps compatibility for patch versions whose first two fields are the same (`a.b.x` -> `a.b.y`),
+these patch versions can be upgraded and downgraded with the same database structure.
+Otherwise (`a.b.?` -> `a.c.?`), a newer Gitea version will upgrade the old database
to a new structure that may differ from the old version.
For example:
@@ -39,8 +45,8 @@ For example:
| 1.4.x | 1.5.y | ✅ Database gets upgraded. You can upgrade from 1.4.x to the latest 1.5.y directly. |
| 1.5.y | 1.4.x | ❌ Database already got upgraded and can not be used for an old Gitea, use a backup to downgrade. |
-**Since you can not run an old Gitea with an upgraded database,
-a backup should always be made before a database upgrade.**
+**Since you can not run an old Gitea with an upgraded database,
+a backup should always be made before a database upgrade.**
If you use Gitea in production, it's always highly recommended to make a backup before upgrade,
even if the upgrade is between patch versions.
@@ -56,7 +62,6 @@ Backup steps:
If you are using cloud services or filesystems with snapshot feature,
a snapshot for the Gitea data volume and related object storage is more convenient.
-
## Upgrade with Docker
* `docker pull` the latest Gitea release.
@@ -73,16 +78,16 @@ a snapshot for the Gitea data volume and related object storage is more convenie
* Download the latest Gitea binary to a temporary directory.
* Stop the running instance, backup data.
-* Replace the installed Gitea binary with the downloaded one.
+* Replace the installed Gitea binary with the downloaded one.
* Start the Gitea instance.
A script automating these steps for a deployment on Linux can be found at [`contrib/upgrade.sh` in Gitea's source tree](https://github.com/go-gitea/gitea/blob/main/contrib/upgrade.sh).
## Take care about customized templates
-Gitea's template structure and variables may change between releases, if you are using customized templates,
-do pay attention if your templates are compatible with the Gitea you are using.
+Gitea's template structure and variables may change between releases, if you are using customized templates,
+do pay attention if your templates are compatible with the Gitea you are using.
-If the customized templates don't match Gitea version, you may experience:
-`50x` server error, page components missing or malfunctioning, strange page layout, ...
+If the customized templates don't match Gitea version, you may experience:
+`50x` server error, page components missing or malfunctioning, strange page layout, ...
Remove or update the incompatible templates and Gitea web will work again.
diff --git a/docs/content/doc/usage/backup-and-restore.en-us.md b/docs/content/doc/usage/backup-and-restore.en-us.md
index 95e6d376d09d2..c9c41c413c771 100644
--- a/docs/content/doc/usage/backup-and-restore.en-us.md
+++ b/docs/content/doc/usage/backup-and-restore.en-us.md
@@ -74,7 +74,7 @@ The command has to be executed with the `RUN_USER = ` specified in
Example:
```none
-docker exec -u -it -w <--tempdir> $(docker ps -qf 'name=^$') bash -c '/user/local/bin/gitea dump -c '
+docker exec -u -it -w <--tempdir> $(docker ps -qf 'name=^$') bash -c '/usr/local/bin/gitea dump -c '
```
\*Note: `--tempdir` refers to the temporary directory of the docker environment used by Gitea; if you have not specified a custom `--tempdir`, then Gitea uses `/tmp` or the `TMPDIR` environment variable of the docker container. For `--tempdir` adjust your `docker exec` command options accordingly.
diff --git a/docs/content/doc/usage/backup-and-restore.zh-tw.md b/docs/content/doc/usage/backup-and-restore.zh-tw.md
index 152d0a19b730c..18e244b19c69d 100644
--- a/docs/content/doc/usage/backup-and-restore.zh-tw.md
+++ b/docs/content/doc/usage/backup-and-restore.zh-tw.md
@@ -45,6 +45,7 @@ Gitea 目前支援 `dump` 指令,用來將資料備份成 zip 檔案,後續
持續更新中: 此文件尚未完成.
例:
+
```sh
unzip gitea-dump-1610949662.zip
cd gitea-dump-1610949662
diff --git a/docs/content/doc/usage/command-line.en-us.md b/docs/content/doc/usage/command-line.en-us.md
index 8cc420ed11b1f..5f05bc4c3be3e 100644
--- a/docs/content/doc/usage/command-line.en-us.md
+++ b/docs/content/doc/usage/command-line.en-us.md
@@ -364,7 +364,7 @@ NB: Gitea must be running for this command to succeed.
### migrate
-Migrates the database. This command can be used to run other commands before starting the server for the first time.
+Migrates the database. This command can be used to run other commands before starting the server for the first time.
This command is idempotent.
### convert
@@ -522,7 +522,7 @@ Dump-repo dumps repository data from Git/GitHub/Gitea/GitLab:
- Options:
- `--git_service service` : Git service, it could be `git`, `github`, `gitea`, `gitlab`, If clone_addr could be recognized, this could be ignored.
- - `--repo_dir dir`, `-r dir`: Repository dir path to store the data
+ - `--repo_dir dir`, `-r dir`: Repository dir path to store the data
- `--clone_addr addr`: The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL. i.e. https://github.com/lunny/tango.git
- `--auth_username lunny`: The username to visit the clone_addr
- `--auth_password `: The password to visit the clone_addr
diff --git a/docs/content/doc/usage/email-setup.en-us.md b/docs/content/doc/usage/email-setup.en-us.md
index df1b8545af5dc..533e0fe1a8f9c 100644
--- a/docs/content/doc/usage/email-setup.en-us.md
+++ b/docs/content/doc/usage/email-setup.en-us.md
@@ -60,9 +60,10 @@ To send a test email to validate the settings, go to Gitea > Site Administration
For the full list of options check the [Config Cheat Sheet]({{< relref "doc/advanced/config-cheat-sheet.en-us.md" >}})
Please note: authentication is only supported when the SMTP server communication is encrypted with TLS or `HOST=localhost`. TLS encryption can be through:
- - STARTTLS (also known as Opportunistic TLS) via port 587. Initial connection is done over cleartext, but then be upgraded over TLS if the server supports it.
- - SMTPS connection (SMTP over TLS) via the default port 465. Connection to the server use TLS from the beginning.
- - Forced SMTPS connection with `IS_TLS_ENABLED=true`. (These are both known as Implicit TLS.)
+
+- STARTTLS (also known as Opportunistic TLS) via port 587. Initial connection is done over cleartext, but then be upgraded over TLS if the server supports it.
+- SMTPS connection (SMTP over TLS) via the default port 465. Connection to the server use TLS from the beginning.
+- Forced SMTPS connection with `IS_TLS_ENABLED=true`. (These are both known as Implicit TLS.)
This is due to protections imposed by the Go internal libraries against STRIPTLS attacks.
Note that Implicit TLS is recommended by [RFC8314](https://tools.ietf.org/html/rfc8314#section-3) since 2018.
@@ -82,4 +83,3 @@ MAILER_TYPE = smtp
IS_TLS_ENABLED = true
HELO_HOSTNAME = example.com
```
-
diff --git a/docs/content/doc/usage/fail2ban-setup.en-us.md b/docs/content/doc/usage/fail2ban-setup.en-us.md
index d1ff633246e40..f00551e3efa92 100644
--- a/docs/content/doc/usage/fail2ban-setup.en-us.md
+++ b/docs/content/doc/usage/fail2ban-setup.en-us.md
@@ -29,31 +29,37 @@ on a bad authentication from the web or CLI using SSH or HTTP respectively:
```log
2020/10/15 16:05:09 modules/ssh/ssh.go:143:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
```
+
(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.)
```log
2020/10/15 16:05:09 modules/ssh/ssh.go:155:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
```
+
(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.)
```log
2020/10/15 16:05:09 modules/ssh/ssh.go:198:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
```
+
(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.)
```log
2020/10/15 16:05:09 modules/ssh/ssh.go:213:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
```
+
(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.)
```log
2020/10/15 16:05:09 modules/ssh/ssh.go:227:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
```
+
(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.)
```log
2020/10/15 16:05:09 modules/ssh/ssh.go:249:sshConnectionFailed() [W] Failed authentication attempt from xxx.xxx.xxx.xxx
```
+
(From 1.15 this new message will available and doesn't have any of the false positive results that above messages from publicKeyHandler do. This will only be logged if the user has completely failed authentication.)
```log
diff --git a/docs/content/doc/usage/fail2ban-setup.zh-cn.md b/docs/content/doc/usage/fail2ban-setup.zh-cn.md
new file mode 100644
index 0000000000000..446d192aa619f
--- /dev/null
+++ b/docs/content/doc/usage/fail2ban-setup.zh-cn.md
@@ -0,0 +1,92 @@
+---
+date: "2022-08-01T00:00:00+00:00"
+title: "使用: 设置 Fail2ban"
+slug: "fail2ban-setup"
+weight: 16
+toc: false
+draft: false
+menu:
+ sidebar:
+ parent: "usage"
+ name: "设置 Fail2ban"
+ weight: 16
+ identifier: "fail2ban-setup"
+---
+
+# 使用 Fail2ban 阻止攻击者的暴力登录
+
+**Fail2ban 检查客户端登录日志,将多次登录失败的客户端识别为攻击者并在一段时间内阻止其访问服务。如果你的实例是公开的,这一点尤其重要。请管理员仔细设置 fail2ban,错误的配置将导致防火墙阻止你访问自己的服务器。**
+
+Gitea 会在日志文件 `log/gitea.log` 中记录登录失败的 CLI、SSH 或 HTTP 客户端 IP 地址,而你需要将 Gitea 的日志输出模式从默认的 `console` 更改为 `file`。这表示将日志输出到文件,使得 fail2ban 可以定期扫描日志内容。
+
+当用户的身份验证失败时,日志中会记录此类信息:
+
+```log
+2018/04/26 18:15:54 [I] Failed authentication attempt for user from xxx.xxx.xxx.xxx
+```
+
+```log
+2020/10/15 16:08:44 [E] invalid credentials from xxx.xxx.xxx.xxx
+```
+
+## 设置 Fail2ban
+
+添加日志过滤器规则到配置文件 `/etc/fail2ban/filter.d/gitea.conf`:
+
+```ini
+[Definition]
+failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from
+ignoreregex =
+```
+
+添加监狱规则到配置文件 `/etc/fail2ban/jail.d/gitea.conf`:
+
+```ini
+[gitea]
+enabled = true
+filter = gitea
+logpath = /var/lib/gitea/log/gitea.log
+maxretry = 10
+findtime = 3600
+bantime = 900
+action = iptables-allports
+```
+
+如果你的 Gitea 实例运行在 Docker 容器中,并且直接将容器端口暴露到外部网络,
+你还需要添加 `chain="FORWARD"` 到监狱规则配置文件 `/etc/fail2ban/jail.d/gitea-docker.conf`
+以适应 Docker 的网络转发规则。但如果你在容器的宿主机上使用 Nginx 反向代理连接到 Gitea 则无需这样配置。
+
+```ini
+[gitea-docker]
+enabled = true
+filter = gitea
+logpath = /var/lib/gitea/log/gitea.log
+maxretry = 10
+findtime = 3600
+bantime = 900
+action = iptables-allports[chain="FORWARD"]
+```
+
+最后,运行 `systemctl restart fail2ban` 即可应用更改。现在,你可以使用 `systemctl status fail2ban` 检查 fail2ban 运行状态。
+
+上述规则规定客户端在 1 小时内,如果登录失败的次数达到 10 次,则通过 iptables 锁定该客户端 IP 地址 15 分钟。
+
+## 设置反向代理
+
+如果你使用 Nginx 反向代理到 Gitea 实例,你还需要设置 Nginx 的 HTTP 头部值 `X-Real-IP` 将真实的客户端 IP 地址传递给 Gitea。否则 Gitea 程序会将客户端地址错误解析为反向代理服务器的地址,例如回环地址 `127.0.0.1`。
+
+```
+proxy_set_header X-Real-IP $remote_addr;
+```
+
+额外注意,在 Gitea 的配置文件 `app.ini` 中存在下列默认值:
+
+```
+REVERSE_PROXY_LIMIT = 1
+REVERSE_PROXY_TRUSTED_PROXIES = 127.0.0.0/8,::1/128
+```
+
+`REVERSE_PROXY_LIMIT` 限制反向代理服务器的层数,设置为 `0` 表示不使用这些标头。
+`REVERSE_PROXY_TRUSTED_PROXIES` 表示受信任的反向代理服务器网络地址,
+经过该网络地址转发来的流量会经过解析 `X-Real-IP` 头部得到真实客户端地址。
+(参考 [configuration cheat sheet](https://docs.gitea.io/en-us/config-cheat-sheet/#security-security))
diff --git a/docs/content/doc/usage/https-support.md b/docs/content/doc/usage/https-support.md
index 756e11fd03e29..783d6d803774f 100644
--- a/docs/content/doc/usage/https-support.md
+++ b/docs/content/doc/usage/https-support.md
@@ -60,6 +60,7 @@ If you are using Docker, make sure that this port is configured in your `docker-
[ACME](https://tools.ietf.org/html/rfc8555) is a Certificate Authority standard protocol that allows you to automatically request and renew SSL/TLS certificates. [Let's Encrypt](https://letsencrypt.org/) is a free publicly trusted Certificate Authority server using this standard. Only `HTTP-01` and `TLS-ALPN-01` challenges are implemented. In order for ACME challenges to pass and verify your domain ownership, external traffic to the gitea domain on port `80` (`HTTP-01`) or port `443` (`TLS-ALPN-01`) has to be served by the gitea instance. Setting up [HTTP redirection](#setting-up-http-redirection) and port-forwards might be needed for external traffic to route correctly. Normal traffic to port `80` will otherwise be automatically redirected to HTTPS. **You must consent** to the ACME provider's terms of service (default Let's Encrypt's [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf)).
Minimum setup using the default Let's Encrypt:
+
```ini
[server]
PROTOCOL=https
@@ -72,6 +73,7 @@ ACME_EMAIL=email@example.com
```
Minimumg setup using a [smallstep CA](https://github.com/smallstep/certificates), refer to [their tutorial](https://smallstep.com/docs/tutorials/acme-challenge) for more information.
+
```ini
[server]
PROTOCOL=https
diff --git a/docs/content/doc/usage/issue-pull-request-templates.zh-cn.md b/docs/content/doc/usage/issue-pull-request-templates.zh-cn.md
index 1d2539b7bd19f..db69f3e5ce6cb 100644
--- a/docs/content/doc/usage/issue-pull-request-templates.zh-cn.md
+++ b/docs/content/doc/usage/issue-pull-request-templates.zh-cn.md
@@ -26,7 +26,6 @@ menu:
* .github/ISSUE_TEMPLATE.md
* .github/issue_template.md
-
以下罗列了一些可供参考的 PR 模板:
* PULL_REQUEST_TEMPLATE.md
diff --git a/docs/content/doc/usage/permissions.en-us.md b/docs/content/doc/usage/permissions.en-us.md
index 0c3dc9e09e736..013dbfabd4570 100644
--- a/docs/content/doc/usage/permissions.en-us.md
+++ b/docs/content/doc/usage/permissions.en-us.md
@@ -55,7 +55,7 @@ And there are some differences for permissions between individual repositories a
## Individual Repository
-For individual repositories, the creators are the only owners of repositories and have no limit to change anything of this
+For individual repositories, the creators are the only owners of repositories and have no limit to change anything of this
repository or delete it. Repositories owners could add collaborators to help maintain the repositories. Collaborators could have `Read`, `Write` and `Admin` permissions.
## Organization Repository
diff --git a/docs/content/doc/usage/push-options.en-us.md b/docs/content/doc/usage/push-options.en-us.md
index 6539c9d7cd527..8d7de19609c83 100644
--- a/docs/content/doc/usage/push-options.en-us.md
+++ b/docs/content/doc/usage/push-options.en-us.md
@@ -18,14 +18,16 @@ menu:
In Gitea `1.13`, support for some [push options](https://git-scm.com/docs/git-push#Documentation/git-push.txt--oltoptiongt)
were added.
-
## Supported Options
-- `repo.private` (true|false) - Change the repository's visibility.
-This is particularly useful when combined with push-to-create.
+- `repo.private` (true|false) - Change the repository's visibility.
+
+ This is particularly useful when combined with push-to-create.
+
- `repo.template` (true|false) - Change whether the repository is a template.
-Example of changing a repository's visibility to public:
+Example of changing a repository's visibility to public:
+
```shell
git push -o repo.private=false -u origin master
```
diff --git a/docs/content/doc/usage/push-options.zh-tw.md b/docs/content/doc/usage/push-options.zh-tw.md
index b0fc75ac24129..d6ffbe695b401 100644
--- a/docs/content/doc/usage/push-options.zh-tw.md
+++ b/docs/content/doc/usage/push-options.zh-tw.md
@@ -20,8 +20,10 @@ Gitea 從 `1.13` 版開始支援某些 [push options](https://git-scm.com/docs/g
## 支援的 Options
-- `repo.private` (true|false) - 修改儲存庫的可見性。
+- `repo.private` (true|false) - 修改儲存庫的可見性。
+
與 push-to-create 一起使用時特別有用。
+
- `repo.template` (true|false) - 修改儲存庫是否為範本儲存庫。
以下範例修改儲存庫的可見性為公開:
diff --git a/docs/content/doc/usage/reverse-proxies.en-us.md b/docs/content/doc/usage/reverse-proxies.en-us.md
index 9e903f4259436..5797d8e5eb8f0 100644
--- a/docs/content/doc/usage/reverse-proxies.en-us.md
+++ b/docs/content/doc/usage/reverse-proxies.en-us.md
@@ -138,7 +138,6 @@ In your nginx config file containing your Gitea proxy directive, find the `locat
`client_max_body_size 16M;` to set this limit to 16 megabytes or any other number of choice.
If you use Git LFS, this will also limit the size of the largest file you will be able to push.
-
## Apache HTTPD
If you want Apache HTTPD to serve your Gitea instance, you can add the following to your Apache HTTPD configuration (usually located at `/etc/apache2/httpd.conf` in Ubuntu):
@@ -307,6 +306,7 @@ If you wish to run Gitea with IIS. You will need to setup IIS with URL Rewrite a
If you want HAProxy to serve your Gitea instance, you can add the following to your HAProxy configuration
add an acl in the frontend section to redirect calls to gitea.example.com to the correct backend
+
```
frontend http-in
...
@@ -316,6 +316,7 @@ frontend http-in
```
add the previously defined backend section
+
```
backend gitea
server localhost:3000 check
@@ -338,6 +339,7 @@ frontend http-in
With that configuration http://example.com/gitea/ will redirect to your Gitea instance.
then for the backend section
+
```
backend gitea
http-request replace-path /gitea\/?(.*) \/\1
diff --git a/docs/content/doc/usage/reverse-proxies.zh-cn.md b/docs/content/doc/usage/reverse-proxies.zh-cn.md
index 88db0c3790306..722b9c7c9db91 100644
--- a/docs/content/doc/usage/reverse-proxies.zh-cn.md
+++ b/docs/content/doc/usage/reverse-proxies.zh-cn.md
@@ -121,4 +121,4 @@ gitea:
- "traefik.http.services.gitea-websecure.loadbalancer.server.port=3000"
```
-这份配置假设您使用 traefik 来处理 HTTPS 服务,并在其和 Gitea 之间使用 HTTP 进行通信。
\ No newline at end of file
+这份配置假设您使用 traefik 来处理 HTTPS 服务,并在其和 Gitea 之间使用 HTTP 进行通信。
diff --git a/docs/content/doc/usage/template-repositories.md b/docs/content/doc/usage/template-repositories.md
index 24fdf28ee091f..9a2a23ed2b032 100644
--- a/docs/content/doc/usage/template-repositories.md
+++ b/docs/content/doc/usage/template-repositories.md
@@ -19,8 +19,10 @@ menu:
{{< toc >}}
-Gitea `1.11.0` and above includes template repositories, and one feature implemented with them is auto-expansion of specific variables within your template files.
-To tell Gitea which files to expand, you must include a `template` file inside the `.gitea` directory of the template repository.
+Gitea `1.11.0` and above includes template repositories, and one feature implemented with them is auto-expansion of specific variables within your template files.
+
+To tell Gitea which files to expand, you must include a `template` file inside the `.gitea` directory of the template repository.
+
Gitea uses [gobwas/glob](https://github.com/gobwas/glob) for its glob syntax. It closely resembles a traditional `.gitignore`, however there may be slight differences.
## Example `.gitea/template` file
@@ -45,7 +47,8 @@ a/b/c/d.json
## Variable Expansion
-In any file matched by the above globs, certain variables will be expanded.
+In any file matched by the above globs, certain variables will be expanded.
+
All variables must be of the form `$VAR` or `${VAR}`. To escape an expansion, use a double `$$`, such as `$$VAR` or `$${VAR}`
| Variable | Expands To | Transformable |
@@ -65,7 +68,8 @@ All variables must be of the form `$VAR` or `${VAR}`. To escape an expansion, us
## Transformers :robot:
-Gitea `1.12.0` adds a few transformers to some of the applicable variables above.
+Gitea `1.12.0` adds a few transformers to some of the applicable variables above.
+
For example, to get `REPO_NAME` in `PASCAL`-case, your template would use `${REPO_NAME_PASCAL}`
Feeding `go-sdk` to the available transformers yields...
diff --git a/docs/content/page/index.de-de.md b/docs/content/page/index.de-de.md
index e901702969f66..8f8f264ed12ab 100644
--- a/docs/content/page/index.de-de.md
+++ b/docs/content/page/index.de-de.md
@@ -10,27 +10,28 @@ draft: false
# Was ist Gitea?
-Gitea ist ein einfacher, selbst gehosteter Git-Service. Änlich wie GitHub, Bitbucket oder GitLab.
+Gitea ist ein einfacher, selbst gehosteter Git-Service. Änlich wie GitHub, Bitbucket oder GitLab.
+
Gitea ist ein [Gogs](http://gogs.io)-Fork.
## Ziele
- * Einfach zu installieren
- * Plattformübergreifend
- * Leichtgewichtig
- * Quelloffen
+* Einfach zu installieren
+* Plattformübergreifend
+* Leichtgewichtig
+* Quelloffen
## System Voraussetzungen
-- Ein Raspberry Pi 3 ist leistungsstark genug, um Gitea für kleine Belastungen laufen zu lassen.
-- 2 CPU Kerne und 1GB RAM sind für kleine Teams/Projekte ausreichend.
-- Gitea sollte unter einem seperaten nicht-root Account auf UNIX-Systemen ausgeführt werden.
- - Achtung: Gitea verwaltet die `~/.ssh/authorized_keys` Datei. Gitea unter einem normalen Benutzer auszuführen könnte dazu führen, dass dieser sich nicht mehr anmelden kann.
-- [Git](https://git-scm.com/) Version 2.0 oder später wird benötigt.
- - Wenn git >= 2.1.2. und [Git large file storage](https://git-lfs.github.com/) aktiviert ist, dann wird es auch in Gitea verwendbar sein.
- - Wenn git >= 2.18, dann wird das Rendern von Commit-Graphen automatisch aktiviert.
+* Ein Raspberry Pi 3 ist leistungsstark genug, um Gitea für kleine Belastungen laufen zu lassen.
+* 2 CPU Kerne und 1GB RAM sind für kleine Teams/Projekte ausreichend.
+* Gitea sollte unter einem seperaten nicht-root Account auf UNIX-Systemen ausgeführt werden.
+ * Achtung: Gitea verwaltet die `~/.ssh/authorized_keys` Datei. Gitea unter einem normalen Benutzer auszuführen könnte dazu führen, dass dieser sich nicht mehr anmelden kann.
+* [Git](https://git-scm.com/) Version 2.0 oder später wird benötigt.
+ * Wenn git >= 2.1.2. und [Git large file storage](https://git-lfs.github.com/) aktiviert ist, dann wird es auch in Gitea verwendbar sein.
+ * Wenn git >= 2.18, dann wird das Rendern von Commit-Graphen automatisch aktiviert.
## Browser Unterstützung
-- Letzten 2 Versions von Chrome, Firefox, Safari und Edge
-- Firefox ESR
+* Letzten 2 Versions von Chrome, Firefox, Safari und Edge
+* Firefox ESR
diff --git a/docs/content/page/index.en-us.md b/docs/content/page/index.en-us.md
index c3a43cd029dbf..8e2e36223ad00 100644
--- a/docs/content/page/index.en-us.md
+++ b/docs/content/page/index.en-us.md
@@ -17,50 +17,53 @@ blog post to read about the justification for a fork.
## Purpose
The goal of this project is to provide the easiest, fastest, and most painless way of setting
-up a self-hosted Git service. With Go, this can be done with an independent binary distribution
-across all platforms and architectures that Go supports. This support includes Linux, macOS, and
-Windows, on architectures like amd64, i386, ARM, PowerPC, and others.
+up a self-hosted Git service.
+
+With Go, this can be done platform-independently across
+**all platforms** which Go supports, including Linux, macOS, and Windows,
+on x86, amd64, ARM and PowerPC architectures.
+You can try it out using [the online demo](https://try.gitea.io/).
## Features
- User Dashboard
- - Context switcher (organization or current user)
- - Activity timeline
- - Commits
- - Issues
- - Pull requests
- - Repository creation
- - Searchable repository list
- - List of organizations
- - A list of mirror repositories
+ - Context switcher (organization or current user)
+ - Activity timeline
+ - Commits
+ - Issues
+ - Pull requests
+ - Repository creation
+ - Searchable repository list
+ - List of organizations
+ - A list of mirror repositories
- Issues dashboard
- - Context switcher (organization or current user)
- - Filter by
- - Open
- - Closed
- - Your repositories
- - Assigned issues
- - Your issues
- - Repository
- - Sort by
- - Oldest
- - Last updated
- - Number of comments
+ - Context switcher (organization or current user)
+ - Filter by
+ - Open
+ - Closed
+ - Your repositories
+ - Assigned issues
+ - Your issues
+ - Repository
+ - Sort by
+ - Oldest
+ - Last updated
+ - Number of comments
- Pull request dashboard
- - Same as issue dashboard
+ - Same as issue dashboard
- Repository types
- - Mirror
- - Normal
- - Migrated
+ - Mirror
+ - Normal
+ - Migrated
- Notifications (email and web)
- - Read
- - Unread
- - Pin
+ - Read
+ - Unread
+ - Pin
- Explore page
- - Users
- - Repos
- - Organizations
- - Search
+ - Users
+ - Repos
+ - Organizations
+ - Search
- Custom templates
- Override public files (logo, css, etc)
- CSRF and XSS protection
@@ -68,187 +71,187 @@ Windows, on architectures like amd64, i386, ARM, PowerPC, and others.
- Set allowed upload sizes and types
- Logging
- Configuration
- - Databases
- - MySQL (>=5.7)
- - PostgreSQL (>=10)
- - SQLite3
- - MSSQL (>=2008R2 SP3)
- - TiDB (MySQL protocol)
- - Configuration file
- - [app.ini](https://github.com/go-gitea/gitea/blob/main/custom/conf/app.example.ini)
- - Admin panel
- - Statistics
- - Actions
- - Delete inactive accounts
- - Delete cached repository archives
- - Delete repositories records which are missing their files
- - Run garbage collection on repositories
- - Rewrite SSH keys
- - Resync hooks
- - Recreate repositories which are missing
- - Server status
- - Uptime
- - Memory
- - Current # of goroutines
- - And more
- - User management
- - Search
- - Sort
- - Last login
- - Authentication source
- - Maximum repositories
- - Disable account
- - Admin permissions
- - Permission to create Git Hooks
- - Permission to create organizations
- - Permission to import repositories
- - Organization management
- - People
- - Teams
- - Avatar
- - Hooks
- - Repository management
- - See all repository information and manage repositories
- - Authentication sources
- - OAuth
- - PAM
- - LDAP
- - SMTP
- - Configuration viewer
- - Everything in config file
- - System notices
- - When something unexpected happens
- - Monitoring
- - Current processes
- - Cron jobs
- - Update mirrors
- - Repository health check
- - Check repository statistics
- - Clean up old archives
- - Environment variables
- - Command line options
+ - Databases
+ - MySQL (>=5.7)
+ - PostgreSQL (>=10)
+ - SQLite3
+ - MSSQL (>=2008R2 SP3)
+ - TiDB (MySQL protocol)
+ - Configuration file
+ - [app.ini](https://github.com/go-gitea/gitea/blob/main/custom/conf/app.example.ini)
+ - Admin panel
+ - Statistics
+ - Actions
+ - Delete inactive accounts
+ - Delete cached repository archives
+ - Delete repositories records which are missing their files
+ - Run garbage collection on repositories
+ - Rewrite SSH keys
+ - Resync hooks
+ - Recreate repositories which are missing
+ - Server status
+ - Uptime
+ - Memory
+ - Current # of goroutines
+ - And more
+ - User management
+ - Search
+ - Sort
+ - Last login
+ - Authentication source
+ - Maximum repositories
+ - Disable account
+ - Admin permissions
+ - Permission to create Git Hooks
+ - Permission to create organizations
+ - Permission to import repositories
+ - Organization management
+ - People
+ - Teams
+ - Avatar
+ - Hooks
+ - Repository management
+ - See all repository information and manage repositories
+ - Authentication sources
+ - OAuth
+ - PAM
+ - LDAP
+ - SMTP
+ - Configuration viewer
+ - Everything in config file
+ - System notices
+ - When something unexpected happens
+ - Monitoring
+ - Current processes
+ - Cron jobs
+ - Update mirrors
+ - Repository health check
+ - Check repository statistics
+ - Clean up old archives
+ - Environment variables
+ - Command line options
- Multi-language support ([21 languages](https://github.com/go-gitea/gitea/tree/main/options/locale))
- [Mermaid](https://mermaidjs.github.io/) Diagram support
- Mail service
- - Notifications
- - Registration confirmation
- - Password reset
+ - Notifications
+ - Registration confirmation
+ - Password reset
- Reverse proxy support
- - Includes subpaths
+ - Includes subpaths
- Users
- - Profile
- - Name
- - Username
- - Email
- - Website
- - Join date
- - Followers and following
- - Organizations
- - Repositories
- - Activity
- - Starred repositories
- - Settings
- - Same as profile and more below
- - Keep email private
- - Avatar
- - Gravatar
- - Libravatar
- - Custom
- - Password
- - Multiple email addresses
- - SSH Keys
- - Connected applications
- - Two factor authentication
- - Linked OAuth2 sources
- - Delete account
+ - Profile
+ - Name
+ - Username
+ - Email
+ - Website
+ - Join date
+ - Followers and following
+ - Organizations
+ - Repositories
+ - Activity
+ - Starred repositories
+ - Settings
+ - Same as profile and more below
+ - Keep email private
+ - Avatar
+ - Gravatar
+ - Libravatar
+ - Custom
+ - Password
+ - Multiple email addresses
+ - SSH Keys
+ - Connected applications
+ - Two factor authentication
+ - Linked OAuth2 sources
+ - Delete account
- Repositories
- - Clone with SSH/HTTP/HTTPS
- - Git LFS
- - Watch, Star, Fork
- - View watchers, stars, and forks
- - Code
- - Branch browser
- - Web based file upload and creation
- - Clone urls
- - Download
- - ZIP
- - TAR.GZ
- - Web based editor
- - Markdown editor
- - Plain text editor
- - Syntax highlighting
- - Diff preview
- - Preview
- - Choose where to commit to
- - View file history
- - Delete file
- - View raw
- - Issues
- - Issue templates
- - Milestones
- - Labels
- - Assign issues
- - Track time
- - Reactions
- - Filter
- - Open
- - Closed
- - Assigned person
- - Created by you
- - Mentioning you
- - Sort
- - Oldest
- - Last updated
- - Number of comments
- - Search
- - Comments
- - Attachments
- - Pull requests
- - Same features as issues
- - Commits
- - Commit graph
- - Commits by branch
- - Search
- - Search in all branches
- - View diff
- - View SHA
- - View author
- - Browse files in commit
- - Releases
- - Attachments
- - Title
- - Content
- - Delete
- - Mark as pre-release
- - Choose branch
- - Wiki
- - Import
- - Markdown editor
- - Settings
- - Options
- - Name
- - Description
- - Private/Public
- - Website
- - Wiki
- - Enabled/disabled
- - Internal/external
- - Issues
- - Enabled/disabled
- - Internal/external
- - External supports url rewriting for better integration
- - Enable/disable pull requests
- - Transfer repository
- - Delete wiki
- - Delete repository
- - Collaboration
- - Read/write/admin
- - Branches
- - Default branch
- - Branch protection
- - Webhooks
- - Git Hooks
- - Deploy keys
+ - Clone with SSH/HTTP/HTTPS
+ - Git LFS
+ - Watch, Star, Fork
+ - View watchers, stars, and forks
+ - Code
+ - Branch browser
+ - Web based file upload and creation
+ - Clone urls
+ - Download
+ - ZIP
+ - TAR.GZ
+ - Web based editor
+ - Markdown editor
+ - Plain text editor
+ - Syntax highlighting
+ - Diff preview
+ - Preview
+ - Choose where to commit to
+ - View file history
+ - Delete file
+ - View raw
+ - Issues
+ - Issue templates
+ - Milestones
+ - Labels
+ - Assign issues
+ - Track time
+ - Reactions
+ - Filter
+ - Open
+ - Closed
+ - Assigned person
+ - Created by you
+ - Mentioning you
+ - Sort
+ - Oldest
+ - Last updated
+ - Number of comments
+ - Search
+ - Comments
+ - Attachments
+ - Pull requests
+ - Same features as issues
+ - Commits
+ - Commit graph
+ - Commits by branch
+ - Search
+ - Search in all branches
+ - View diff
+ - View SHA
+ - View author
+ - Browse files in commit
+ - Releases
+ - Attachments
+ - Title
+ - Content
+ - Delete
+ - Mark as pre-release
+ - Choose branch
+ - Wiki
+ - Import
+ - Markdown editor
+ - Settings
+ - Options
+ - Name
+ - Description
+ - Private/Public
+ - Website
+ - Wiki
+ - Enabled/disabled
+ - Internal/external
+ - Issues
+ - Enabled/disabled
+ - Internal/external
+ - External supports url rewriting for better integration
+ - Enable/disable pull requests
+ - Transfer repository
+ - Delete wiki
+ - Delete repository
+ - Collaboration
+ - Read/write/admin
+ - Branches
+ - Default branch
+ - Branch protection
+ - Webhooks
+ - Git Hooks
+ - Deploy keys
- Package Registries
- Composer
- Conan
@@ -266,10 +269,10 @@ Windows, on architectures like amd64, i386, ARM, PowerPC, and others.
- A Raspberry Pi 3 is powerful enough to run Gitea for small workloads.
- 2 CPU cores and 1GB RAM is typically sufficient for small teams/projects.
- Gitea should be run with a dedicated non-root system account on UNIX-type systems.
- - Note: Gitea manages the `~/.ssh/authorized_keys` file. Running Gitea as a regular user could break that user's ability to log in.
+ - Note: Gitea manages the `~/.ssh/authorized_keys` file. Running Gitea as a regular user could break that user's ability to log in.
- [Git](https://git-scm.com/) version 2.0.0 or later is required.
- - [Git Large File Storage](https://git-lfs.github.com/) will be available if enabled when Git >= 2.1.2.
- - Git commit-graph rendering will be enabled automatically when Git >= 2.18.
+ - [Git Large File Storage](https://git-lfs.github.com/) will be available if enabled and if your Git version is >= 2.1.2
+ - Git commit-graph rendering will be enabled automatically if your Git version is >= 2.18
## Browser Support
@@ -278,22 +281,22 @@ Windows, on architectures like amd64, i386, ARM, PowerPC, and others.
## Components
-* Web server framework: [Chi](http://github.com/go-chi/chi)
-* ORM: [XORM](https://xorm.io)
-* UI frameworks:
- * [jQuery](https://jquery.com)
- * [Fomantic UI](https://fomantic-ui.com)
- * [Vue2](https://vuejs.org)
- * and various components (see package.json)
-* Editors:
- * [CodeMirror](https://codemirror.net)
- * [EasyMDE](https://github.com/Ionaru/easy-markdown-editor)
- * [Monaco Editor](https://microsoft.github.io/monaco-editor)
-* Database drivers:
- * [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
- * [github.com/lib/pq](https://github.com/lib/pq)
- * [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
- * [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
+- Web server framework: [Chi](http://github.com/go-chi/chi)
+- ORM: [XORM](https://xorm.io)
+- UI frameworks:
+ - [jQuery](https://jquery.com)
+ - [Fomantic UI](https://fomantic-ui.com)
+ - [Vue2](https://vuejs.org)
+ - and various components (see package.json)
+- Editors:
+ - [CodeMirror](https://codemirror.net)
+ - [EasyMDE](https://github.com/Ionaru/easy-markdown-editor)
+ - [Monaco Editor](https://microsoft.github.io/monaco-editor)
+- Database drivers:
+ - [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
+ - [github.com/lib/pq](https://github.com/lib/pq)
+ - [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
+ - [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
## Software and Service Support
diff --git a/docs/content/page/index.fr-fr.md b/docs/content/page/index.fr-fr.md
index b3828c7141330..39d7ff8df388c 100755
--- a/docs/content/page/index.fr-fr.md
+++ b/docs/content/page/index.fr-fr.md
@@ -19,43 +19,43 @@ Le but de ce projet est de fournir de la manière la plus simple, la plus rapide
## Fonctionalités
- Tableau de bord de l'utilisateur
- - Choix du contexte (organisation ou utilisateur actuel)
- - Chronologie de l'activité
- - Révisions (_Commits_)
- - Tickets
- - Demande d'ajout (_Pull request_)
- - Création de dépôts
- - Liste des dépôts
- - Liste de vos organisations
- - Liste des dépôts miroires
+ - Choix du contexte (organisation ou utilisateur actuel)
+ - Chronologie de l'activité
+ - Révisions (_Commits_)
+ - Tickets
+ - Demande d'ajout (_Pull request_)
+ - Création de dépôts
+ - Liste des dépôts
+ - Liste de vos organisations
+ - Liste des dépôts miroires
- Tableau de bord des tickets
- - Choix du contexte (organisation ou utilisateur actuel)
- - Filtres
- - Ouvert
- - Fermé
- - Vos dépôts
- - Tickets assignés
- - Vos tickets
- - Dépôts
- - Options de tri
- - Plus vieux
- - Dernière mise à jour
- - Nombre de commentaires
+ - Choix du contexte (organisation ou utilisateur actuel)
+ - Filtres
+ - Ouvert
+ - Fermé
+ - Vos dépôts
+ - Tickets assignés
+ - Vos tickets
+ - Dépôts
+ - Options de tri
+ - Plus vieux
+ - Dernière mise à jour
+ - Nombre de commentaires
- Tableau de bord des demandes d'ajout
- - Identique au tableau de bord des tickets
+ - Identique au tableau de bord des tickets
- Types de dépôt
- - Miroire
- - Normal
- - Migré
+ - Miroire
+ - Normal
+ - Migré
- Notifications (courriel et web)
- - Lu
- - Non lu
- - Épinglé
+ - Lu
+ - Non lu
+ - Épinglé
- Page d'exploration
- - Utilisateurs
- - Dépôts
- - Organisations
- - Moteur de recherche
+ - Utilisateurs
+ - Dépôts
+ - Organisations
+ - Moteur de recherche
- Interface personnalisables
- Fichiers publiques remplaçables (logo, css, etc)
- Protection CSRF et XSS
@@ -63,183 +63,183 @@ Le but de ce projet est de fournir de la manière la plus simple, la plus rapide
- Configuration des types et de la taille maximale des fichiers téléversés
- Journalisation (_Log_)
- Configuration
- - Base de données
- - MySQL
- - PostgreSQL
- - SQLite3
- - MSSQL
- - [TiDB](https://github.com/pingcap/tidb) (MySQL protocol)
- - Fichier de configuration
- - Voir [ici](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini)
- - Panel d'administration
- - Statistiques
- - Actions
- - Suppression des comptes inactifs
- - Suppression des dépôts archivés
- - Suppression des dépôts pour lesquels il manque leurs fichiers
- - Exécution du _garbage collector_ sur les dépôts
- - Ré-écriture des clefs SSH
- - Resynchronisation des hooks
- - Recreation des dépôts manquants
- - Status du server
- - Temps de disponibilité
- - Mémoire
- - Nombre de goroutines
- - et bien plus...
- - Gestion des utilisateurs
- - Recherche
- - Tri
- - Dernière connexion
- - Méthode d'authentification
- - Nombre maximum de dépôts
- - Désactivation du compte
- - Permissions d'administration
- - Permission pour crééer des hooks
- - Permission pour crééer des organisations
- - Permission pour importer des dépôts
- - Gestion des organisations
- - Membres
- - Équipes
- - Avatar
- - Hooks
- - Gestion des depôts
- - Voir toutes les informations pour un dépôt donné et gérer tous les dépôts
- - Méthodes d'authentification
- - OAuth
- - PAM
- - LDAP
- - SMTP
- - Visualisation de la configuration
- - Tout ce que contient le fichier de configuration
- - Alertes du système
- - Quand quelque chose d'inattendu survient
- - Surveillance
- - Processus courrants
- - Tâches CRON
- - Mise à jour des dépôts miroires
- - Vérification de l'état des dépôts
- - Vérification des statistiques des dépôts
- - Nettoyage des anciennes archives
- - Variables d'environement
- - Options de ligne de commande
+ - Base de données
+ - MySQL
+ - PostgreSQL
+ - SQLite3
+ - MSSQL
+ - [TiDB](https://github.com/pingcap/tidb) (MySQL protocol)
+ - Fichier de configuration
+ - Voir [ici](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini)
+ - Panel d'administration
+ - Statistiques
+ - Actions
+ - Suppression des comptes inactifs
+ - Suppression des dépôts archivés
+ - Suppression des dépôts pour lesquels il manque leurs fichiers
+ - Exécution du _garbage collector_ sur les dépôts
+ - Ré-écriture des clefs SSH
+ - Resynchronisation des hooks
+ - Recreation des dépôts manquants
+ - Status du server
+ - Temps de disponibilité
+ - Mémoire
+ - Nombre de goroutines
+ - et bien plus...
+ - Gestion des utilisateurs
+ - Recherche
+ - Tri
+ - Dernière connexion
+ - Méthode d'authentification
+ - Nombre maximum de dépôts
+ - Désactivation du compte
+ - Permissions d'administration
+ - Permission pour crééer des hooks
+ - Permission pour crééer des organisations
+ - Permission pour importer des dépôts
+ - Gestion des organisations
+ - Membres
+ - Équipes
+ - Avatar
+ - Hooks
+ - Gestion des depôts
+ - Voir toutes les informations pour un dépôt donné et gérer tous les dépôts
+ - Méthodes d'authentification
+ - OAuth
+ - PAM
+ - LDAP
+ - SMTP
+ - Visualisation de la configuration
+ - Tout ce que contient le fichier de configuration
+ - Alertes du système
+ - Quand quelque chose d'inattendu survient
+ - Surveillance
+ - Processus courrants
+ - Tâches CRON
+ - Mise à jour des dépôts miroires
+ - Vérification de l'état des dépôts
+ - Vérification des statistiques des dépôts
+ - Nettoyage des anciennes archives
+ - Variables d'environement
+ - Options de ligne de commande
- Internationalisation ([21 langues](https://github.com/go-gitea/gitea/tree/master/options/locale))
- Courriel
- - Notifications
- - Confirmation d'inscription
- - Ré-initialisation du mot de passe
+ - Notifications
+ - Confirmation d'inscription
+ - Ré-initialisation du mot de passe
- Support de _reverse proxy_
- - _subpaths_ inclus
+ - _subpaths_ inclus
- Utilisateurs
- - Profil
- - Nom
- - Prénom
- - Courriel
- - Site internet
- - Date de création
- - Abonnés et abonnements
- - Organisations
- - Dépôts
- - Activité
- - Dépôts suivis
- - Paramètres
- - Identiques au profil avec en plus les éléments ci-dessous
- - Rendre l'adresse de courriel privée
- - Avatar
- - Gravatar
- - Libravatar
- - Personnalisé
- - Mot de passe
- - Courriels multiples
- - Clefs SSH
- - Applications connectées
- - Authentification à double facteurs
- - Identités OAuth2 attachées
- - Suppression du compte
+ - Profil
+ - Nom
+ - Prénom
+ - Courriel
+ - Site internet
+ - Date de création
+ - Abonnés et abonnements
+ - Organisations
+ - Dépôts
+ - Activité
+ - Dépôts suivis
+ - Paramètres
+ - Identiques au profil avec en plus les éléments ci-dessous
+ - Rendre l'adresse de courriel privée
+ - Avatar
+ - Gravatar
+ - Libravatar
+ - Personnalisé
+ - Mot de passe
+ - Courriels multiples
+ - Clefs SSH
+ - Applications connectées
+ - Authentification à double facteurs
+ - Identités OAuth2 attachées
+ - Suppression du compte
- Dépôts
- - Clone à partir de SSH / HTTP / HTTPS
- - Git LFS
- - Suivre, Voter, Fork
- - Voir les personnes qui suivent, les votes et les forks
- - Code
- - Navigation entre les branches
- - Création ou téléversement de fichier depuis le navigateur
- - URLs pour clôner le dépôt
- - Téléchargement
- - ZIP
- - TAR.GZ
- - Édition en ligne
- - Éditeur Markdown
- - Éditeur de texte
- - Coloration syntaxique
- - Visualisation des Diffs
- - Visualisation
- - Possibilité de choisir où sauvegarder la révision
- - Historiques des fichiers
- - Suppression de fichiers
- - Voir le fichier brut
- - Tickets
- - Modèle de ticket
- - Jalons
- - Étiquettes
- - Affecter des tickets
- - Filtres
- - Ouvert
- - Ferme
- - Personne assignée
- - Créer par vous
- - Qui vous mentionne
- - Tri
- - Plus vieux
- - Dernière mise à jour
- - Nombre de commentaires
- - Moteur de recherche
- - Commentaires
- - Joindre des fichiers
- - Demande d’ajout (_Pull request_)
- - Les mêmes fonctionnalités que pour les tickets
- - Révisions (_Commits_)
- - Representation graphique des révisions
- - Révisions par branches
- - Moteur de recherche
- - Voir les différences
- - Voir les numéro de révision SHA
- - Voir l'auteur
- - Naviguer dans les fichiers d'une révision donnée
- - Publication
- - Pièces jointes
- - Titre
- - Contenu
- - Suppression
- - Définir comme une pré-publication
- - Choix de la branche
- - Wiki
- - Import
- - Éditeur Markdown
- - Paramètres
- - Options
- - Nom
- - Description
- - Privé / Publique
- - Site internet
- - Wiki
- - Activé / Désactivé
- - Interne / externe
- - Tickets
- - Activé / Désactivé
- - Interne / externe
- - URL personnalisable pour une meilleur intégration avec un gestionnaire de tickets externe
- - Activer / désactiver les demandes d'ajout (_Pull request_)
- - Transfert du dépôt
- - Suppression du wiki
- - Suppression du dépôt
- - Collaboration
- - Lecture / Écriture / Administration
- - Branches
- - Branche par défaut
- - Protection
- - Webhooks
- - Git hooks
- - Clefs de déploiement
+ - Clone à partir de SSH / HTTP / HTTPS
+ - Git LFS
+ - Suivre, Voter, Fork
+ - Voir les personnes qui suivent, les votes et les forks
+ - Code
+ - Navigation entre les branches
+ - Création ou téléversement de fichier depuis le navigateur
+ - URLs pour clôner le dépôt
+ - Téléchargement
+ - ZIP
+ - TAR.GZ
+ - Édition en ligne
+ - Éditeur Markdown
+ - Éditeur de texte
+ - Coloration syntaxique
+ - Visualisation des Diffs
+ - Visualisation
+ - Possibilité de choisir où sauvegarder la révision
+ - Historiques des fichiers
+ - Suppression de fichiers
+ - Voir le fichier brut
+ - Tickets
+ - Modèle de ticket
+ - Jalons
+ - Étiquettes
+ - Affecter des tickets
+ - Filtres
+ - Ouvert
+ - Ferme
+ - Personne assignée
+ - Créer par vous
+ - Qui vous mentionne
+ - Tri
+ - Plus vieux
+ - Dernière mise à jour
+ - Nombre de commentaires
+ - Moteur de recherche
+ - Commentaires
+ - Joindre des fichiers
+ - Demande d’ajout (_Pull request_)
+ - Les mêmes fonctionnalités que pour les tickets
+ - Révisions (_Commits_)
+ - Representation graphique des révisions
+ - Révisions par branches
+ - Moteur de recherche
+ - Voir les différences
+ - Voir les numéro de révision SHA
+ - Voir l'auteur
+ - Naviguer dans les fichiers d'une révision donnée
+ - Publication
+ - Pièces jointes
+ - Titre
+ - Contenu
+ - Suppression
+ - Définir comme une pré-publication
+ - Choix de la branche
+ - Wiki
+ - Import
+ - Éditeur Markdown
+ - Paramètres
+ - Options
+ - Nom
+ - Description
+ - Privé / Publique
+ - Site internet
+ - Wiki
+ - Activé / Désactivé
+ - Interne / externe
+ - Tickets
+ - Activé / Désactivé
+ - Interne / externe
+ - URL personnalisable pour une meilleur intégration avec un gestionnaire de tickets externe
+ - Activer / désactiver les demandes d'ajout (_Pull request_)
+ - Transfert du dépôt
+ - Suppression du wiki
+ - Suppression du dépôt
+ - Collaboration
+ - Lecture / Écriture / Administration
+ - Branches
+ - Branche par défaut
+ - Protection
+ - Webhooks
+ - Git hooks
+ - Clefs de déploiement
## Configuration requise
@@ -253,21 +253,21 @@ Le but de ce projet est de fournir de la manière la plus simple, la plus rapide
## Composants
-* Framework web : [Chi](http://github.com/go-chi/chi)
-* ORM: [XORM](https://xorm.io)
-* Interface graphique :
- * [jQuery](https://jquery.com)
- * [Fomantic UI](https://fomantic-ui.com)
- * [Vue2](https://vuejs.org)
- * [CodeMirror](https://codemirror.net)
- * [EasyMDE](https://github.com/Ionaru/easy-markdown-editor)
- * [Monaco Editor](https://microsoft.github.io/monaco-editor)
- * ... (package.json)
-* Connecteurs de base de données :
- * [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
- * [github.com/lib/pq](https://github.com/lib/pq)
- * [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
- * [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
+- Framework web : [Chi](http://github.com/go-chi/chi)
+- ORM: [XORM](https://xorm.io)
+- Interface graphique :
+ - [jQuery](https://jquery.com)
+ - [Fomantic UI](https://fomantic-ui.com)
+ - [Vue2](https://vuejs.org)
+ - [CodeMirror](https://codemirror.net)
+ - [EasyMDE](https://github.com/Ionaru/easy-markdown-editor)
+ - [Monaco Editor](https://microsoft.github.io/monaco-editor)
+ - ... (package.json)
+- Connecteurs de base de données :
+ - [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
+ - [github.com/lib/pq](https://github.com/lib/pq)
+ - [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
+ - [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
## Logiciels et services
diff --git a/docs/content/page/index.zh-cn.md b/docs/content/page/index.zh-cn.md
index d364edb2d7673..1c94f8ea788a4 100644
--- a/docs/content/page/index.zh-cn.md
+++ b/docs/content/page/index.zh-cn.md
@@ -47,22 +47,22 @@ Gitea的首要目标是创建一个极易安装,运行非常快速,安装和
## 组件
-* Web框架: [Chi](http://github.com/go-chi/chi)
-* ORM: [XORM](https://xorm.io)
-* UI 框架:
- * [jQuery](https://jquery.com)
- * [Fomantic UI](https://fomantic-ui.com)
- * [Vue2](https://vuejs.org)
- * 更多组件参见 package.json
-* 编辑器:
- * [CodeMirror](https://codemirror.net)
- * [EasyMDE](https://github.com/Ionaru/easy-markdown-editor)
- * [Monaco Editor](https://microsoft.github.io/monaco-editor)
-* 数据库驱动:
- * [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
- * [github.com/lib/pq](https://github.com/lib/pq)
- * [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
- * [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
+- Web框架: [Chi](http://github.com/go-chi/chi)
+- ORM: [XORM](https://xorm.io)
+- UI 框架:
+ - [jQuery](https://jquery.com)
+ - [Fomantic UI](https://fomantic-ui.com)
+ - [Vue2](https://vuejs.org)
+ - 更多组件参见 package.json
+- 编辑器:
+ - [CodeMirror](https://codemirror.net)
+ - [EasyMDE](https://github.com/Ionaru/easy-markdown-editor)
+ - [Monaco Editor](https://microsoft.github.io/monaco-editor)
+- 数据库驱动:
+ - [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
+ - [github.com/lib/pq](https://github.com/lib/pq)
+ - [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
+ - [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
## 软件及服务支持
diff --git a/docs/content/page/index.zh-tw.md b/docs/content/page/index.zh-tw.md
index 0c67ef0b28a40..3dde97a9431e9 100644
--- a/docs/content/page/index.zh-tw.md
+++ b/docs/content/page/index.zh-tw.md
@@ -10,7 +10,7 @@ draft: false
# 關於 Gitea
-Gitea 是一個可自行託管的 Git 服務。你可以拿 GitHub、Bitbucket 或 Gitlab 來比較看看。
+Gitea 是一個可自行託管的 Git 服務。你可以拿 GitHub、Bitbucket 或 Gitlab 來比較看看。
Gitea 是從 [Gogs](http://gogs.io) Fork 出來的,請閱讀部落格文章 [Gitea 公告](https://blog.gitea.io/2016/12/welcome-to-gitea/)以了解我們 Fork 的理由。
## 目標
@@ -269,19 +269,18 @@ Gitea 是從 [Gogs](http://gogs.io) Fork 出來的,請閱讀部落格文章 [G
- Web 框架: [Chi](http://github.com/go-chi/chi)
- ORM: [XORM](https://xorm.io)
- UI 元件:
- * [jQuery](https://jquery.com)
- * [Fomantic UI](https://fomantic-ui.com)
- * [Vue2](https://vuejs.org)
- * [CodeMirror](https://codemirror.net)
- * [EasyMDE](https://github.com/Ionaru/easy-markdown-editor)
- * [Monaco Editor](https://microsoft.github.io/monaco-editor)
- * ... (package.json)
+ - [jQuery](https://jquery.com)
+ - [Fomantic UI](https://fomantic-ui.com)
+ - [Vue2](https://vuejs.org)
+ - [CodeMirror](https://codemirror.net)
+ - [EasyMDE](https://github.com/Ionaru/easy-markdown-editor)
+ - [Monaco Editor](https://microsoft.github.io/monaco-editor)
+ - ... (package.json)
- 資料庫驅動程式:
- * [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
- * [github.com/lib/pq](https://github.com/lib/pq)
- * [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
- * [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
-
+ - [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
+ - [github.com/lib/pq](https://github.com/lib/pq)
+ - [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
+ - [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
## 軟體和服務支援
diff --git a/go.mod b/go.mod
index 026c5723c38d7..6d41af507d351 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
gitea.com/go-chi/cache v0.2.0
gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5
gitea.com/go-chi/session v0.0.0-20211218221615-e3605d8b28b8
- gitea.com/lunny/levelqueue v0.4.1
+ gitea.com/lunny/levelqueue v0.4.2-0.20220729054728-f020868cc2f7
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
github.com/NYTimes/gziphandler v1.1.1
github.com/PuerkitoBio/goquery v1.8.0
@@ -104,7 +104,7 @@ require (
mvdan.cc/xurls/v2 v2.4.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
xorm.io/builder v0.3.11
- xorm.io/xorm v1.3.1
+ xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f
)
require (
diff --git a/go.sum b/go.sum
index 103206980776e..124e65a727ad9 100644
--- a/go.sum
+++ b/go.sum
@@ -80,8 +80,8 @@ gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5 h1:J/1i8u40TbcLP/w2w
gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5/go.mod h1:hQ9SYHKdOX968wJglb/NMQ+UqpOKwW4L+EYdvkWjHSo=
gitea.com/go-chi/session v0.0.0-20211218221615-e3605d8b28b8 h1:tJQRXgZigkLeeW9LPlps9G9aMoE6LAmqigLA+wxmd1Q=
gitea.com/go-chi/session v0.0.0-20211218221615-e3605d8b28b8/go.mod h1:fc/pjt5EqNKgqQXYzcas1Z5L5whkZHyOvTA7OzWVJck=
-gitea.com/lunny/levelqueue v0.4.1 h1:RZ+AFx5gBsZuyqCvofhAkPQ9uaVDPJnsULoJZIYaJNw=
-gitea.com/lunny/levelqueue v0.4.1/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU=
+gitea.com/lunny/levelqueue v0.4.2-0.20220729054728-f020868cc2f7 h1:Zc3RQWC2xOVglLciQH/ZIC5IqSk3Jn96LflGQLv18Rg=
+gitea.com/lunny/levelqueue v0.4.2-0.20220729054728-f020868cc2f7/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE=
@@ -2423,5 +2423,5 @@ strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.11 h1:naLkJitGyYW7ZZdncsh/JW+HF4HshmvTHTyUyPwJS00=
xorm.io/builder v0.3.11/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
-xorm.io/xorm v1.3.1 h1:z5egKrDoOLqZFhMjcGF4FBHiTmE5/feQoHclfhNidfM=
-xorm.io/xorm v1.3.1/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=
+xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f h1:3NvNsM4lnttTsHpk8ODHqrwN1MCEjsO3bD/rpd8A47k=
+xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=
diff --git a/integrations/admin_user_test.go b/integrations/admin_user_test.go
index 59adac7ecc65b..a2020652b747f 100644
--- a/integrations/admin_user_test.go
+++ b/integrations/admin_user_test.go
@@ -76,7 +76,7 @@ func TestAdminDeleteUser(t *testing.T) {
req := NewRequestWithValues(t, "POST", "/admin/users/8/delete", map[string]string{
"_csrf": csrf,
})
- session.MakeRequest(t, req, http.StatusOK)
+ session.MakeRequest(t, req, http.StatusSeeOther)
assertUserDeleted(t, 8)
unittest.CheckConsistencyFor(t, &user_model.User{})
diff --git a/integrations/api_issue_test.go b/integrations/api_issue_test.go
index 5c802e8d20df7..bb4e2f0c72dac 100644
--- a/integrations/api_issue_test.go
+++ b/integrations/api_issue_test.go
@@ -16,6 +16,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert"
@@ -171,19 +172,21 @@ func TestAPISearchIssues(t *testing.T) {
token := getUserToken(t, "user2")
+ // as this API was used in the frontend, it uses UI page size
+ expectedIssueCount := 15 // from the fixtures
+ if expectedIssueCount > setting.UI.IssuePagingNum {
+ expectedIssueCount = setting.UI.IssuePagingNum
+ }
+
link, _ := url.Parse("/api/v1/repos/issues/search")
- req := NewRequest(t, "GET", link.String()+"?token="+token)
- resp := MakeRequest(t, req, http.StatusOK)
+ query := url.Values{"token": {getUserToken(t, "user1")}}
var apiIssues []*api.Issue
- DecodeJSON(t, resp, &apiIssues)
- assert.Len(t, apiIssues, 10)
- query := url.Values{"token": {token}}
link.RawQuery = query.Encode()
- req = NewRequest(t, "GET", link.String())
- resp = MakeRequest(t, req, http.StatusOK)
+ req := NewRequest(t, "GET", link.String())
+ resp := MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
- assert.Len(t, apiIssues, 10)
+ assert.Len(t, apiIssues, expectedIssueCount)
since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801
before := time.Unix(999307200, 0).Format(time.RFC3339)
@@ -211,14 +214,15 @@ func TestAPISearchIssues(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
- assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit
+ assert.Len(t, apiIssues, 17)
- query.Add("limit", "20")
+ query.Add("limit", "10")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
- assert.Len(t, apiIssues, 17)
+ assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
+ assert.Len(t, apiIssues, 10)
query = url.Values{"assigned": {"true"}, "state": {"all"}, "token": {token}}
link.RawQuery = query.Encode()
@@ -266,23 +270,21 @@ func TestAPISearchIssues(t *testing.T) {
func TestAPISearchIssuesWithLabels(t *testing.T) {
defer prepareTestEnv(t)()
- token := getUserToken(t, "user1")
+ // as this API was used in the frontend, it uses UI page size
+ expectedIssueCount := 15 // from the fixtures
+ if expectedIssueCount > setting.UI.IssuePagingNum {
+ expectedIssueCount = setting.UI.IssuePagingNum
+ }
link, _ := url.Parse("/api/v1/repos/issues/search")
- req := NewRequest(t, "GET", link.String()+"?token="+token)
- resp := MakeRequest(t, req, http.StatusOK)
+ query := url.Values{"token": {getUserToken(t, "user1")}}
var apiIssues []*api.Issue
- DecodeJSON(t, resp, &apiIssues)
-
- assert.Len(t, apiIssues, 10)
- query := url.Values{}
- query.Add("token", token)
link.RawQuery = query.Encode()
- req = NewRequest(t, "GET", link.String())
- resp = MakeRequest(t, req, http.StatusOK)
+ req := NewRequest(t, "GET", link.String())
+ resp := MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
- assert.Len(t, apiIssues, 10)
+ assert.Len(t, apiIssues, expectedIssueCount)
query.Add("labels", "label1")
link.RawQuery = query.Encode()
diff --git a/integrations/api_packages_container_test.go b/integrations/api_packages_container_test.go
index 1ed80dfd02277..5e073f313f7ae 100644
--- a/integrations/api_packages_container_test.go
+++ b/integrations/api_packages_container_test.go
@@ -20,12 +20,14 @@ import (
container_module "code.gitea.io/gitea/modules/packages/container"
"code.gitea.io/gitea/modules/packages/container/oci"
"code.gitea.io/gitea/modules/setting"
+ api "code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert"
)
func TestPackageContainer(t *testing.T) {
defer prepareTestEnv(t)()
+
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
has := func(l packages_model.PackagePropertyList, name string) bool {
@@ -36,6 +38,15 @@ func TestPackageContainer(t *testing.T) {
}
return false
}
+ getAllByName := func(l packages_model.PackagePropertyList, name string) []string {
+ values := make([]string, 0, len(l))
+ for _, pp := range l {
+ if pp.Name == name {
+ values = append(values, pp.Value)
+ }
+ }
+ return values
+ }
images := []string{"test", "te/st"}
tags := []string{"latest", "main"}
@@ -66,7 +77,7 @@ func TestPackageContainer(t *testing.T) {
Token string `json:"token"`
}
- authenticate := []string{`Bearer realm="` + setting.AppURL + `v2/token"`}
+ authenticate := []string{`Bearer realm="` + setting.AppURL + `v2/token",service="container_registry",scope="*"`}
t.Run("Anonymous", func(t *testing.T) {
defer PrintCurrentTest(t)()
@@ -236,7 +247,8 @@ func TestPackageContainer(t *testing.T) {
assert.Nil(t, pd.SemVer)
assert.Equal(t, image, pd.Package.Name)
assert.Equal(t, tag, pd.Version.Version)
- assert.True(t, has(pd.Properties, container_module.PropertyManifestTagged))
+ assert.ElementsMatch(t, []string{strings.ToLower(user.LowerName + "/" + image)}, getAllByName(pd.PackageProperties, container_module.PropertyRepository))
+ assert.True(t, has(pd.VersionProperties, container_module.PropertyManifestTagged))
assert.IsType(t, &container_module.Metadata{}, pd.Metadata)
metadata := pd.Metadata.(*container_module.Metadata)
@@ -330,7 +342,8 @@ func TestPackageContainer(t *testing.T) {
assert.Nil(t, pd.SemVer)
assert.Equal(t, image, pd.Package.Name)
assert.Equal(t, untaggedManifestDigest, pd.Version.Version)
- assert.False(t, has(pd.Properties, container_module.PropertyManifestTagged))
+ assert.ElementsMatch(t, []string{strings.ToLower(user.LowerName + "/" + image)}, getAllByName(pd.PackageProperties, container_module.PropertyRepository))
+ assert.False(t, has(pd.VersionProperties, container_module.PropertyManifestTagged))
assert.IsType(t, &container_module.Metadata{}, pd.Metadata)
@@ -362,18 +375,10 @@ func TestPackageContainer(t *testing.T) {
assert.Nil(t, pd.SemVer)
assert.Equal(t, image, pd.Package.Name)
assert.Equal(t, multiTag, pd.Version.Version)
- assert.True(t, has(pd.Properties, container_module.PropertyManifestTagged))
+ assert.ElementsMatch(t, []string{strings.ToLower(user.LowerName + "/" + image)}, getAllByName(pd.PackageProperties, container_module.PropertyRepository))
+ assert.True(t, has(pd.VersionProperties, container_module.PropertyManifestTagged))
- getAllByName := func(l packages_model.PackagePropertyList, name string) []string {
- values := make([]string, 0, len(l))
- for _, pp := range l {
- if pp.Name == name {
- values = append(values, pp.Value)
- }
- }
- return values
- }
- assert.ElementsMatch(t, []string{manifestDigest, untaggedManifestDigest}, getAllByName(pd.Properties, container_module.PropertyManifestReference))
+ assert.ElementsMatch(t, []string{manifestDigest, untaggedManifestDigest}, getAllByName(pd.VersionProperties, container_module.PropertyManifestReference))
assert.IsType(t, &container_module.Metadata{}, pd.Metadata)
metadata := pd.Metadata.(*container_module.Metadata)
@@ -487,6 +492,13 @@ func TestPackageContainer(t *testing.T) {
assert.Equal(t, c.ExpectedTags, tagList.Tags)
assert.Equal(t, c.ExpectedLink, resp.Header().Get("Link"))
}
+
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s?type=container&q=%s", user.Name, image))
+ resp := MakeRequest(t, req, http.StatusOK)
+
+ var apiPackages []*api.Package
+ DecodeJSON(t, resp, &apiPackages)
+ assert.Len(t, apiPackages, 4) // "latest", "main", "multi", "sha256:..."
})
t.Run("Delete", func(t *testing.T) {
@@ -528,4 +540,56 @@ func TestPackageContainer(t *testing.T) {
})
})
}
+
+ t.Run("OwnerNameChange", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ checkCatalog := func(owner string) func(t *testing.T) {
+ return func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ req := NewRequest(t, "GET", fmt.Sprintf("%sv2/_catalog", setting.AppURL))
+ addTokenAuthHeader(req, userToken)
+ resp := MakeRequest(t, req, http.StatusOK)
+
+ type RepositoryList struct {
+ Repositories []string `json:"repositories"`
+ }
+
+ repoList := &RepositoryList{}
+ DecodeJSON(t, resp, &repoList)
+
+ assert.Len(t, repoList.Repositories, len(images))
+ names := make([]string, 0, len(images))
+ for _, image := range images {
+ names = append(names, strings.ToLower(owner+"/"+image))
+ }
+ assert.ElementsMatch(t, names, repoList.Repositories)
+ }
+ }
+
+ t.Run(fmt.Sprintf("Catalog[%s]", user.LowerName), checkCatalog(user.LowerName))
+
+ session := loginUser(t, user.Name)
+
+ newOwnerName := "newUsername"
+
+ req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
+ "_csrf": GetCSRF(t, session, "/user/settings"),
+ "name": newOwnerName,
+ "email": "user2@example.com",
+ "language": "en-US",
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+
+ t.Run(fmt.Sprintf("Catalog[%s]", newOwnerName), checkCatalog(newOwnerName))
+
+ req = NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
+ "_csrf": GetCSRF(t, session, "/user/settings"),
+ "name": user.Name,
+ "email": "user2@example.com",
+ "language": "en-US",
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+ })
}
diff --git a/integrations/api_packages_generic_test.go b/integrations/api_packages_generic_test.go
index c507702eaafd1..adaf99e981ae9 100644
--- a/integrations/api_packages_generic_test.go
+++ b/integrations/api_packages_generic_test.go
@@ -42,7 +42,6 @@ func TestPackageGeneric(t *testing.T) {
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
assert.NoError(t, err)
- assert.NotNil(t, pd.SemVer)
assert.Nil(t, pd.Metadata)
assert.Equal(t, packageName, pd.Package.Name)
assert.Equal(t, packageVersion, pd.Version.Version)
diff --git a/integrations/api_packages_maven_test.go b/integrations/api_packages_maven_test.go
index c7c45426859e7..e7ab3bfe4b640 100644
--- a/integrations/api_packages_maven_test.go
+++ b/integrations/api_packages_maven_test.go
@@ -42,6 +42,7 @@ func TestPackageMaven(t *testing.T) {
defer PrintCurrentTest(t)()
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusCreated)
+ putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusBadRequest)
putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
@@ -135,12 +136,14 @@ func TestPackageMaven(t *testing.T) {
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
assert.NoError(t, err)
assert.Len(t, pfs, 2)
- i := 0
- if strings.HasSuffix(pfs[1].Name, ".pom") {
- i = 1
+ for _, pf := range pfs {
+ if strings.HasSuffix(pf.Name, ".pom") {
+ assert.Equal(t, filename+".pom", pf.Name)
+ assert.True(t, pf.IsLead)
+ } else {
+ assert.False(t, pf.IsLead)
+ }
}
- assert.Equal(t, filename+".pom", pfs[i].Name)
- assert.True(t, pfs[i].IsLead)
})
t.Run("DownloadPOM", func(t *testing.T) {
@@ -202,4 +205,13 @@ func TestPackageMaven(t *testing.T) {
assert.Equal(t, checksum, resp.Body.String())
}
})
+
+ t.Run("UploadSnapshot", func(t *testing.T) {
+ snapshotVersion := packageVersion + "-SNAPSHOT"
+
+ putFile(t, fmt.Sprintf("/%s/%s", snapshotVersion, filename), "test", http.StatusCreated)
+ putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
+ putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test", http.StatusCreated)
+ putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test-overwrite", http.StatusCreated)
+ })
}
diff --git a/integrations/api_packages_npm_test.go b/integrations/api_packages_npm_test.go
index 28a3711939828..ad88ac5da6764 100644
--- a/integrations/api_packages_npm_test.go
+++ b/integrations/api_packages_npm_test.go
@@ -85,9 +85,9 @@ func TestPackageNpm(t *testing.T) {
assert.IsType(t, &npm.Metadata{}, pd.Metadata)
assert.Equal(t, packageName, pd.Package.Name)
assert.Equal(t, packageVersion, pd.Version.Version)
- assert.Len(t, pd.Properties, 1)
- assert.Equal(t, npm.TagProperty, pd.Properties[0].Name)
- assert.Equal(t, packageTag, pd.Properties[0].Value)
+ assert.Len(t, pd.VersionProperties, 1)
+ assert.Equal(t, npm.TagProperty, pd.VersionProperties[0].Name)
+ assert.Equal(t, packageTag, pd.VersionProperties[0].Value)
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
assert.NoError(t, err)
diff --git a/integrations/api_packages_nuget_test.go b/integrations/api_packages_nuget_test.go
index e69dd0ff9b669..346f391f82fcc 100644
--- a/integrations/api_packages_nuget_test.go
+++ b/integrations/api_packages_nuget_test.go
@@ -122,7 +122,7 @@ func TestPackageNuGet(t *testing.T) {
req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
req = AddBasicAuthHeader(req, user.Name)
- MakeRequest(t, req, http.StatusBadRequest)
+ MakeRequest(t, req, http.StatusConflict)
})
t.Run("SymbolPackage", func(t *testing.T) {
@@ -208,7 +208,7 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createPackage(packageName, "SymbolsPackage"))
req = AddBasicAuthHeader(req, user.Name)
- MakeRequest(t, req, http.StatusBadRequest)
+ MakeRequest(t, req, http.StatusConflict)
})
})
@@ -352,7 +352,7 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, packageVersion))
req = AddBasicAuthHeader(req, user.Name)
- MakeRequest(t, req, http.StatusOK)
+ MakeRequest(t, req, http.StatusNoContent)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
assert.NoError(t, err)
diff --git a/integrations/api_packages_pub_test.go b/integrations/api_packages_pub_test.go
new file mode 100644
index 0000000000000..d64f88def747a
--- /dev/null
+++ b/integrations/api_packages_pub_test.go
@@ -0,0 +1,179 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package integrations
+
+import (
+ "archive/tar"
+ "bytes"
+ "compress/gzip"
+ "fmt"
+ "io"
+ "mime/multipart"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+ "time"
+
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/models/packages"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ pub_module "code.gitea.io/gitea/modules/packages/pub"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestPackagePub(t *testing.T) {
+ defer prepareTestEnv(t)()
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+
+ token := "Bearer " + getUserToken(t, user.Name)
+
+ packageName := "test_package"
+ packageVersion := "1.0.1"
+ packageDescription := "Test Description"
+
+ filename := fmt.Sprintf("%s.tar.gz", packageVersion)
+
+ pubspecContent := `name: ` + packageName + `
+version: ` + packageVersion + `
+description: ` + packageDescription
+
+ var buf bytes.Buffer
+ zw := gzip.NewWriter(&buf)
+ archive := tar.NewWriter(zw)
+ archive.WriteHeader(&tar.Header{
+ Name: "pubspec.yaml",
+ Mode: 0o600,
+ Size: int64(len(pubspecContent)),
+ })
+ archive.Write([]byte(pubspecContent))
+ archive.Close()
+ zw.Close()
+ content := buf.Bytes()
+
+ root := fmt.Sprintf("/api/packages/%s/pub", user.Name)
+
+ t.Run("Upload", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ uploadURL := root + "/api/packages/versions/new"
+
+ req := NewRequest(t, "GET", uploadURL)
+ MakeRequest(t, req, http.StatusUnauthorized)
+
+ req = NewRequest(t, "GET", uploadURL)
+ addTokenAuthHeader(req, token)
+ resp := MakeRequest(t, req, http.StatusOK)
+
+ type UploadRequest struct {
+ URL string `json:"url"`
+ Fields map[string]string `json:"fields"`
+ }
+
+ var result UploadRequest
+ DecodeJSON(t, resp, &result)
+
+ assert.Empty(t, result.Fields)
+
+ uploadFile := func(t *testing.T, url string, content []byte, expectedStatus int) *httptest.ResponseRecorder {
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+ part, _ := writer.CreateFormFile("file", "dummy.tar.gz")
+ _, _ = io.Copy(part, bytes.NewReader(content))
+
+ _ = writer.Close()
+
+ req := NewRequestWithBody(t, "POST", url, body)
+ req.Header.Add("Content-Type", writer.FormDataContentType())
+ addTokenAuthHeader(req, token)
+ return MakeRequest(t, req, expectedStatus)
+ }
+
+ resp = uploadFile(t, result.URL, content, http.StatusNoContent)
+
+ req = NewRequest(t, "GET", resp.Header().Get("Location"))
+ addTokenAuthHeader(req, token)
+ MakeRequest(t, req, http.StatusOK)
+
+ pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypePub)
+ assert.NoError(t, err)
+ assert.Len(t, pvs, 1)
+
+ pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
+ assert.NoError(t, err)
+ assert.NotNil(t, pd.SemVer)
+ assert.IsType(t, &pub_module.Metadata{}, pd.Metadata)
+ assert.Equal(t, packageName, pd.Package.Name)
+ assert.Equal(t, packageVersion, pd.Version.Version)
+
+ pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
+ assert.NoError(t, err)
+ assert.Len(t, pfs, 1)
+ assert.Equal(t, filename, pfs[0].Name)
+ assert.True(t, pfs[0].IsLead)
+
+ pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
+ assert.NoError(t, err)
+ assert.Equal(t, int64(len(content)), pb.Size)
+
+ resp = uploadFile(t, result.URL, content, http.StatusBadRequest)
+ })
+
+ t.Run("Download", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ req := NewRequest(t, "GET", fmt.Sprintf("%s/api/packages/%s/%s", root, packageName, packageVersion))
+ resp := MakeRequest(t, req, http.StatusOK)
+
+ type VersionMetadata struct {
+ Version string `json:"version"`
+ ArchiveURL string `json:"archive_url"`
+ Published time.Time `json:"published"`
+ Pubspec interface{} `json:"pubspec,omitempty"`
+ }
+
+ var result VersionMetadata
+ DecodeJSON(t, resp, &result)
+
+ assert.Equal(t, packageVersion, result.Version)
+ assert.NotNil(t, result.Pubspec)
+
+ req = NewRequest(t, "GET", result.ArchiveURL)
+ resp = MakeRequest(t, req, http.StatusOK)
+
+ assert.Equal(t, content, resp.Body.Bytes())
+ })
+
+ t.Run("EnumeratePackageVersions", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ req := NewRequest(t, "GET", fmt.Sprintf("%s/api/packages/%s", root, packageName))
+ resp := MakeRequest(t, req, http.StatusOK)
+
+ type VersionMetadata struct {
+ Version string `json:"version"`
+ ArchiveURL string `json:"archive_url"`
+ Published time.Time `json:"published"`
+ Pubspec interface{} `json:"pubspec,omitempty"`
+ }
+
+ type PackageVersions struct {
+ Name string `json:"name"`
+ Latest *VersionMetadata `json:"latest"`
+ Versions []*VersionMetadata `json:"versions"`
+ }
+
+ var result PackageVersions
+ DecodeJSON(t, resp, &result)
+
+ assert.Equal(t, packageName, result.Name)
+ assert.NotNil(t, result.Latest)
+ assert.Len(t, result.Versions, 1)
+ assert.Equal(t, result.Latest.Version, result.Versions[0].Version)
+ assert.Equal(t, packageVersion, result.Latest.Version)
+ assert.NotNil(t, result.Latest.Pubspec)
+ })
+}
diff --git a/integrations/api_repo_file_create_test.go b/integrations/api_repo_file_create_test.go
index eb550f1d28d74..fd460ce5643fc 100644
--- a/integrations/api_repo_file_create_test.go
+++ b/integrations/api_repo_file_create_test.go
@@ -50,7 +50,7 @@ func getCreateFileOptions() api.CreateFileOptions {
}
}
-func getExpectedFileResponseForCreate(repoFullName, commitID, treePath string) *api.FileResponse {
+func getExpectedFileResponseForCreate(repoFullName, commitID, treePath, latestCommitSHA string) *api.FileResponse {
sha := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
encoding := "base64"
content := "VGhpcyBpcyBuZXcgdGV4dA=="
@@ -60,17 +60,18 @@ func getExpectedFileResponseForCreate(repoFullName, commitID, treePath string) *
downloadURL := setting.AppURL + repoFullName + "/raw/branch/master/" + treePath
return &api.FileResponse{
Content: &api.ContentsResponse{
- Name: filepath.Base(treePath),
- Path: treePath,
- SHA: sha,
- Size: 16,
- Type: "file",
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: filepath.Base(treePath),
+ Path: treePath,
+ SHA: sha,
+ LastCommitSHA: latestCommitSHA,
+ Size: 16,
+ Type: "file",
+ Encoding: &encoding,
+ Content: &content,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -170,7 +171,8 @@ func TestAPICreateFile(t *testing.T) {
resp := session.MakeRequest(t, req, http.StatusCreated)
gitRepo, _ := git.OpenRepository(stdCtx.Background(), repo1.RepoPath())
commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
- expectedFileResponse := getExpectedFileResponseForCreate("user2/repo1", commitID, treePath)
+ latestCommit, _ := gitRepo.GetCommitByPath(treePath)
+ expectedFileResponse := getExpectedFileResponseForCreate("user2/repo1", commitID, treePath, latestCommit.ID.String())
var fileResponse api.FileResponse
DecodeJSON(t, resp, &fileResponse)
assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
@@ -289,7 +291,8 @@ func TestAPICreateFile(t *testing.T) {
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "empty-repo"}).(*repo_model.Repository) // public repo
gitRepo, _ := git.OpenRepository(stdCtx.Background(), emptyRepo.RepoPath())
commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
- expectedFileResponse := getExpectedFileResponseForCreate("user2/empty-repo", commitID, treePath)
+ latestCommit, _ := gitRepo.GetCommitByPath(treePath)
+ expectedFileResponse := getExpectedFileResponseForCreate("user2/empty-repo", commitID, treePath, latestCommit.ID.String())
DecodeJSON(t, resp, &fileResponse)
assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
diff --git a/integrations/api_repo_file_update_test.go b/integrations/api_repo_file_update_test.go
index 0c9c0763f4671..e39d83e49e13d 100644
--- a/integrations/api_repo_file_update_test.go
+++ b/integrations/api_repo_file_update_test.go
@@ -48,7 +48,7 @@ func getUpdateFileOptions() *api.UpdateFileOptions {
}
}
-func getExpectedFileResponseForUpdate(commitID, treePath string) *api.FileResponse {
+func getExpectedFileResponseForUpdate(commitID, treePath, lastCommitSHA string) *api.FileResponse {
sha := "08bd14b2e2852529157324de9c226b3364e76136"
encoding := "base64"
content := "VGhpcyBpcyB1cGRhdGVkIHRleHQ="
@@ -58,17 +58,18 @@ func getExpectedFileResponseForUpdate(commitID, treePath string) *api.FileRespon
downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath
return &api.FileResponse{
Content: &api.ContentsResponse{
- Name: filepath.Base(treePath),
- Path: treePath,
- SHA: sha,
- Type: "file",
- Size: 20,
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: filepath.Base(treePath),
+ Path: treePath,
+ SHA: sha,
+ LastCommitSHA: lastCommitSHA,
+ Type: "file",
+ Size: 20,
+ Encoding: &encoding,
+ Content: &content,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -137,7 +138,8 @@ func TestAPIUpdateFile(t *testing.T) {
resp := session.MakeRequest(t, req, http.StatusOK)
gitRepo, _ := git.OpenRepository(stdCtx.Background(), repo1.RepoPath())
commitID, _ := gitRepo.GetBranchCommitID(updateFileOptions.NewBranchName)
- expectedFileResponse := getExpectedFileResponseForUpdate(commitID, treePath)
+ lasCommit, _ := gitRepo.GetCommitByPath(treePath)
+ expectedFileResponse := getExpectedFileResponseForUpdate(commitID, treePath, lasCommit.ID.String())
var fileResponse api.FileResponse
DecodeJSON(t, resp, &fileResponse)
assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
diff --git a/integrations/api_repo_get_contents_list_test.go b/integrations/api_repo_get_contents_list_test.go
index 42227a9c4b723..97b152bf1b34d 100644
--- a/integrations/api_repo_get_contents_list_test.go
+++ b/integrations/api_repo_get_contents_list_test.go
@@ -21,7 +21,7 @@ import (
"github.com/stretchr/testify/assert"
)
-func getExpectedContentsListResponseForContents(ref, refType string) []*api.ContentsResponse {
+func getExpectedContentsListResponseForContents(ref, refType, lastCommitSHA string) []*api.ContentsResponse {
treePath := "README.md"
sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=" + ref
@@ -30,15 +30,16 @@ func getExpectedContentsListResponseForContents(ref, refType string) []*api.Cont
downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath
return []*api.ContentsResponse{
{
- Name: filepath.Base(treePath),
- Path: treePath,
- SHA: sha,
- Type: "file",
- Size: 30,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: filepath.Base(treePath),
+ Path: treePath,
+ SHA: sha,
+ LastCommitSHA: lastCommitSHA,
+ Type: "file",
+ Size: 30,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -94,7 +95,9 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
var contentsListResponse []*api.ContentsResponse
DecodeJSON(t, resp, &contentsListResponse)
assert.NotNil(t, contentsListResponse)
- expectedContentsListResponse := getExpectedContentsListResponseForContents(ref, refType)
+ lastCommit, err := gitRepo.GetCommitByPath("README.md")
+ assert.NoError(t, err)
+ expectedContentsListResponse := getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
// No ref
@@ -103,17 +106,22 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsListResponse)
assert.NotNil(t, contentsListResponse)
- expectedContentsListResponse = getExpectedContentsListResponseForContents(repo1.DefaultBranch, refType)
+
+ expectedContentsListResponse = getExpectedContentsListResponseForContents(repo1.DefaultBranch, refType, lastCommit.ID.String())
assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
- // ref is the branch we created above in setup
+ // ref is the branch we created above in setup
ref = newBranch
refType = "branch"
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsListResponse)
assert.NotNil(t, contentsListResponse)
- expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType)
+ branchCommit, err := gitRepo.GetBranchCommit(ref)
+ assert.NoError(t, err)
+ lastCommit, err = branchCommit.GetCommitByPath("README.md")
+ assert.NoError(t, err)
+ expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
// ref is the new tag we created above in setup
@@ -123,7 +131,11 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsListResponse)
assert.NotNil(t, contentsListResponse)
- expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType)
+ tagCommit, err := gitRepo.GetTagCommit(ref)
+ assert.NoError(t, err)
+ lastCommit, err = tagCommit.GetCommitByPath("README.md")
+ assert.NoError(t, err)
+ expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
// ref is a commit
@@ -133,7 +145,7 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsListResponse)
assert.NotNil(t, contentsListResponse)
- expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType)
+ expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, commitID)
assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
// Test file contents a file with a bad ref
diff --git a/integrations/api_repo_get_contents_test.go b/integrations/api_repo_get_contents_test.go
index 67f2cb83625a0..56f5336b7bd94 100644
--- a/integrations/api_repo_get_contents_test.go
+++ b/integrations/api_repo_get_contents_test.go
@@ -20,7 +20,7 @@ import (
"github.com/stretchr/testify/assert"
)
-func getExpectedContentsResponseForContents(ref, refType string) *api.ContentsResponse {
+func getExpectedContentsResponseForContents(ref, refType, lastCommitSHA string) *api.ContentsResponse {
treePath := "README.md"
sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
encoding := "base64"
@@ -30,17 +30,18 @@ func getExpectedContentsResponseForContents(ref, refType string) *api.ContentsRe
gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha
downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath
return &api.ContentsResponse{
- Name: treePath,
- Path: treePath,
- SHA: sha,
- Type: "file",
- Size: 30,
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: treePath,
+ Path: treePath,
+ SHA: sha,
+ LastCommitSHA: lastCommitSHA,
+ Type: "file",
+ Size: 30,
+ Encoding: &encoding,
+ Content: &content,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -96,7 +97,8 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
var contentsResponse api.ContentsResponse
DecodeJSON(t, resp, &contentsResponse)
assert.NotNil(t, contentsResponse)
- expectedContentsResponse := getExpectedContentsResponseForContents(ref, refType)
+ lastCommit, _ := gitRepo.GetCommitByPath("README.md")
+ expectedContentsResponse := getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
// No ref
@@ -105,7 +107,7 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsResponse)
assert.NotNil(t, contentsResponse)
- expectedContentsResponse = getExpectedContentsResponseForContents(repo1.DefaultBranch, refType)
+ expectedContentsResponse = getExpectedContentsResponseForContents(repo1.DefaultBranch, refType, lastCommit.ID.String())
assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
// ref is the branch we created above in setup
@@ -115,7 +117,9 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsResponse)
assert.NotNil(t, contentsResponse)
- expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType)
+ branchCommit, _ := gitRepo.GetBranchCommit(ref)
+ lastCommit, _ = branchCommit.GetCommitByPath("README.md")
+ expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
// ref is the new tag we created above in setup
@@ -125,7 +129,9 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsResponse)
assert.NotNil(t, contentsResponse)
- expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType)
+ tagCommit, _ := gitRepo.GetTagCommit(ref)
+ lastCommit, _ = tagCommit.GetCommitByPath("README.md")
+ expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
// ref is a commit
@@ -135,7 +141,7 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsResponse)
assert.NotNil(t, contentsResponse)
- expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType)
+ expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, commitID)
assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
// Test file contents a file with a bad ref
diff --git a/integrations/api_repo_raw_test.go b/integrations/api_repo_raw_test.go
index 2a77d1ba630dc..258b409befb87 100644
--- a/integrations/api_repo_raw_test.go
+++ b/integrations/api_repo_raw_test.go
@@ -10,6 +10,8 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
+
+ "github.com/stretchr/testify/assert"
)
func TestAPIReposRaw(t *testing.T) {
@@ -25,9 +27,11 @@ func TestAPIReposRaw(t *testing.T) {
"65f1bf27bc3bf70f64657658635e66094edbcb4d", // Commit
} {
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md?token="+token, user.Name, ref)
- session.MakeRequest(t, req, http.StatusOK)
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ assert.EqualValues(t, "file", resp.Header().Get("x-gitea-object-type"))
}
// Test default branch
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md?token="+token, user.Name)
- session.MakeRequest(t, req, http.StatusOK)
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ assert.EqualValues(t, "file", resp.Header().Get("x-gitea-object-type"))
}
diff --git a/integrations/integration_test.go b/integrations/integration_test.go
index 8a43de7c45fa9..230f780175c9c 100644
--- a/integrations/integration_test.go
+++ b/integrations/integration_test.go
@@ -188,8 +188,13 @@ func initIntegrationTest() {
switch {
case setting.Database.UseMySQL:
- db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/",
- setting.Database.User, setting.Database.Passwd, setting.Database.Host))
+ connType := "tcp"
+ if len(setting.Database.Host) > 0 && setting.Database.Host[0] == '/' { // looks like a unix socket
+ connType = "unix"
+ }
+
+ db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@%s(%s)/",
+ setting.Database.User, setting.Database.Passwd, connType, setting.Database.Host))
defer db.Close()
if err != nil {
log.Fatal("sql.Open: %v", err)
diff --git a/integrations/issue_test.go b/integrations/issue_test.go
index 7d30d657f5589..e1d3b1b21e2af 100644
--- a/integrations/issue_test.go
+++ b/integrations/issue_test.go
@@ -356,17 +356,17 @@ func TestSearchIssues(t *testing.T) {
session := loginUser(t, "user2")
+ expectedIssueCount := 15 // from the fixtures
+ if expectedIssueCount > setting.UI.IssuePagingNum {
+ expectedIssueCount = setting.UI.IssuePagingNum
+ }
+
link, _ := url.Parse("/issues/search")
req := NewRequest(t, "GET", link.String())
resp := session.MakeRequest(t, req, http.StatusOK)
var apiIssues []*api.Issue
DecodeJSON(t, resp, &apiIssues)
- assert.Len(t, apiIssues, 10)
-
- req = NewRequest(t, "GET", link.String())
- resp = session.MakeRequest(t, req, http.StatusOK)
- DecodeJSON(t, resp, &apiIssues)
- assert.Len(t, apiIssues, 10)
+ assert.Len(t, apiIssues, expectedIssueCount)
since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801
before := time.Unix(999307200, 0).Format(time.RFC3339)
@@ -394,14 +394,15 @@ func TestSearchIssues(t *testing.T) {
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
- assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit
+ assert.Len(t, apiIssues, 17)
- query.Add("limit", "20")
+ query.Add("limit", "5")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
- assert.Len(t, apiIssues, 17)
+ assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
+ assert.Len(t, apiIssues, 5)
query = url.Values{"assigned": {"true"}, "state": {"all"}}
link.RawQuery = query.Encode()
@@ -449,29 +450,26 @@ func TestSearchIssues(t *testing.T) {
func TestSearchIssuesWithLabels(t *testing.T) {
defer prepareTestEnv(t)()
- token := getUserToken(t, "user1")
+ expectedIssueCount := 15 // from the fixtures
+ if expectedIssueCount > setting.UI.IssuePagingNum {
+ expectedIssueCount = setting.UI.IssuePagingNum
+ }
- link, _ := url.Parse("/api/v1/repos/issues/search?token=" + token)
- req := NewRequest(t, "GET", link.String())
- resp := MakeRequest(t, req, http.StatusOK)
+ session := loginUser(t, "user1")
+ link, _ := url.Parse("/issues/search")
+ query := url.Values{}
var apiIssues []*api.Issue
- DecodeJSON(t, resp, &apiIssues)
-
- assert.Len(t, apiIssues, 10)
- query := url.Values{
- "token": []string{token},
- }
link.RawQuery = query.Encode()
- req = NewRequest(t, "GET", link.String())
- resp = MakeRequest(t, req, http.StatusOK)
+ req := NewRequest(t, "GET", link.String())
+ resp := session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
- assert.Len(t, apiIssues, 10)
+ assert.Len(t, apiIssues, expectedIssueCount)
query.Add("labels", "label1")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
- resp = MakeRequest(t, req, http.StatusOK)
+ resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 2)
@@ -479,7 +477,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
query.Set("labels", "label1,label2")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
- resp = MakeRequest(t, req, http.StatusOK)
+ resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 2)
@@ -487,7 +485,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
query.Set("labels", "orglabel4")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
- resp = MakeRequest(t, req, http.StatusOK)
+ resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 1)
@@ -496,7 +494,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
query.Add("state", "all")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
- resp = MakeRequest(t, req, http.StatusOK)
+ resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 2)
@@ -504,7 +502,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
query.Set("labels", "label1,orglabel4")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
- resp = MakeRequest(t, req, http.StatusOK)
+ resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 2)
}
diff --git a/integrations/mirror_push_test.go b/integrations/mirror_push_test.go
index a73b69e7869dd..3a22b0075423b 100644
--- a/integrations/mirror_push_test.go
+++ b/integrations/mirror_push_test.go
@@ -13,6 +13,7 @@ import (
"testing"
"code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
@@ -47,7 +48,7 @@ func testMirrorPush(t *testing.T, u *url.URL) {
doCreatePushMirror(ctx, fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(ctx.Username), url.PathEscape(mirrorRepo.Name)), user.LowerName, userPassword)(t)
- mirrors, err := repo_model.GetPushMirrorsByRepoID(srcRepo.ID)
+ mirrors, _, err := repo_model.GetPushMirrorsByRepoID(db.DefaultContext, srcRepo.ID, db.ListOptions{})
assert.NoError(t, err)
assert.Len(t, mirrors, 1)
@@ -72,7 +73,7 @@ func testMirrorPush(t *testing.T, u *url.URL) {
// Cleanup
doRemovePushMirror(ctx, fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(ctx.Username), url.PathEscape(mirrorRepo.Name)), user.LowerName, userPassword, int(mirrors[0].ID))(t)
- mirrors, err = repo_model.GetPushMirrorsByRepoID(srcRepo.ID)
+ mirrors, _, err = repo_model.GetPushMirrorsByRepoID(db.DefaultContext, srcRepo.ID, db.ListOptions{})
assert.NoError(t, err)
assert.Len(t, mirrors, 0)
}
diff --git a/integrations/org_test.go b/integrations/org_test.go
index d755385726a55..d787e6f79100d 100644
--- a/integrations/org_test.go
+++ b/integrations/org_test.go
@@ -116,6 +116,24 @@ func TestPrivateOrg(t *testing.T) {
session.MakeRequest(t, req, http.StatusOK)
}
+func TestOrgMembers(t *testing.T) {
+ defer prepareTestEnv(t)()
+
+ // not logged in user
+ req := NewRequest(t, "GET", "/org/org25/members")
+ MakeRequest(t, req, http.StatusOK)
+
+ // org member
+ session := loginUser(t, "user24")
+ req = NewRequest(t, "GET", "/org/org25/members")
+ session.MakeRequest(t, req, http.StatusOK)
+
+ // site admin
+ session = loginUser(t, "user1")
+ req = NewRequest(t, "GET", "/org/org25/members")
+ session.MakeRequest(t, req, http.StatusOK)
+}
+
func TestOrgRestrictedUser(t *testing.T) {
defer prepareTestEnv(t)()
diff --git a/integrations/repofiles_update_test.go b/integrations/repofiles_update_test.go
index 2add99cc86ff9..ac9b0509eae40 100644
--- a/integrations/repofiles_update_test.go
+++ b/integrations/repofiles_update_test.go
@@ -47,7 +47,7 @@ func getUpdateRepoFileOptions(repo *repo_model.Repository) *files_service.Update
}
}
-func getExpectedFileResponseForRepofilesCreate(commitID string) *api.FileResponse {
+func getExpectedFileResponseForRepofilesCreate(commitID, lastCommitSHA string) *api.FileResponse {
treePath := "new/file.txt"
encoding := "base64"
content := "VGhpcyBpcyBhIE5FVyBmaWxl"
@@ -57,17 +57,18 @@ func getExpectedFileResponseForRepofilesCreate(commitID string) *api.FileRespons
downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath
return &api.FileResponse{
Content: &api.ContentsResponse{
- Name: filepath.Base(treePath),
- Path: treePath,
- SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
- Type: "file",
- Size: 18,
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: filepath.Base(treePath),
+ Path: treePath,
+ SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
+ LastCommitSHA: lastCommitSHA,
+ Type: "file",
+ Size: 18,
+ Encoding: &encoding,
+ Content: &content,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -115,7 +116,7 @@ func getExpectedFileResponseForRepofilesCreate(commitID string) *api.FileRespons
}
}
-func getExpectedFileResponseForRepofilesUpdate(commitID, filename string) *api.FileResponse {
+func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA string) *api.FileResponse {
encoding := "base64"
content := "VGhpcyBpcyBVUERBVEVEIGNvbnRlbnQgZm9yIHRoZSBSRUFETUUgZmlsZQ=="
selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + filename + "?ref=master"
@@ -124,17 +125,18 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename string) *api.F
downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + filename
return &api.FileResponse{
Content: &api.ContentsResponse{
- Name: filename,
- Path: filename,
- SHA: "dbf8d00e022e05b7e5cf7e535de857de57925647",
- Type: "file",
- Size: 43,
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: filename,
+ Path: filename,
+ SHA: "dbf8d00e022e05b7e5cf7e535de857de57925647",
+ LastCommitSHA: lastCommitSHA,
+ Type: "file",
+ Size: 43,
+ Encoding: &encoding,
+ Content: &content,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -206,7 +208,8 @@ func TestCreateOrUpdateRepoFileForCreate(t *testing.T) {
defer gitRepo.Close()
commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch)
- expectedFileResponse := getExpectedFileResponseForRepofilesCreate(commitID)
+ lastCommit, _ := gitRepo.GetCommitByPath("new/file.txt")
+ expectedFileResponse := getExpectedFileResponseForRepofilesCreate(commitID, lastCommit.ID.String())
assert.NotNil(t, expectedFileResponse)
if expectedFileResponse != nil {
assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
@@ -241,8 +244,9 @@ func TestCreateOrUpdateRepoFileForUpdate(t *testing.T) {
gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath())
defer gitRepo.Close()
- commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch)
- expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commitID, opts.TreePath)
+ commit, _ := gitRepo.GetBranchCommit(opts.NewBranch)
+ lastCommit, _ := commit.GetCommitByPath(opts.TreePath)
+ expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.TreePath, lastCommit.ID.String())
assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
@@ -277,7 +281,8 @@ func TestCreateOrUpdateRepoFileForUpdateWithFileMove(t *testing.T) {
defer gitRepo.Close()
commit, _ := gitRepo.GetBranchCommit(opts.NewBranch)
- expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.TreePath)
+ lastCommit, _ := commit.GetCommitByPath(opts.TreePath)
+ expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.TreePath, lastCommit.ID.String())
// assert that the old file no longer exists in the last commit of the branch
fromEntry, err := commit.GetTreeEntryByPath(opts.FromTreePath)
switch err.(type) {
@@ -326,8 +331,9 @@ func TestCreateOrUpdateRepoFileWithoutBranchNames(t *testing.T) {
gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath())
defer gitRepo.Close()
- commitID, _ := gitRepo.GetBranchCommitID(repo.DefaultBranch)
- expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commitID, opts.TreePath)
+ commit, _ := gitRepo.GetBranchCommit(repo.DefaultBranch)
+ lastCommit, _ := commit.GetCommitByPath(opts.TreePath)
+ expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.TreePath, lastCommit.ID.String())
assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
})
}
diff --git a/main.go b/main.go
index ac60f85a6680b..0e550f05ebca2 100644
--- a/main.go
+++ b/main.go
@@ -171,9 +171,9 @@ func setAppHelpTemplates() {
}
func adjustHelpTemplate(originalTemplate string) string {
- overrided := ""
+ overridden := ""
if _, ok := os.LookupEnv("GITEA_CUSTOM"); ok {
- overrided = "(GITEA_CUSTOM)"
+ overridden = "(GITEA_CUSTOM)"
}
return fmt.Sprintf(`%s
@@ -183,7 +183,7 @@ DEFAULT CONFIGURATION:
AppPath: %s
AppWorkPath: %s
-`, originalTemplate, setting.CustomPath, overrided, setting.CustomConf, setting.AppPath, setting.AppWorkPath)
+`, originalTemplate, setting.CustomPath, overridden, setting.CustomConf, setting.AppPath, setting.AppWorkPath)
}
func formatBuiltWith() string {
diff --git a/models/auth/webauthn.go b/models/auth/webauthn.go
index 2dc3043780101..d3062342f545b 100644
--- a/models/auth/webauthn.go
+++ b/models/auth/webauthn.go
@@ -6,7 +6,6 @@ package auth
import (
"context"
- "encoding/base32"
"fmt"
"strings"
@@ -20,14 +19,14 @@ import (
// ErrWebAuthnCredentialNotExist represents a "ErrWebAuthnCRedentialNotExist" kind of error.
type ErrWebAuthnCredentialNotExist struct {
ID int64
- CredentialID string
+ CredentialID []byte
}
func (err ErrWebAuthnCredentialNotExist) Error() string {
- if err.CredentialID == "" {
+ if len(err.CredentialID) == 0 {
return fmt.Sprintf("WebAuthn credential does not exist [id: %d]", err.ID)
}
- return fmt.Sprintf("WebAuthn credential does not exist [credential_id: %s]", err.CredentialID)
+ return fmt.Sprintf("WebAuthn credential does not exist [credential_id: %x]", err.CredentialID)
}
// IsErrWebAuthnCredentialNotExist checks if an error is a ErrWebAuthnCredentialNotExist.
@@ -43,7 +42,7 @@ type WebAuthnCredential struct {
Name string
LowerName string `xorm:"unique(s)"`
UserID int64 `xorm:"INDEX unique(s)"`
- CredentialID string `xorm:"INDEX VARCHAR(410)"`
+ CredentialID []byte `xorm:"INDEX VARBINARY(1024)"`
PublicKey []byte
AttestationType string
AAGUID []byte
@@ -94,9 +93,8 @@ type WebAuthnCredentialList []*WebAuthnCredential
func (list WebAuthnCredentialList) ToCredentials() []webauthn.Credential {
creds := make([]webauthn.Credential, 0, len(list))
for _, cred := range list {
- credID, _ := base32.HexEncoding.DecodeString(cred.CredentialID)
creds = append(creds, webauthn.Credential{
- ID: credID,
+ ID: cred.CredentialID,
PublicKey: cred.PublicKey,
AttestationType: cred.AttestationType,
Authenticator: webauthn.Authenticator{
@@ -164,11 +162,11 @@ func HasWebAuthnRegistrationsByUID(uid int64) (bool, error) {
}
// GetWebAuthnCredentialByCredID returns WebAuthn credential by credential ID
-func GetWebAuthnCredentialByCredID(userID int64, credID string) (*WebAuthnCredential, error) {
+func GetWebAuthnCredentialByCredID(userID int64, credID []byte) (*WebAuthnCredential, error) {
return getWebAuthnCredentialByCredID(db.DefaultContext, userID, credID)
}
-func getWebAuthnCredentialByCredID(ctx context.Context, userID int64, credID string) (*WebAuthnCredential, error) {
+func getWebAuthnCredentialByCredID(ctx context.Context, userID int64, credID []byte) (*WebAuthnCredential, error) {
cred := new(WebAuthnCredential)
if found, err := db.GetEngine(ctx).Where("user_id = ? AND credential_id = ?", userID, credID).Get(cred); err != nil {
return nil, err
@@ -187,7 +185,7 @@ func createCredential(ctx context.Context, userID int64, name string, cred *weba
c := &WebAuthnCredential{
UserID: userID,
Name: name,
- CredentialID: base32.HexEncoding.EncodeToString(cred.ID),
+ CredentialID: cred.ID,
PublicKey: cred.PublicKey,
AttestationType: cred.AttestationType,
AAGUID: cred.Authenticator.AAGUID,
diff --git a/models/auth/webauthn_test.go b/models/auth/webauthn_test.go
index 216bf110806eb..cc39691ce2d36 100644
--- a/models/auth/webauthn_test.go
+++ b/models/auth/webauthn_test.go
@@ -5,7 +5,6 @@
package auth
import (
- "encoding/base32"
"testing"
"code.gitea.io/gitea/models/unittest"
@@ -61,9 +60,7 @@ func TestCreateCredential(t *testing.T) {
res, err := CreateCredential(1, "WebAuthn Created Credential", &webauthn.Credential{ID: []byte("Test")})
assert.NoError(t, err)
assert.Equal(t, "WebAuthn Created Credential", res.Name)
- bs, err := base32.HexEncoding.DecodeString(res.CredentialID)
- assert.NoError(t, err)
- assert.Equal(t, []byte("Test"), bs)
+ assert.Equal(t, []byte("Test"), res.CredentialID)
unittest.AssertExistsIf(t, true, &WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1})
}
diff --git a/models/db/common.go b/models/db/common.go
new file mode 100644
index 0000000000000..1a59a8b5c697f
--- /dev/null
+++ b/models/db/common.go
@@ -0,0 +1,23 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package db
+
+import (
+ "strings"
+
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
+
+ "xorm.io/builder"
+)
+
+// BuildCaseInsensitiveLike returns a condition to check if the given value is like the given key case-insensitively.
+// Handles especially SQLite correctly as UPPER there only transforms ASCII letters.
+func BuildCaseInsensitiveLike(key, value string) builder.Cond {
+ if setting.Database.UseSQLite3 {
+ return builder.Like{"UPPER(" + key + ")", util.ToUpperASCII(value)}
+ }
+ return builder.Like{"UPPER(" + key + ")", strings.ToUpper(value)}
+}
diff --git a/models/issues/issue.go b/models/issues/issue.go
index 064f0d22abd01..5bdb60f7c08c5 100644
--- a/models/issues/issue.go
+++ b/models/issues/issue.go
@@ -27,7 +27,6 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/references"
- "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -1903,23 +1902,17 @@ func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen,
func SearchIssueIDsByKeyword(ctx context.Context, kw string, repoIDs []int64, limit, start int) (int64, []int64, error) {
repoCond := builder.In("repo_id", repoIDs)
subQuery := builder.Select("id").From("issue").Where(repoCond)
- // SQLite's UPPER function only transforms ASCII letters.
- if setting.Database.UseSQLite3 {
- kw = util.ToUpperASCII(kw)
- } else {
- kw = strings.ToUpper(kw)
- }
cond := builder.And(
repoCond,
builder.Or(
- builder.Like{"UPPER(name)", kw},
- builder.Like{"UPPER(content)", kw},
+ db.BuildCaseInsensitiveLike("name", kw),
+ db.BuildCaseInsensitiveLike("content", kw),
builder.In("id", builder.Select("issue_id").
From("comment").
Where(builder.And(
builder.Eq{"type": CommentTypeComment},
builder.In("issue_id", subQuery),
- builder.Like{"UPPER(content)", kw},
+ db.BuildCaseInsensitiveLike("content", kw),
)),
),
),
diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go
index 20e9949b66202..874f2a6368156 100644
--- a/models/issues/issue_list.go
+++ b/models/issues/issue_list.go
@@ -9,6 +9,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
+ project_model "code.gitea.io/gitea/models/project"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
@@ -222,6 +223,46 @@ func (issues IssueList) loadMilestones(ctx context.Context) error {
return nil
}
+func (issues IssueList) getProjectIDs() []int64 {
+ ids := make(map[int64]struct{}, len(issues))
+ for _, issue := range issues {
+ projectID := issue.ProjectID()
+ if _, ok := ids[projectID]; !ok {
+ ids[projectID] = struct{}{}
+ }
+ }
+ return container.KeysInt64(ids)
+}
+
+func (issues IssueList) loadProjects(ctx context.Context) error {
+ projectIDs := issues.getProjectIDs()
+ if len(projectIDs) == 0 {
+ return nil
+ }
+
+ projectMaps := make(map[int64]*project_model.Project, len(projectIDs))
+ left := len(projectIDs)
+ for left > 0 {
+ limit := db.DefaultMaxInSize
+ if left < limit {
+ limit = left
+ }
+ err := db.GetEngine(ctx).
+ In("id", projectIDs[:limit]).
+ Find(&projectMaps)
+ if err != nil {
+ return err
+ }
+ left -= limit
+ projectIDs = projectIDs[limit:]
+ }
+
+ for _, issue := range issues {
+ issue.Project = projectMaps[issue.ProjectID()]
+ }
+ return nil
+}
+
func (issues IssueList) loadAssignees(ctx context.Context) error {
if len(issues) == 0 {
return nil
@@ -242,7 +283,7 @@ func (issues IssueList) loadAssignees(ctx context.Context) error {
}
rows, err := db.GetEngine(ctx).Table("issue_assignees").
Join("INNER", "`user`", "`user`.id = `issue_assignees`.assignee_id").
- In("`issue_assignees`.issue_id", issueIDs[:limit]).
+ In("`issue_assignees`.issue_id", issueIDs[:limit]).OrderBy(user_model.GetOrderByName()).
Rows(new(AssigneeIssue))
if err != nil {
return err
@@ -495,6 +536,10 @@ func (issues IssueList) loadAttributes(ctx context.Context) error {
return fmt.Errorf("issue.loadAttributes: loadMilestones: %v", err)
}
+ if err := issues.loadProjects(ctx); err != nil {
+ return fmt.Errorf("issue.loadAttributes: loadProjects: %v", err)
+ }
+
if err := issues.loadAssignees(ctx); err != nil {
return fmt.Errorf("issue.loadAttributes: loadAssignees: %v", err)
}
diff --git a/models/issues/milestone.go b/models/issues/milestone.go
index c49799f391dc3..1021938b205ae 100644
--- a/models/issues/milestone.go
+++ b/models/issues/milestone.go
@@ -361,7 +361,7 @@ func (opts GetMilestonesOption) toCond() builder.Cond {
}
if len(opts.Name) != 0 {
- cond = cond.And(builder.Like{"UPPER(name)", strings.ToUpper(opts.Name)})
+ cond = cond.And(db.BuildCaseInsensitiveLike("name", opts.Name))
}
return cond
diff --git a/models/issues/review.go b/models/issues/review.go
index 1cb99dc3373ff..5835900801778 100644
--- a/models/issues/review.go
+++ b/models/issues/review.go
@@ -19,6 +19,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
+ "code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
@@ -474,6 +475,35 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co
return review, comm, committer.Commit()
}
+// GetReviewOptions represent filter options for GetReviews
+type GetReviewOptions struct {
+ IssueID int64
+ ReviewerID int64
+ Dismissed util.OptionalBool
+}
+
+// GetReviews return reviews based on GetReviewOptions
+func GetReviews(ctx context.Context, opts *GetReviewOptions) ([]*Review, error) {
+ if opts == nil {
+ return nil, fmt.Errorf("opts are nil")
+ }
+
+ sess := db.GetEngine(ctx)
+
+ if opts.IssueID != 0 {
+ sess = sess.Where("issue_id=?", opts.IssueID)
+ }
+ if opts.ReviewerID != 0 {
+ sess = sess.Where("reviewer_id=?", opts.ReviewerID)
+ }
+ if !opts.Dismissed.IsNone() {
+ sess = sess.Where("dismissed=?", opts.Dismissed.IsTrue())
+ }
+
+ reviews := make([]*Review, 0, 4)
+ return reviews, sess.Find(&reviews)
+}
+
// GetReviewersByIssueID gets the latest review of each reviewer for a pull request
func GetReviewersByIssueID(issueID int64) ([]*Review, error) {
reviews := make([]*Review, 0, 10)
diff --git a/models/migrations/fixtures/Test_storeWebauthnCredentialIDAsBytes/expected_webauthn_credential.yml b/models/migrations/fixtures/Test_storeWebauthnCredentialIDAsBytes/expected_webauthn_credential.yml
new file mode 100644
index 0000000000000..55a237a0d633d
--- /dev/null
+++ b/models/migrations/fixtures/Test_storeWebauthnCredentialIDAsBytes/expected_webauthn_credential.yml
@@ -0,0 +1,9 @@
+-
+ id: 1
+ credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG="
+-
+ id: 2
+ credential_id: "051CLMMKB62S6M9M2A4H54K7MMCQALFJ36G4TGB2S9A47APLTILU6C6744CEBG4EKCGV357N21BSLH8JD33GQMFAR6DQ70S76P34J6FR="
+-
+ id: 4
+ credential_id: "APU4B1NDTEVTEM60V4T0FRL7SRJMO9KIE2AKFQ8JDGTQ7VHFI41FDEFTDLBVQEAE4ER49QV2GTGVFDNBO31BPOA3OQN6879OT6MTU3G="
diff --git a/models/migrations/fixtures/Test_storeWebauthnCredentialIDAsBytes/webauthn_credential.yml b/models/migrations/fixtures/Test_storeWebauthnCredentialIDAsBytes/webauthn_credential.yml
new file mode 100644
index 0000000000000..c02a76e3742a9
--- /dev/null
+++ b/models/migrations/fixtures/Test_storeWebauthnCredentialIDAsBytes/webauthn_credential.yml
@@ -0,0 +1,31 @@
+-
+ id: 1
+ lower_name: "u2fkey-correctly-migrated"
+ name: "u2fkey-correctly-migrated"
+ user_id: 1
+ credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG="
+ public_key: 0x040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf2
+ attestation_type: 'fido-u2f'
+ sign_count: 1
+ clone_warning: false
+-
+ id: 2
+ lower_name: "non-u2f-key"
+ name: "non-u2f-key"
+ user_id: 1
+ credential_id: "051CLMMKB62S6M9M2A4H54K7MMCQALFJ36G4TGB2S9A47APLTILU6C6744CEBG4EKCGV357N21BSLH8JD33GQMFAR6DQ70S76P34J6FR"
+ public_key: 0x040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf2
+ attestation_type: 'none'
+ sign_count: 1
+ clone_warning: false
+-
+ id: 4
+ lower_name: "packed-key"
+ name: "packed-key"
+ user_id: 1
+ credential_id: "APU4B1NDTEVTEM60V4T0FRL7SRJMO9KIE2AKFQ8JDGTQ7VHFI41FDEFTDLBVQEAE4ER49QV2GTGVFDNBO31BPOA3OQN6879OT6MTU3G="
+ public_key: 0x040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf2
+ attestation_type: 'fido-u2f'
+ sign_count: 1
+ clone_warning: false
+
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 1b2a743b6d357..2719f45efbbbc 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -398,6 +398,14 @@ var migrations = []Migration{
NewMigration("Improve Action table indices v2", improveActionTableIndices),
// v219 -> v220
NewMigration("Add sync_on_commit column to push_mirror table", addSyncOnCommitColForPushMirror),
+ // v220 -> v221
+ NewMigration("Add container repository property", addContainerRepositoryProperty),
+ // v221 -> v222
+ NewMigration("Store WebAuthentication CredentialID as bytes and increase size to at least 1024", storeWebauthnCredentialIDAsBytes),
+ // v222 -> v223
+ NewMigration("Drop old CredentialID column", dropOldCredentialIDColumn),
+ // v223 -> v224
+ NewMigration("Rename CredentialIDBytes column to CredentialID", renameCredentialIDBytes),
}
// GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v219.go b/models/migrations/v219.go
index 7b2eaa3292704..7b4f34b704033 100644
--- a/models/migrations/v219.go
+++ b/models/migrations/v219.go
@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/timeutil"
+
"xorm.io/xorm"
)
diff --git a/models/migrations/v220.go b/models/migrations/v220.go
new file mode 100644
index 0000000000000..8138bc5bb1499
--- /dev/null
+++ b/models/migrations/v220.go
@@ -0,0 +1,28 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package migrations
+
+import (
+ packages_model "code.gitea.io/gitea/models/packages"
+ container_module "code.gitea.io/gitea/modules/packages/container"
+
+ "xorm.io/xorm"
+ "xorm.io/xorm/schemas"
+)
+
+func addContainerRepositoryProperty(x *xorm.Engine) (err error) {
+ switch x.Dialect().URI().DBType {
+ case schemas.SQLITE:
+ _, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name || '/' || p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?",
+ packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
+ case schemas.MSSQL:
+ _, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name + '/' + p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?",
+ packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
+ default:
+ _, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, CONCAT(u.lower_name, '/', p.lower_name) FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?",
+ packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
+ }
+ return err
+}
diff --git a/models/migrations/v221.go b/models/migrations/v221.go
new file mode 100644
index 0000000000000..f3bcfcdf1de20
--- /dev/null
+++ b/models/migrations/v221.go
@@ -0,0 +1,75 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package migrations
+
+import (
+ "encoding/base32"
+ "fmt"
+
+ "code.gitea.io/gitea/modules/timeutil"
+
+ "xorm.io/xorm"
+)
+
+func storeWebauthnCredentialIDAsBytes(x *xorm.Engine) error {
+ // Create webauthnCredential table
+ type webauthnCredential struct {
+ ID int64 `xorm:"pk autoincr"`
+ Name string
+ LowerName string `xorm:"unique(s)"`
+ UserID int64 `xorm:"INDEX unique(s)"`
+ CredentialID string `xorm:"INDEX VARCHAR(410)"`
+ // Note the lack of INDEX here - these will be created once the column is renamed in v223.go
+ CredentialIDBytes []byte `xorm:"VARBINARY(1024)"` // CredentialID is at most 1023 bytes as per spec released 20 July 2022
+ PublicKey []byte
+ AttestationType string
+ AAGUID []byte
+ SignCount uint32 `xorm:"BIGINT"`
+ CloneWarning bool
+ CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
+ UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
+ }
+ if err := x.Sync2(&webauthnCredential{}); err != nil {
+ return err
+ }
+
+ var start int
+ creds := make([]*webauthnCredential, 0, 50)
+ for {
+ err := x.Select("id, credential_id").OrderBy("id").Limit(50, start).Find(&creds)
+ if err != nil {
+ return err
+ }
+
+ err = func() error {
+ sess := x.NewSession()
+ defer sess.Close()
+ if err := sess.Begin(); err != nil {
+ return fmt.Errorf("unable to allow start session. Error: %w", err)
+ }
+ for _, cred := range creds {
+ cred.CredentialIDBytes, err = base32.HexEncoding.DecodeString(cred.CredentialID)
+ if err != nil {
+ return fmt.Errorf("unable to parse credential id %s for credential[%d]: %w", cred.CredentialID, cred.ID, err)
+ }
+ count, err := sess.ID(cred.ID).Cols("credential_id_bytes").Update(cred)
+ if count != 1 || err != nil {
+ return fmt.Errorf("unable to update credential id bytes for credential[%d]: %d,%w", cred.ID, count, err)
+ }
+ }
+ return sess.Commit()
+ }()
+ if err != nil {
+ return err
+ }
+
+ if len(creds) < 50 {
+ break
+ }
+ start += 50
+ creds = creds[:0]
+ }
+ return nil
+}
diff --git a/models/migrations/v221_test.go b/models/migrations/v221_test.go
new file mode 100644
index 0000000000000..c50ca5c873291
--- /dev/null
+++ b/models/migrations/v221_test.go
@@ -0,0 +1,65 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package migrations
+
+import (
+ "encoding/base32"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func Test_storeWebauthnCredentialIDAsBytes(t *testing.T) {
+ // Create webauthnCredential table
+ type WebauthnCredential struct {
+ ID int64 `xorm:"pk autoincr"`
+ Name string
+ LowerName string `xorm:"unique(s)"`
+ UserID int64 `xorm:"INDEX unique(s)"`
+ CredentialID string `xorm:"INDEX VARCHAR(410)"`
+ PublicKey []byte
+ AttestationType string
+ AAGUID []byte
+ SignCount uint32 `xorm:"BIGINT"`
+ CloneWarning bool
+ }
+
+ type ExpectedWebauthnCredential struct {
+ ID int64 `xorm:"pk autoincr"`
+ CredentialID string // CredentialID is at most 1023 bytes as per spec released 20 July 2022
+ }
+
+ type ConvertedWebauthnCredential struct {
+ ID int64 `xorm:"pk autoincr"`
+ CredentialIDBytes []byte `xorm:"VARBINARY(1024)"` // CredentialID is at most 1023 bytes as per spec released 20 July 2022
+ }
+
+ // Prepare and load the testing database
+ x, deferable := prepareTestEnv(t, 0, new(WebauthnCredential), new(ExpectedWebauthnCredential))
+ defer deferable()
+ if x == nil || t.Failed() {
+ return
+ }
+
+ if err := storeWebauthnCredentialIDAsBytes(x); err != nil {
+ assert.NoError(t, err)
+ return
+ }
+
+ expected := []ExpectedWebauthnCredential{}
+ if err := x.Table("expected_webauthn_credential").Asc("id").Find(&expected); !assert.NoError(t, err) {
+ return
+ }
+
+ got := []ConvertedWebauthnCredential{}
+ if err := x.Table("webauthn_credential").Select("id, credential_id_bytes").Asc("id").Find(&got); !assert.NoError(t, err) {
+ return
+ }
+
+ for i, e := range expected {
+ credIDBytes, _ := base32.HexEncoding.DecodeString(e.CredentialID)
+ assert.Equal(t, credIDBytes, got[i].CredentialIDBytes)
+ }
+}
diff --git a/models/migrations/v222.go b/models/migrations/v222.go
new file mode 100644
index 0000000000000..99acdfd20608a
--- /dev/null
+++ b/models/migrations/v222.go
@@ -0,0 +1,64 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package migrations
+
+import (
+ "context"
+ "fmt"
+
+ "code.gitea.io/gitea/modules/timeutil"
+
+ "xorm.io/xorm"
+)
+
+func dropOldCredentialIDColumn(x *xorm.Engine) error {
+ // This migration maybe rerun so that we should check if it has been run
+ credentialIDExist, err := x.Dialect().IsColumnExist(x.DB(), context.Background(), "webauthn_credential", "credential_id")
+ if err != nil {
+ return err
+ }
+ if !credentialIDExist {
+ // Column is already non-extant
+ return nil
+ }
+ credentialIDBytesExists, err := x.Dialect().IsColumnExist(x.DB(), context.Background(), "webauthn_credential", "credential_id_bytes")
+ if err != nil {
+ return err
+ }
+ if !credentialIDBytesExists {
+ // looks like 221 hasn't properly run
+ return fmt.Errorf("webauthn_credential does not have a credential_id_bytes column... it is not safe to run this migration")
+ }
+
+ // Create webauthnCredential table
+ type webauthnCredential struct {
+ ID int64 `xorm:"pk autoincr"`
+ Name string
+ LowerName string `xorm:"unique(s)"`
+ UserID int64 `xorm:"INDEX unique(s)"`
+ CredentialID string `xorm:"INDEX VARCHAR(410)"`
+ // Note the lack of the INDEX on CredentialIDBytes - we will add this in v223.go
+ CredentialIDBytes []byte `xorm:"VARBINARY(1024)"` // CredentialID is at most 1023 bytes as per spec released 20 July 2022
+ PublicKey []byte
+ AttestationType string
+ AAGUID []byte
+ SignCount uint32 `xorm:"BIGINT"`
+ CloneWarning bool
+ CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
+ UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
+ }
+ if err := x.Sync2(&webauthnCredential{}); err != nil {
+ return err
+ }
+
+ // Drop the old credential ID
+ sess := x.NewSession()
+ defer sess.Close()
+
+ if err := dropTableColumns(sess, "webauthn_credential", "credential_id"); err != nil {
+ return fmt.Errorf("unable to drop old credentialID column: %w", err)
+ }
+ return sess.Commit()
+}
diff --git a/models/migrations/v223.go b/models/migrations/v223.go
new file mode 100644
index 0000000000000..d7ee4812b8264
--- /dev/null
+++ b/models/migrations/v223.go
@@ -0,0 +1,103 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package migrations
+
+import (
+ "context"
+ "fmt"
+
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/timeutil"
+
+ "xorm.io/xorm"
+)
+
+func renameCredentialIDBytes(x *xorm.Engine) error {
+ // This migration maybe rerun so that we should check if it has been run
+ credentialIDExist, err := x.Dialect().IsColumnExist(x.DB(), context.Background(), "webauthn_credential", "credential_id")
+ if err != nil {
+ return err
+ }
+ if credentialIDExist {
+ credentialIDBytesExists, err := x.Dialect().IsColumnExist(x.DB(), context.Background(), "webauthn_credential", "credential_id_bytes")
+ if err != nil {
+ return err
+ }
+ if !credentialIDBytesExists {
+ return nil
+ }
+ }
+
+ err = func() error {
+ // webauthnCredential table
+ type webauthnCredential struct {
+ ID int64 `xorm:"pk autoincr"`
+ Name string
+ LowerName string `xorm:"unique(s)"`
+ UserID int64 `xorm:"INDEX unique(s)"`
+ // Note the lack of INDEX here
+ CredentialIDBytes []byte `xorm:"VARBINARY(1024)"` // CredentialID is at most 1023 bytes as per spec released 20 July 2022
+ PublicKey []byte
+ AttestationType string
+ AAGUID []byte
+ SignCount uint32 `xorm:"BIGINT"`
+ CloneWarning bool
+ CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
+ UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
+ }
+ sess := x.NewSession()
+ defer sess.Close()
+ if err := sess.Begin(); err != nil {
+ return err
+ }
+
+ if err := sess.Sync2(new(webauthnCredential)); err != nil {
+ return fmt.Errorf("error on Sync2: %v", err)
+ }
+
+ if credentialIDExist {
+ // if both errors and message exist, drop message at first
+ if err := dropTableColumns(sess, "webauthn_credential", "credential_id"); err != nil {
+ return err
+ }
+ }
+
+ switch {
+ case setting.Database.UseMySQL:
+ if _, err := sess.Exec("ALTER TABLE `webauthn_credential` CHANGE credential_id_bytes credential_id VARBINARY(1024)"); err != nil {
+ return err
+ }
+ case setting.Database.UseMSSQL:
+ if _, err := sess.Exec("sp_rename 'webauthn_credential.credential_id_bytes', 'credential_id', 'COLUMN'"); err != nil {
+ return err
+ }
+ default:
+ if _, err := sess.Exec("ALTER TABLE `webauthn_credential` RENAME COLUMN credential_id_bytes TO credential_id"); err != nil {
+ return err
+ }
+ }
+ return sess.Commit()
+ }()
+ if err != nil {
+ return err
+ }
+
+ // Create webauthnCredential table
+ type webauthnCredential struct {
+ ID int64 `xorm:"pk autoincr"`
+ Name string
+ LowerName string `xorm:"unique(s)"`
+ UserID int64 `xorm:"INDEX unique(s)"`
+ CredentialID []byte `xorm:"INDEX VARBINARY(1024)"` // CredentialID is at most 1023 bytes as per spec released 20 July 2022
+ PublicKey []byte
+ AttestationType string
+ AAGUID []byte
+ SignCount uint32 `xorm:"BIGINT"`
+ CloneWarning bool
+ CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
+ UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
+ }
+ return x.Sync2(&webauthnCredential{})
+}
diff --git a/models/organization/team_repo.go b/models/organization/team_repo.go
index fb3f267f817af..3ac4fa926b839 100644
--- a/models/organization/team_repo.go
+++ b/models/organization/team_repo.go
@@ -81,5 +81,6 @@ func GetTeamsWithAccessToRepo(ctx context.Context, orgID, repoID int64, mode per
Join("INNER", "team_repo", "team_repo.team_id = team.id").
And("team_repo.org_id = ?", orgID).
And("team_repo.repo_id = ?", repoID).
+ OrderBy("name").
Find(&teams)
}
diff --git a/models/packages/container/search.go b/models/packages/container/search.go
index 972cac9528f86..a3409fe743117 100644
--- a/models/packages/container/search.go
+++ b/models/packages/container/search.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/packages"
+ user_model "code.gitea.io/gitea/models/user"
container_module "code.gitea.io/gitea/modules/packages/container"
"xorm.io/builder"
@@ -210,6 +211,7 @@ func SearchImageTags(ctx context.Context, opts *ImageTagsSearchOptions) ([]*pack
return pvs, count, err
}
+// SearchExpiredUploadedBlobs gets all uploaded blobs which are older than specified
func SearchExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) ([]*packages.PackageFile, error) {
var cond builder.Cond = builder.Eq{
"package_version.is_internal": true,
@@ -225,3 +227,37 @@ func SearchExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) ([
Where(cond).
Find(&pfs)
}
+
+// GetRepositories gets a sorted list of all repositories
+func GetRepositories(ctx context.Context, actor *user_model.User, n int, last string) ([]string, error) {
+ var cond builder.Cond = builder.Eq{
+ "package.type": packages.TypeContainer,
+ "package_property.ref_type": packages.PropertyTypePackage,
+ "package_property.name": container_module.PropertyRepository,
+ }
+
+ cond = cond.And(builder.Exists(
+ builder.
+ Select("package_version.id").
+ Where(builder.Eq{"package_version.is_internal": false}.And(builder.Expr("package.id = package_version.package_id"))).
+ From("package_version"),
+ ))
+
+ if last != "" {
+ cond = cond.And(builder.Gt{"package_property.value": strings.ToLower(last)})
+ }
+
+ cond = cond.And(user_model.BuildCanSeeUserCondition(actor))
+
+ sess := db.GetEngine(ctx).
+ Table("package").
+ Select("package_property.value").
+ Join("INNER", "user", "`user`.id = package.owner_id").
+ Join("INNER", "package_property", "package_property.ref_id = package.id").
+ Where(cond).
+ Asc("package_property.value").
+ Limit(n)
+
+ repositories := make([]string, 0, n)
+ return repositories, sess.Find(&repositories)
+}
diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go
index fbdc40f37fbb2..dc753421d0210 100644
--- a/models/packages/descriptor.go
+++ b/models/packages/descriptor.go
@@ -19,6 +19,7 @@ import (
"code.gitea.io/gitea/modules/packages/maven"
"code.gitea.io/gitea/modules/packages/npm"
"code.gitea.io/gitea/modules/packages/nuget"
+ "code.gitea.io/gitea/modules/packages/pub"
"code.gitea.io/gitea/modules/packages/pypi"
"code.gitea.io/gitea/modules/packages/rubygems"
@@ -40,15 +41,16 @@ func (l PackagePropertyList) GetByName(name string) string {
// PackageDescriptor describes a package
type PackageDescriptor struct {
- Package *Package
- Owner *user_model.User
- Repository *repo_model.Repository
- Version *PackageVersion
- SemVer *version.Version
- Creator *user_model.User
- Properties PackagePropertyList
- Metadata interface{}
- Files []*PackageFileDescriptor
+ Package *Package
+ Owner *user_model.User
+ Repository *repo_model.Repository
+ Version *PackageVersion
+ SemVer *version.Version
+ Creator *user_model.User
+ PackageProperties PackagePropertyList
+ VersionProperties PackagePropertyList
+ Metadata interface{}
+ Files []*PackageFileDescriptor
}
// PackageFileDescriptor describes a package file
@@ -102,6 +104,10 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
return nil, err
}
}
+ pps, err := GetProperties(ctx, PropertyTypePackage, p.ID)
+ if err != nil {
+ return nil, err
+ }
pvps, err := GetProperties(ctx, PropertyTypeVersion, pv.ID)
if err != nil {
return nil, err
@@ -138,6 +144,8 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
metadata = &npm.Metadata{}
case TypeMaven:
metadata = &maven.Metadata{}
+ case TypePub:
+ metadata = &pub.Metadata{}
case TypePyPI:
metadata = &pypi.Metadata{}
case TypeRubyGems:
@@ -152,15 +160,16 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
}
return &PackageDescriptor{
- Package: p,
- Owner: o,
- Repository: repository,
- Version: pv,
- SemVer: semVer,
- Creator: creator,
- Properties: PackagePropertyList(pvps),
- Metadata: metadata,
- Files: pfds,
+ Package: p,
+ Owner: o,
+ Repository: repository,
+ Version: pv,
+ SemVer: semVer,
+ Creator: creator,
+ PackageProperties: PackagePropertyList(pps),
+ VersionProperties: PackagePropertyList(pvps),
+ Metadata: metadata,
+ Files: pfds,
}, nil
}
diff --git a/models/packages/package.go b/models/packages/package.go
index bdb535492bb40..39b1c83cfabf6 100644
--- a/models/packages/package.go
+++ b/models/packages/package.go
@@ -39,6 +39,7 @@ const (
TypeMaven Type = "maven"
TypeNpm Type = "npm"
TypeNuGet Type = "nuget"
+ TypePub Type = "pub"
TypePyPI Type = "pypi"
TypeRubyGems Type = "rubygems"
)
@@ -62,6 +63,8 @@ func (pt Type) Name() string {
return "npm"
case TypeNuGet:
return "NuGet"
+ case TypePub:
+ return "Pub"
case TypePyPI:
return "PyPI"
case TypeRubyGems:
@@ -89,6 +92,8 @@ func (pt Type) SVGName() string {
return "gitea-npm"
case TypeNuGet:
return "gitea-nuget"
+ case TypePub:
+ return "gitea-pub"
case TypePyPI:
return "gitea-python"
case TypeRubyGems:
@@ -131,6 +136,12 @@ func TryInsertPackage(ctx context.Context, p *Package) (*Package, error) {
return p, nil
}
+// DeletePackageByID deletes a package by id
+func DeletePackageByID(ctx context.Context, packageID int64) error {
+ _, err := db.GetEngine(ctx).ID(packageID).Delete(&Package{})
+ return err
+}
+
// SetRepositoryLink sets the linked repository
func SetRepositoryLink(ctx context.Context, packageID, repoID int64) error {
_, err := db.GetEngine(ctx).ID(packageID).Cols("repo_id").Update(&Package{RepoID: repoID})
@@ -192,21 +203,20 @@ func GetPackagesByType(ctx context.Context, ownerID int64, packageType Type) ([]
Find(&ps)
}
-// DeletePackagesIfUnreferenced deletes a package if there are no associated versions
-func DeletePackagesIfUnreferenced(ctx context.Context) error {
+// FindUnreferencedPackages gets all packages without associated versions
+func FindUnreferencedPackages(ctx context.Context) ([]*Package, error) {
in := builder.
Select("package.id").
From("package").
LeftJoin("package_version", "package_version.package_id = package.id").
Where(builder.Expr("package_version.id IS NULL"))
- _, err := db.GetEngine(ctx).
+ ps := make([]*Package, 0, 10)
+ return ps, db.GetEngine(ctx).
// double select workaround for MySQL
// https://stackoverflow.com/questions/4471277/mysql-delete-from-with-subquery-as-condition
Where(builder.In("package.id", builder.Select("id").From(in, "temp"))).
- Delete(&Package{})
-
- return err
+ Find(&ps)
}
// HasOwnerPackages tests if a user/org has packages
diff --git a/models/packages/package_property.go b/models/packages/package_property.go
index bf7dc346c6c97..fc10713801947 100644
--- a/models/packages/package_property.go
+++ b/models/packages/package_property.go
@@ -21,9 +21,11 @@ const (
PropertyTypeVersion PropertyType = iota // 0
// PropertyTypeFile means the reference is a package file
PropertyTypeFile // 1
+ // PropertyTypePackage means the reference is a package
+ PropertyTypePackage // 2
)
-// PackageProperty represents a property of a package version or file
+// PackageProperty represents a property of a package, version or file
type PackageProperty struct {
ID int64 `xorm:"pk autoincr"`
RefType PropertyType `xorm:"INDEX NOT NULL"`
@@ -68,3 +70,9 @@ func DeletePropertyByID(ctx context.Context, propertyID int64) error {
_, err := db.GetEngine(ctx).ID(propertyID).Delete(&PackageProperty{})
return err
}
+
+// DeletePropertyByName deletes properties by name
+func DeletePropertyByName(ctx context.Context, refType PropertyType, refID int64, name string) error {
+ _, err := db.GetEngine(ctx).Where("ref_type = ? AND ref_id = ? AND name = ?", refType, refID, name).Delete(&PackageProperty{})
+ return err
+}
diff --git a/models/packages/package_version.go b/models/packages/package_version.go
index 583f832e5eec8..5479bae1c29fc 100644
--- a/models/packages/package_version.go
+++ b/models/packages/package_version.go
@@ -107,7 +107,7 @@ func getVersionByNameAndVersion(ctx context.Context, ownerID int64, packageType
ExactMatch: true,
Value: version,
},
- IsInternal: isInternal,
+ IsInternal: util.OptionalBoolOf(isInternal),
Paginator: db.NewAbsoluteListOptions(0, 1),
})
if err != nil {
@@ -122,8 +122,9 @@ func getVersionByNameAndVersion(ctx context.Context, ownerID int64, packageType
// GetVersionsByPackageType gets all versions of a specific type
func GetVersionsByPackageType(ctx context.Context, ownerID int64, packageType Type) ([]*PackageVersion, error) {
pvs, _, err := SearchVersions(ctx, &PackageSearchOptions{
- OwnerID: ownerID,
- Type: packageType,
+ OwnerID: ownerID,
+ Type: packageType,
+ IsInternal: util.OptionalBoolFalse,
})
return pvs, err
}
@@ -137,6 +138,7 @@ func GetVersionsByPackageName(ctx context.Context, ownerID int64, packageType Ty
ExactMatch: true,
Value: name,
},
+ IsInternal: util.OptionalBoolFalse,
})
return pvs, err
}
@@ -171,7 +173,7 @@ type PackageSearchOptions struct {
Name SearchValue // only results with the specific name are found
Version SearchValue // only results with the specific version are found
Properties map[string]string // only results are found which contain all listed version properties with the specific value
- IsInternal bool
+ IsInternal util.OptionalBool
HasFileWithName string // only results are found which are associated with a file with the specific name
HasFiles util.OptionalBool // only results are found which have associated files
Sort string
@@ -179,7 +181,10 @@ type PackageSearchOptions struct {
}
func (opts *PackageSearchOptions) toConds() builder.Cond {
- var cond builder.Cond = builder.Eq{"package_version.is_internal": opts.IsInternal}
+ cond := builder.NewCond()
+ if !opts.IsInternal.IsNone() {
+ cond = builder.Eq{"package_version.is_internal": opts.IsInternal.IsTrue()}
+ }
if opts.OwnerID != 0 {
cond = cond.And(builder.Eq{"package.owner_id": opts.OwnerID})
diff --git a/models/project/project.go b/models/project/project.go
index 0aa37cc5c9071..86a77947d8838 100644
--- a/models/project/project.go
+++ b/models/project/project.go
@@ -330,3 +330,40 @@ func DeleteProjectByIDCtx(ctx context.Context, id int64) error {
return updateRepositoryProjectCount(ctx, p.RepoID)
}
+
+func DeleteProjectByRepoIDCtx(ctx context.Context, repoID int64) error {
+ switch {
+ case setting.Database.UseSQLite3:
+ if _, err := db.GetEngine(ctx).Exec("DELETE FROM project_issue WHERE project_issue.id IN (SELECT project_issue.id FROM project_issue INNER JOIN project WHERE project.id = project_issue.project_id AND project.repo_id = ?)", repoID); err != nil {
+ return err
+ }
+ if _, err := db.GetEngine(ctx).Exec("DELETE FROM project_board WHERE project_board.id IN (SELECT project_board.id FROM project_board INNER JOIN project WHERE project.id = project_board.project_id AND project.repo_id = ?)", repoID); err != nil {
+ return err
+ }
+ if _, err := db.GetEngine(ctx).Table("project").Where("repo_id = ? ", repoID).Delete(&Project{}); err != nil {
+ return err
+ }
+ case setting.Database.UsePostgreSQL:
+ if _, err := db.GetEngine(ctx).Exec("DELETE FROM project_issue USING project WHERE project.id = project_issue.project_id AND project.repo_id = ? ", repoID); err != nil {
+ return err
+ }
+ if _, err := db.GetEngine(ctx).Exec("DELETE FROM project_board USING project WHERE project.id = project_board.project_id AND project.repo_id = ? ", repoID); err != nil {
+ return err
+ }
+ if _, err := db.GetEngine(ctx).Table("project").Where("repo_id = ? ", repoID).Delete(&Project{}); err != nil {
+ return err
+ }
+ default:
+ if _, err := db.GetEngine(ctx).Exec("DELETE project_issue FROM project_issue INNER JOIN project ON project.id = project_issue.project_id WHERE project.repo_id = ? ", repoID); err != nil {
+ return err
+ }
+ if _, err := db.GetEngine(ctx).Exec("DELETE project_board FROM project_board INNER JOIN project ON project.id = project_board.project_id WHERE project.repo_id = ? ", repoID); err != nil {
+ return err
+ }
+ if _, err := db.GetEngine(ctx).Table("project").Where("repo_id = ? ", repoID).Delete(&Project{}); err != nil {
+ return err
+ }
+ }
+
+ return updateRepositoryProjectCount(ctx, repoID)
+}
diff --git a/models/repo.go b/models/repo.go
index ca83b03e42ca1..66ef51473950f 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -342,16 +342,8 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
}
}
- projects, _, err := project_model.GetProjects(ctx, project_model.SearchOptions{
- RepoID: repoID,
- })
- if err != nil {
- return fmt.Errorf("get projects: %v", err)
- }
- for i := range projects {
- if err := project_model.DeleteProjectByIDCtx(ctx, projects[i].ID); err != nil {
- return fmt.Errorf("delete project [%d]: %v", projects[i].ID, err)
- }
+ if err := project_model.DeleteProjectByRepoIDCtx(ctx, repoID); err != nil {
+ return fmt.Errorf("unable to delete projects for repo[%d]: %v", repoID, err)
}
// Remove LFS objects
diff --git a/models/repo/pushmirror.go b/models/repo/pushmirror.go
index 0a7dea79c93b3..02ffcbee76a50 100644
--- a/models/repo/pushmirror.go
+++ b/models/repo/pushmirror.go
@@ -5,12 +5,15 @@
package repo
import (
+ "context"
"errors"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
+
+ "xorm.io/builder"
)
// ErrPushMirrorNotExist mirror does not exist error
@@ -29,6 +32,25 @@ type PushMirror struct {
LastUpdateUnix timeutil.TimeStamp `xorm:"INDEX last_update"`
LastError string `xorm:"text"`
}
+type PushMirrorOptions struct {
+ ID int64
+ RepoID int64
+ RemoteName string
+}
+
+func (opts *PushMirrorOptions) toConds() builder.Cond {
+ cond := builder.NewCond()
+ if opts.RepoID > 0 {
+ cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
+ }
+ if opts.RemoteName != "" {
+ cond = cond.And(builder.Eq{"remote_name": opts.RemoteName})
+ }
+ if opts.ID > 0 {
+ cond = cond.And(builder.Eq{"id": opts.ID})
+ }
+ return cond
+}
func init() {
db.RegisterModel(new(PushMirror))
@@ -53,45 +75,48 @@ func (m *PushMirror) GetRemoteName() string {
}
// InsertPushMirror inserts a push-mirror to database
-func InsertPushMirror(m *PushMirror) error {
- _, err := db.GetEngine(db.DefaultContext).Insert(m)
+func InsertPushMirror(ctx context.Context, m *PushMirror) error {
+ _, err := db.GetEngine(ctx).Insert(m)
return err
}
// UpdatePushMirror updates the push-mirror
-func UpdatePushMirror(m *PushMirror) error {
- _, err := db.GetEngine(db.DefaultContext).ID(m.ID).AllCols().Update(m)
- return err
-}
-
-// DeletePushMirrorByID deletes a push-mirrors by ID
-func DeletePushMirrorByID(ID int64) error {
- _, err := db.GetEngine(db.DefaultContext).ID(ID).Delete(&PushMirror{})
+func UpdatePushMirror(ctx context.Context, m *PushMirror) error {
+ _, err := db.GetEngine(ctx).ID(m.ID).AllCols().Update(m)
return err
}
-// DeletePushMirrorsByRepoID deletes all push-mirrors by repoID
-func DeletePushMirrorsByRepoID(repoID int64) error {
- _, err := db.GetEngine(db.DefaultContext).Delete(&PushMirror{RepoID: repoID})
- return err
+func DeletePushMirrors(ctx context.Context, opts PushMirrorOptions) error {
+ if opts.RepoID > 0 {
+ _, err := db.GetEngine(ctx).Where(opts.toConds()).Delete(&PushMirror{})
+ return err
+ }
+ return errors.New("repoID required and must be set")
}
-// GetPushMirrorByID returns push-mirror information.
-func GetPushMirrorByID(ID int64) (*PushMirror, error) {
- m := &PushMirror{}
- has, err := db.GetEngine(db.DefaultContext).ID(ID).Get(m)
+func GetPushMirror(ctx context.Context, opts PushMirrorOptions) (*PushMirror, error) {
+ mirror := &PushMirror{}
+ exist, err := db.GetEngine(ctx).Where(opts.toConds()).Get(mirror)
if err != nil {
return nil, err
- } else if !has {
+ } else if !exist {
return nil, ErrPushMirrorNotExist
}
- return m, nil
+ return mirror, nil
}
// GetPushMirrorsByRepoID returns push-mirror information of a repository.
-func GetPushMirrorsByRepoID(repoID int64) ([]*PushMirror, error) {
+func GetPushMirrorsByRepoID(ctx context.Context, repoID int64, listOptions db.ListOptions) ([]*PushMirror, int64, error) {
+ sess := db.GetEngine(ctx).Where("repo_id = ?", repoID)
+ if listOptions.Page != 0 {
+ sess = db.SetSessionPagination(sess, &listOptions)
+ mirrors := make([]*PushMirror, 0, listOptions.PageSize)
+ count, err := sess.FindAndCount(&mirrors)
+ return mirrors, count, err
+ }
mirrors := make([]*PushMirror, 0, 10)
- return mirrors, db.GetEngine(db.DefaultContext).Where("repo_id=?", repoID).Find(&mirrors)
+ count, err := sess.FindAndCount(&mirrors)
+ return mirrors, count, err
}
// GetPushMirrorsSyncedOnCommit returns push-mirrors for this repo that should be updated by new commits
@@ -103,8 +128,8 @@ func GetPushMirrorsSyncedOnCommit(repoID int64) ([]*PushMirror, error) {
}
// PushMirrorsIterate iterates all push-mirror repositories.
-func PushMirrorsIterate(limit int, f func(idx int, bean interface{}) error) error {
- return db.GetEngine(db.DefaultContext).
+func PushMirrorsIterate(ctx context.Context, limit int, f func(idx int, bean interface{}) error) error {
+ return db.GetEngine(ctx).
Where("last_update + (`interval` / ?) <= ?", time.Second, time.Now().Unix()).
And("`interval` != 0").
OrderBy("last_update ASC").
diff --git a/models/repo/pushmirror_test.go b/models/repo/pushmirror_test.go
index d36a48547e1c6..5087e30095773 100644
--- a/models/repo/pushmirror_test.go
+++ b/models/repo/pushmirror_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"time"
+ "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/timeutil"
@@ -20,20 +21,20 @@ func TestPushMirrorsIterate(t *testing.T) {
now := timeutil.TimeStampNow()
- repo_model.InsertPushMirror(&repo_model.PushMirror{
+ repo_model.InsertPushMirror(db.DefaultContext, &repo_model.PushMirror{
RemoteName: "test-1",
LastUpdateUnix: now,
Interval: 1,
})
long, _ := time.ParseDuration("24h")
- repo_model.InsertPushMirror(&repo_model.PushMirror{
+ repo_model.InsertPushMirror(db.DefaultContext, &repo_model.PushMirror{
RemoteName: "test-2",
LastUpdateUnix: now,
Interval: long,
})
- repo_model.InsertPushMirror(&repo_model.PushMirror{
+ repo_model.InsertPushMirror(db.DefaultContext, &repo_model.PushMirror{
RemoteName: "test-3",
LastUpdateUnix: now,
Interval: 0,
@@ -41,7 +42,7 @@ func TestPushMirrorsIterate(t *testing.T) {
time.Sleep(1 * time.Millisecond)
- repo_model.PushMirrorsIterate(1, func(idx int, bean interface{}) error {
+ repo_model.PushMirrorsIterate(db.DefaultContext, 1, func(idx int, bean interface{}) error {
m, ok := bean.(*repo_model.PushMirror)
assert.True(t, ok)
assert.Equal(t, "test-1", m.RemoteName)
diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go
index a70fc8efd409a..9de76fa5ffa14 100644
--- a/models/repo/repo_list.go
+++ b/models/repo/repo_list.go
@@ -6,6 +6,7 @@ package repo
import (
"context"
+ "errors"
"fmt"
"strings"
@@ -695,6 +696,9 @@ func GetUserRepositories(opts *SearchRepoOptions) (RepositoryList, int64, error)
}
cond := builder.NewCond()
+ if opts.Actor == nil {
+ return nil, 0, errors.New("GetUserRepositories: Actor is needed but not given")
+ }
cond = cond.And(builder.Eq{"owner_id": opts.Actor.ID})
if !opts.Private {
cond = cond.And(builder.Eq{"is_private": false})
diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go
index e697505b81e4e..71e0c57550c56 100644
--- a/models/repo/user_repo.go
+++ b/models/repo/user_repo.go
@@ -109,7 +109,7 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
// and just waste 1 unit is cheaper than re-allocate memory once.
users := make([]*user_model.User, 0, len(userIDs)+1)
if len(userIDs) > 0 {
- if err = e.In("id", userIDs).Find(&users); err != nil {
+ if err = e.In("id", userIDs).OrderBy(user_model.GetOrderByName()).Find(&users); err != nil {
return nil, err
}
}
@@ -168,5 +168,5 @@ func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64)
}
users := make([]*user_model.User, 0, 8)
- return users, db.GetEngine(ctx).Where(cond).OrderBy("name").Find(&users)
+ return users, db.GetEngine(ctx).Where(cond).OrderBy(user_model.GetOrderByName()).Find(&users)
}
diff --git a/models/user.go b/models/user.go
index 49374014aa7db..86a714e746bb2 100644
--- a/models/user.go
+++ b/models/user.go
@@ -27,7 +27,7 @@ import (
)
// DeleteUser deletes models associated to an user.
-func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
+func DeleteUser(ctx context.Context, u *user_model.User, purge bool) (err error) {
e := db.GetEngine(ctx)
// ***** START: Watch *****
@@ -95,8 +95,8 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
return err
}
- if setting.Service.UserDeleteWithCommentsMaxTime != 0 &&
- u.CreatedUnix.AsTime().Add(setting.Service.UserDeleteWithCommentsMaxTime).After(time.Now()) {
+ if purge || (setting.Service.UserDeleteWithCommentsMaxTime != 0 &&
+ u.CreatedUnix.AsTime().Add(setting.Service.UserDeleteWithCommentsMaxTime).After(time.Now())) {
// Delete Comments
const batchSize = 50
diff --git a/models/user/search.go b/models/user/search.go
index 1b65dcb12d46c..f8e6c89f06804 100644
--- a/models/user/search.go
+++ b/models/user/search.go
@@ -58,31 +58,7 @@ func (opts *SearchUserOptions) toSearchQueryBase() *xorm.Session {
cond = cond.And(builder.In("visibility", opts.Visible))
}
- if opts.Actor != nil {
- exprCond := builder.Expr("org_user.org_id = `user`.id")
-
- // If Admin - they see all users!
- if !opts.Actor.IsAdmin {
- // Force visibility for privacy
- var accessCond builder.Cond
- if !opts.Actor.IsRestricted {
- accessCond = builder.Or(
- builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID}, builder.Eq{"visibility": structs.VisibleTypePrivate}))),
- builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited))
- } else {
- // restricted users only see orgs they are a member of
- accessCond = builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID})))
- }
- // Don't forget about self
- accessCond = accessCond.Or(builder.Eq{"id": opts.Actor.ID})
- cond = cond.And(accessCond)
- }
-
- } else {
- // Force visibility for privacy
- // Not logged in - only public users
- cond = cond.And(builder.In("visibility", structs.VisibleTypePublic))
- }
+ cond = cond.And(BuildCanSeeUserCondition(opts.Actor))
if opts.UID > 0 {
cond = cond.And(builder.Eq{"id": opts.UID})
@@ -170,3 +146,26 @@ func IterateUser(f func(user *User) error) error {
}
}
}
+
+// BuildCanSeeUserCondition creates a condition which can be used to restrict results to users/orgs the actor can see
+func BuildCanSeeUserCondition(actor *User) builder.Cond {
+ if actor != nil {
+ // If Admin - they see all users!
+ if !actor.IsAdmin {
+ // Users can see an organization they are a member of
+ cond := builder.In("`user`.id", builder.Select("org_id").From("org_user").Where(builder.Eq{"uid": actor.ID}))
+ if !actor.IsRestricted {
+ // Not-Restricted users can see public and limited users/organizations
+ cond = cond.Or(builder.In("`user`.visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited))
+ }
+ // Don't forget about self
+ return cond.Or(builder.Eq{"`user`.id": actor.ID})
+ }
+
+ return nil
+ }
+
+ // Force visibility for privacy
+ // Not logged in - only public users
+ return builder.In("`user`.visibility", structs.VisibleTypePublic)
+}
diff --git a/models/user/user.go b/models/user/user.go
index 125c643f3ee88..91eeeb8962526 100644
--- a/models/user/user.go
+++ b/models/user/user.go
@@ -64,12 +64,14 @@ var AvailableHashAlgorithms = []string{
}
const (
- // EmailNotificationsEnabled indicates that the user would like to receive all email notifications
+ // EmailNotificationsEnabled indicates that the user would like to receive all email notifications except your own
EmailNotificationsEnabled = "enabled"
// EmailNotificationsOnMention indicates that the user would like to be notified via email when mentioned.
EmailNotificationsOnMention = "onmention"
// EmailNotificationsDisabled indicates that the user would not like to be notified via email.
EmailNotificationsDisabled = "disabled"
+ // EmailNotificationsEnabled indicates that the user would like to receive all email notifications and your own
+ EmailNotificationsAndYourOwn = "andyourown"
)
// User represents the object of individual and member of organization.
@@ -1045,7 +1047,7 @@ func GetMaileableUsersByIDs(ids []int64, isMention bool) ([]*User, error) {
Where("`type` = ?", UserTypeIndividual).
And("`prohibit_login` = ?", false).
And("`is_active` = ?", true).
- And("`email_notifications_preference` IN ( ?, ?)", EmailNotificationsEnabled, EmailNotificationsOnMention).
+ In("`email_notifications_preference`", EmailNotificationsEnabled, EmailNotificationsOnMention, EmailNotificationsAndYourOwn).
Find(&ous)
}
@@ -1053,7 +1055,7 @@ func GetMaileableUsersByIDs(ids []int64, isMention bool) ([]*User, error) {
Where("`type` = ?", UserTypeIndividual).
And("`prohibit_login` = ?", false).
And("`is_active` = ?", true).
- And("`email_notifications_preference` = ?", EmailNotificationsEnabled).
+ In("`email_notifications_preference`", EmailNotificationsEnabled, EmailNotificationsAndYourOwn).
Find(&ous)
}
@@ -1314,3 +1316,10 @@ func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
}
return false
}
+
+func GetOrderByName() string {
+ if setting.UI.DefaultShowFullName {
+ return "full_name, name"
+ }
+ return "name"
+}
diff --git a/models/user/user_test.go b/models/user/user_test.go
index 4994ac53ab3df..489ee3b05da35 100644
--- a/models/user/user_test.go
+++ b/models/user/user_test.go
@@ -153,6 +153,9 @@ func TestEmailNotificationPreferences(t *testing.T) {
assert.NoError(t, user_model.SetEmailNotifications(user, user_model.EmailNotificationsDisabled))
assert.Equal(t, user_model.EmailNotificationsDisabled, user.EmailNotifications())
+
+ assert.NoError(t, user_model.SetEmailNotifications(user, user_model.EmailNotificationsAndYourOwn))
+ assert.Equal(t, user_model.EmailNotificationsAndYourOwn, user.EmailNotifications())
}
}
diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go
index 1b79a414ade52..478a6a29ff236 100644
--- a/models/webhook/webhook.go
+++ b/models/webhook/webhook.go
@@ -399,6 +399,10 @@ func CreateWebhook(ctx context.Context, w *Webhook) error {
// CreateWebhooks creates multiple web hooks
func CreateWebhooks(ctx context.Context, ws []*Webhook) error {
+ // xorm returns err "no element on slice when insert" for empty slices.
+ if len(ws) == 0 {
+ return nil
+ }
for i := 0; i < len(ws); i++ {
ws[i].Type = strings.TrimSpace(ws[i].Type)
}
diff --git a/modules/context/api.go b/modules/context/api.go
index 558a9f51ee34f..b9d130e2a8ac0 100644
--- a/modules/context/api.go
+++ b/modules/context/api.go
@@ -16,6 +16,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web/middleware"
@@ -268,6 +269,7 @@ func APIContexter() func(http.Handler) http.Handler {
}
}
+ httpcache.AddCacheControlToHeader(ctx.Resp.Header(), 0, "no-transform")
ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
ctx.Data["Context"] = &ctx
diff --git a/modules/context/context.go b/modules/context/context.go
index 68f8a1b408c1f..8824911619921 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -28,6 +28,7 @@ import (
"code.gitea.io/gitea/modules/base"
mc "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -767,6 +768,7 @@ func Contexter() func(next http.Handler) http.Handler {
}
}
+ httpcache.AddCacheControlToHeader(ctx.Resp.Header(), 0, "no-transform")
ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
ctx.Data["CsrfToken"] = ctx.csrf.GetToken()
diff --git a/modules/context/org.go b/modules/context/org.go
index 9f4ce485e5ee7..d020befa40165 100644
--- a/modules/context/org.go
+++ b/modules/context/org.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/structs"
)
// Organization contains organization context
@@ -69,6 +70,20 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
return
}
org := ctx.Org.Organization
+
+ // Handle Visibility
+ if org.Visibility != structs.VisibleTypePublic && !ctx.IsSigned {
+ // We must be signed in to see limited or private organizations
+ ctx.NotFound("OrgAssignment", err)
+ return
+ }
+
+ if org.Visibility == structs.VisibleTypePrivate {
+ requireMember = true
+ } else if ctx.IsSigned && ctx.Doer.IsRestricted {
+ requireMember = true
+ }
+
ctx.ContextUser = org.AsUser()
ctx.Data["Org"] = org
diff --git a/modules/context/package.go b/modules/context/package.go
index 4c52907dc529c..92a97831ddc0b 100644
--- a/modules/context/package.go
+++ b/modules/context/package.go
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/organization"
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/models/perm"
+ "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/structs"
)
@@ -52,14 +53,30 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
}
if ctx.Package.Owner.IsOrganization() {
+ org := organization.OrgFromUser(ctx.Package.Owner)
+
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
if ctx.Doer != nil {
var err error
- ctx.Package.AccessMode, err = organization.OrgFromUser(ctx.Package.Owner).GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
+ ctx.Package.AccessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
if err != nil {
errCb(http.StatusInternalServerError, "GetOrgUserMaxAuthorizeLevel", err)
return
}
+ // If access mode is less than write check every team for more permissions
+ if ctx.Package.AccessMode < perm.AccessModeWrite {
+ teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
+ if err != nil {
+ errCb(http.StatusInternalServerError, "GetUserOrgTeams", err)
+ return
+ }
+ for _, t := range teams {
+ perm := t.UnitAccessModeCtx(ctx, unit.TypePackages)
+ if ctx.Package.AccessMode < perm {
+ ctx.Package.AccessMode = perm
+ }
+ }
+ }
}
// 2. If authorize level is none, check if org is visible to user
if ctx.Package.AccessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
diff --git a/modules/context/repo.go b/modules/context/repo.go
index 183637391862e..ea40542069991 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -393,7 +393,7 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) {
}
}
- pushMirrors, err := repo_model.GetPushMirrorsByRepoID(repo.ID)
+ pushMirrors, _, err := repo_model.GetPushMirrorsByRepoID(ctx, repo.ID, db.ListOptions{})
if err != nil {
ctx.ServerError("GetPushMirrorsByRepoID", err)
return
@@ -1001,6 +1001,8 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
return
}
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
+ ctx.Repo.GitRepo.LastCommitCache = git.NewLastCommitCache(ctx.Repo.CommitsCount, ctx.Repo.Repository.FullName(), ctx.Repo.GitRepo, cache.GetCache())
+
return cancel
}
}
diff --git a/modules/convert/mirror.go b/modules/convert/mirror.go
new file mode 100644
index 0000000000000..b2414f46774cc
--- /dev/null
+++ b/modules/convert/mirror.go
@@ -0,0 +1,39 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package convert
+
+import (
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/modules/git"
+ api "code.gitea.io/gitea/modules/structs"
+)
+
+// ToPushMirror convert from repo_model.PushMirror and remoteAddress to api.TopicResponse
+func ToPushMirror(pm *repo_model.PushMirror) (*api.PushMirror, error) {
+ repo := pm.GetRepository()
+ remoteAddress, err := getRemoteAddress(repo, pm.RemoteName)
+ if err != nil {
+ return nil, err
+ }
+ return &api.PushMirror{
+ RepoName: repo.Name,
+ RemoteName: pm.RemoteName,
+ RemoteAddress: remoteAddress,
+ CreatedUnix: pm.CreatedUnix.FormatLong(),
+ LastUpdateUnix: pm.LastUpdateUnix.FormatLong(),
+ LastError: pm.LastError,
+ Interval: pm.Interval.String(),
+ }, nil
+}
+
+func getRemoteAddress(repo *repo_model.Repository, remoteName string) (string, error) {
+ url, err := git.GetRemoteURL(git.DefaultContext, repo.RepoPath(), remoteName)
+ if err != nil {
+ return "", err
+ }
+ // remove confidential information
+ url.User = nil
+ return url.String(), nil
+}
diff --git a/modules/convert/repository.go b/modules/convert/repository.go
index eb6bb37707391..d333c124b54c6 100644
--- a/modules/convert/repository.go
+++ b/modules/convert/repository.go
@@ -78,6 +78,8 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo
allowRebase := false
allowRebaseMerge := false
allowSquash := false
+ allowRebaseUpdate := false
+ defaultDeleteBranchAfterMerge := false
defaultMergeStyle := repo_model.MergeStyleMerge
if unit, err := repo.GetUnit(unit_model.TypePullRequests); err == nil {
config := unit.PullRequestsConfig()
@@ -87,6 +89,8 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo
allowRebase = config.AllowRebase
allowRebaseMerge = config.AllowRebaseMerge
allowSquash = config.AllowSquash
+ allowRebaseUpdate = config.AllowRebaseUpdate
+ defaultDeleteBranchAfterMerge = config.DefaultDeleteBranchAfterMerge
defaultMergeStyle = config.GetDefaultMergeStyle()
}
hasProjects := false
@@ -133,54 +137,56 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo
repoAPIURL := repo.APIURL()
return &api.Repository{
- ID: repo.ID,
- Owner: ToUserWithAccessMode(repo.Owner, mode),
- Name: repo.Name,
- FullName: repo.FullName(),
- Description: repo.Description,
- Private: repo.IsPrivate,
- Template: repo.IsTemplate,
- Empty: repo.IsEmpty,
- Archived: repo.IsArchived,
- Size: int(repo.Size / 1024),
- Fork: repo.IsFork,
- Parent: parent,
- Mirror: repo.IsMirror,
- HTMLURL: repo.HTMLURL(),
- SSHURL: cloneLink.SSH,
- CloneURL: cloneLink.HTTPS,
- OriginalURL: repo.SanitizedOriginalURL(),
- Website: repo.Website,
- Language: language,
- LanguagesURL: repoAPIURL + "/languages",
- Stars: repo.NumStars,
- Forks: repo.NumForks,
- Watchers: repo.NumWatches,
- OpenIssues: repo.NumOpenIssues,
- OpenPulls: repo.NumOpenPulls,
- Releases: int(numReleases),
- DefaultBranch: repo.DefaultBranch,
- Created: repo.CreatedUnix.AsTime(),
- Updated: repo.UpdatedUnix.AsTime(),
- Permissions: permission,
- HasIssues: hasIssues,
- ExternalTracker: externalTracker,
- InternalTracker: internalTracker,
- HasWiki: hasWiki,
- HasProjects: hasProjects,
- ExternalWiki: externalWiki,
- HasPullRequests: hasPullRequests,
- IgnoreWhitespaceConflicts: ignoreWhitespaceConflicts,
- AllowMerge: allowMerge,
- AllowRebase: allowRebase,
- AllowRebaseMerge: allowRebaseMerge,
- AllowSquash: allowSquash,
- DefaultMergeStyle: string(defaultMergeStyle),
- AvatarURL: repo.AvatarLink(),
- Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
- MirrorInterval: mirrorInterval,
- MirrorUpdated: mirrorUpdated,
- RepoTransfer: transfer,
+ ID: repo.ID,
+ Owner: ToUserWithAccessMode(repo.Owner, mode),
+ Name: repo.Name,
+ FullName: repo.FullName(),
+ Description: repo.Description,
+ Private: repo.IsPrivate,
+ Template: repo.IsTemplate,
+ Empty: repo.IsEmpty,
+ Archived: repo.IsArchived,
+ Size: int(repo.Size / 1024),
+ Fork: repo.IsFork,
+ Parent: parent,
+ Mirror: repo.IsMirror,
+ HTMLURL: repo.HTMLURL(),
+ SSHURL: cloneLink.SSH,
+ CloneURL: cloneLink.HTTPS,
+ OriginalURL: repo.SanitizedOriginalURL(),
+ Website: repo.Website,
+ Language: language,
+ LanguagesURL: repoAPIURL + "/languages",
+ Stars: repo.NumStars,
+ Forks: repo.NumForks,
+ Watchers: repo.NumWatches,
+ OpenIssues: repo.NumOpenIssues,
+ OpenPulls: repo.NumOpenPulls,
+ Releases: int(numReleases),
+ DefaultBranch: repo.DefaultBranch,
+ Created: repo.CreatedUnix.AsTime(),
+ Updated: repo.UpdatedUnix.AsTime(),
+ Permissions: permission,
+ HasIssues: hasIssues,
+ ExternalTracker: externalTracker,
+ InternalTracker: internalTracker,
+ HasWiki: hasWiki,
+ HasProjects: hasProjects,
+ ExternalWiki: externalWiki,
+ HasPullRequests: hasPullRequests,
+ IgnoreWhitespaceConflicts: ignoreWhitespaceConflicts,
+ AllowMerge: allowMerge,
+ AllowRebase: allowRebase,
+ AllowRebaseMerge: allowRebaseMerge,
+ AllowSquash: allowSquash,
+ AllowRebaseUpdate: allowRebaseUpdate,
+ DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge,
+ DefaultMergeStyle: string(defaultMergeStyle),
+ AvatarURL: repo.AvatarLink(),
+ Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
+ MirrorInterval: mirrorInterval,
+ MirrorUpdated: mirrorUpdated,
+ RepoTransfer: transfer,
}
}
diff --git a/modules/convert/user.go b/modules/convert/user.go
index 2b07d21838d71..093994856cae7 100644
--- a/modules/convert/user.go
+++ b/modules/convert/user.go
@@ -73,6 +73,7 @@ func toUser(user *user_model.User, signed, authed bool) *api.User {
// only site admin will get these information and possibly user himself
if authed {
result.IsAdmin = user.IsAdmin
+ result.LoginName = user.LoginName
result.LastLogin = user.LastLoginUnix.AsTime()
result.Language = user.Language
result.IsActive = user.IsActive
diff --git a/modules/git/command.go b/modules/git/command.go
index a1bacbb707a25..b24d32dbe8743 100644
--- a/modules/git/command.go
+++ b/modules/git/command.go
@@ -95,14 +95,15 @@ func (c *Command) AddArguments(args ...string) *Command {
return c
}
-// RunOpts represents parameters to run the command
+// RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored.
type RunOpts struct {
- Env []string
- Timeout time.Duration
- Dir string
- Stdout, Stderr io.Writer
- Stdin io.Reader
- PipelineFunc func(context.Context, context.CancelFunc) error
+ Env []string
+ Timeout time.Duration
+ UseContextTimeout bool
+ Dir string
+ Stdout, Stderr io.Writer
+ Stdin io.Reader
+ PipelineFunc func(context.Context, context.CancelFunc) error
}
func commonBaseEnvs() []string {
@@ -171,7 +172,15 @@ func (c *Command) Run(opts *RunOpts) error {
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), opts.Dir)
}
- ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
+ var ctx context.Context
+ var cancel context.CancelFunc
+ var finished context.CancelFunc
+
+ if opts.UseContextTimeout {
+ ctx, cancel, finished = process.GetManager().AddContext(c.parentContext, desc)
+ } else {
+ ctx, cancel, finished = process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
+ }
defer finished()
cmd := exec.CommandContext(ctx, c.name, c.args...)
diff --git a/modules/git/commit.go b/modules/git/commit.go
index 82712dd1ef3f1..32589f534980c 100644
--- a/modules/git/commit.go
+++ b/modules/git/commit.go
@@ -80,6 +80,9 @@ func (c *Commit) ParentCount() int {
// GetCommitByPath return the commit of relative path object.
func (c *Commit) GetCommitByPath(relpath string) (*Commit, error) {
+ if c.repo.LastCommitCache != nil {
+ return c.repo.LastCommitCache.GetCommitByPath(c.ID.String(), relpath)
+ }
return c.repo.getCommitByPathWithID(c.ID, relpath)
}
diff --git a/modules/git/commit_info_gogit.go b/modules/git/commit_info_gogit.go
index 91a1804db5cff..341698ab34fe0 100644
--- a/modules/git/commit_info_gogit.go
+++ b/modules/git/commit_info_gogit.go
@@ -17,7 +17,7 @@ import (
)
// GetCommitsInfo gets information of all commits that are corresponding to these entries
-func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath string, cache *LastCommitCache) ([]CommitInfo, *Commit, error) {
+func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
entryPaths := make([]string, len(tes)+1)
// Get the commit for the treePath itself
entryPaths[0] = ""
@@ -35,15 +35,15 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
return nil, nil, err
}
- var revs map[string]*object.Commit
- if cache != nil {
+ var revs map[string]*Commit
+ if commit.repo.LastCommitCache != nil {
var unHitPaths []string
- revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, cache)
+ revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache)
if err != nil {
return nil, nil, err
}
if len(unHitPaths) > 0 {
- revs2, err := GetLastCommitForPaths(ctx, cache, c, treePath, unHitPaths)
+ revs2, err := GetLastCommitForPaths(ctx, commit.repo.LastCommitCache, c, treePath, unHitPaths)
if err != nil {
return nil, nil, err
}
@@ -68,8 +68,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
}
// Check if we have found a commit for this entry in time
- if rev, ok := revs[entry.Name()]; ok {
- entryCommit := convertCommit(rev)
+ if entryCommit, ok := revs[entry.Name()]; ok {
commitsInfo[i].Commit = entryCommit
}
@@ -96,10 +95,10 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
// get it for free during the tree traversal and it's used for listing
// pages to display information about newest commit for a given path.
var treeCommit *Commit
+ var ok bool
if treePath == "" {
treeCommit = commit
- } else if rev, ok := revs[""]; ok {
- treeCommit = convertCommit(rev)
+ } else if treeCommit, ok = revs[""]; ok {
treeCommit.repo = commit.repo
}
return commitsInfo, treeCommit, nil
@@ -155,16 +154,16 @@ func getFileHashes(c cgobject.CommitNode, treePath string, paths []string) (map[
return hashes, nil
}
-func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*object.Commit, []string, error) {
+func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) {
var unHitEntryPaths []string
- results := make(map[string]*object.Commit)
+ results := make(map[string]*Commit)
for _, p := range paths {
lastCommit, err := cache.Get(commitID, path.Join(treePath, p))
if err != nil {
return nil, nil, err
}
if lastCommit != nil {
- results[p] = lastCommit.(*object.Commit)
+ results[p] = lastCommit
continue
}
@@ -175,7 +174,7 @@ func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cac
}
// GetLastCommitForPaths returns last commit information
-func GetLastCommitForPaths(ctx context.Context, cache *LastCommitCache, c cgobject.CommitNode, treePath string, paths []string) (map[string]*object.Commit, error) {
+func GetLastCommitForPaths(ctx context.Context, cache *LastCommitCache, c cgobject.CommitNode, treePath string, paths []string) (map[string]*Commit, error) {
refSha := c.ID().String()
// We do a tree traversal with nodes sorted by commit time
@@ -293,13 +292,13 @@ heaploop:
}
// Post-processing
- result := make(map[string]*object.Commit)
+ result := make(map[string]*Commit)
for path, commitNode := range resultNodes {
- var err error
- result[path], err = commitNode.Commit()
+ commit, err := commitNode.Commit()
if err != nil {
return nil, err
}
+ result[path] = convertCommit(commit)
}
return result, nil
diff --git a/modules/git/commit_info_nogogit.go b/modules/git/commit_info_nogogit.go
index ceab11adbb8c6..d7bca3b9486a6 100644
--- a/modules/git/commit_info_nogogit.go
+++ b/modules/git/commit_info_nogogit.go
@@ -17,7 +17,7 @@ import (
)
// GetCommitsInfo gets information of all commits that are corresponding to these entries
-func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath string, cache *LastCommitCache) ([]CommitInfo, *Commit, error) {
+func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
entryPaths := make([]string, len(tes)+1)
// Get the commit for the treePath itself
entryPaths[0] = ""
@@ -28,15 +28,15 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
var err error
var revs map[string]*Commit
- if cache != nil {
+ if commit.repo.LastCommitCache != nil {
var unHitPaths []string
- revs, unHitPaths, err = getLastCommitForPathsByCache(ctx, commit.ID.String(), treePath, entryPaths, cache)
+ revs, unHitPaths, err = getLastCommitForPathsByCache(ctx, commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache)
if err != nil {
return nil, nil, err
}
if len(unHitPaths) > 0 {
sort.Strings(unHitPaths)
- commits, err := GetLastCommitForPaths(ctx, cache, commit, treePath, unHitPaths)
+ commits, err := GetLastCommitForPaths(ctx, commit, treePath, unHitPaths)
if err != nil {
return nil, nil, err
}
@@ -47,7 +47,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
}
} else {
sort.Strings(entryPaths)
- revs, err = GetLastCommitForPaths(ctx, nil, commit, treePath, entryPaths)
+ revs, err = GetLastCommitForPaths(ctx, commit, treePath, entryPaths)
}
if err != nil {
return nil, nil, err
@@ -99,18 +99,15 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
}
func getLastCommitForPathsByCache(ctx context.Context, commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) {
- wr, rd, cancel := cache.repo.CatFileBatch(ctx)
- defer cancel()
-
var unHitEntryPaths []string
results := make(map[string]*Commit)
for _, p := range paths {
- lastCommit, err := cache.Get(commitID, path.Join(treePath, p), wr, rd)
+ lastCommit, err := cache.Get(commitID, path.Join(treePath, p))
if err != nil {
return nil, nil, err
}
if lastCommit != nil {
- results[p] = lastCommit.(*Commit)
+ results[p] = lastCommit
continue
}
@@ -121,9 +118,9 @@ func getLastCommitForPathsByCache(ctx context.Context, commitID, treePath string
}
// GetLastCommitForPaths returns last commit information
-func GetLastCommitForPaths(ctx context.Context, cache *LastCommitCache, commit *Commit, treePath string, paths []string) (map[string]*Commit, error) {
+func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string, paths []string) (map[string]*Commit, error) {
// We read backwards from the commit to obtain all of the commits
- revs, err := WalkGitLog(ctx, cache, commit.repo, commit, treePath, paths...)
+ revs, err := WalkGitLog(ctx, commit.repo, commit, treePath, paths...)
if err != nil {
return nil, err
}
diff --git a/modules/git/commit_info_test.go b/modules/git/commit_info_test.go
index 49845522a9d53..a12452c4040bc 100644
--- a/modules/git/commit_info_test.go
+++ b/modules/git/commit_info_test.go
@@ -91,7 +91,7 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
}
// FIXME: Context.TODO() - if graceful has started we should use its Shutdown context otherwise use install signals in TestMain.
- commitsInfo, treeCommit, err := entries.GetCommitsInfo(context.TODO(), commit, testCase.Path, nil)
+ commitsInfo, treeCommit, err := entries.GetCommitsInfo(context.TODO(), commit, testCase.Path)
assert.NoError(t, err, "Unable to get commit information for entries of subtree: %s in commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err)
if err != nil {
t.FailNow()
@@ -170,7 +170,7 @@ func BenchmarkEntries_GetCommitsInfo(b *testing.B) {
b.ResetTimer()
b.Run(benchmark.name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
- _, _, err := entries.GetCommitsInfo(context.Background(), commit, "", nil)
+ _, _, err := entries.GetCommitsInfo(context.Background(), commit, "")
if err != nil {
b.Fatal(err)
}
diff --git a/modules/git/git.go b/modules/git/git.go
index 3bc08ff93b5fa..b8317396c0150 100644
--- a/modules/git/git.go
+++ b/modules/git/git.go
@@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
+
"github.com/hashicorp/go-version"
)
diff --git a/modules/git/last_commit_cache.go b/modules/git/last_commit_cache.go
index d4ec517b51025..2b51d5972086f 100644
--- a/modules/git/last_commit_cache.go
+++ b/modules/git/last_commit_cache.go
@@ -9,6 +9,7 @@ import (
"fmt"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
)
// Cache represents a caching interface
@@ -19,16 +20,96 @@ type Cache interface {
Get(key string) interface{}
}
-func (c *LastCommitCache) getCacheKey(repoPath, ref, entryPath string) string {
- hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%s", repoPath, ref, entryPath)))
+func getCacheKey(repoPath, commitID, entryPath string) string {
+ hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%s", repoPath, commitID, entryPath)))
return fmt.Sprintf("last_commit:%x", hashBytes)
}
+// LastCommitCache represents a cache to store last commit
+type LastCommitCache struct {
+ repoPath string
+ ttl func() int64
+ repo *Repository
+ commitCache map[string]*Commit
+ cache Cache
+}
+
+// NewLastCommitCache creates a new last commit cache for repo
+func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache Cache) *LastCommitCache {
+ if cache == nil {
+ return nil
+ }
+ if !setting.CacheService.LastCommit.Enabled || count < setting.CacheService.LastCommit.CommitsCount {
+ return nil
+ }
+
+ return &LastCommitCache{
+ repoPath: repoPath,
+ repo: gitRepo,
+ ttl: setting.LastCommitCacheTTLSeconds,
+ cache: cache,
+ }
+}
+
// Put put the last commit id with commit and entry path
func (c *LastCommitCache) Put(ref, entryPath, commitID string) error {
if c == nil || c.cache == nil {
return nil
}
log.Debug("LastCommitCache save: [%s:%s:%s]", ref, entryPath, commitID)
- return c.cache.Put(c.getCacheKey(c.repoPath, ref, entryPath), commitID, c.ttl())
+ return c.cache.Put(getCacheKey(c.repoPath, ref, entryPath), commitID, c.ttl())
+}
+
+// Get gets the last commit information by commit id and entry path
+func (c *LastCommitCache) Get(ref, entryPath string) (*Commit, error) {
+ if c == nil || c.cache == nil {
+ return nil, nil
+ }
+
+ commitID, ok := c.cache.Get(getCacheKey(c.repoPath, ref, entryPath)).(string)
+ if !ok || commitID == "" {
+ return nil, nil
+ }
+
+ log.Debug("LastCommitCache hit level 1: [%s:%s:%s]", ref, entryPath, commitID)
+ if c.commitCache != nil {
+ if commit, ok := c.commitCache[commitID]; ok {
+ log.Debug("LastCommitCache hit level 2: [%s:%s:%s]", ref, entryPath, commitID)
+ return commit, nil
+ }
+ }
+
+ commit, err := c.repo.GetCommit(commitID)
+ if err != nil {
+ return nil, err
+ }
+ if c.commitCache == nil {
+ c.commitCache = make(map[string]*Commit)
+ }
+ c.commitCache[commitID] = commit
+ return commit, nil
+}
+
+// GetCommitByPath gets the last commit for the entry in the provided commit
+func (c *LastCommitCache) GetCommitByPath(commitID, entryPath string) (*Commit, error) {
+ sha1, err := NewIDFromString(commitID)
+ if err != nil {
+ return nil, err
+ }
+
+ lastCommit, err := c.Get(sha1.String(), entryPath)
+ if err != nil || lastCommit != nil {
+ return lastCommit, err
+ }
+
+ lastCommit, err = c.repo.getCommitByPathWithID(sha1, entryPath)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := c.Put(commitID, entryPath, lastCommit.ID.String()); err != nil {
+ log.Error("Unable to cache %s as the last commit for %q in %s %s. Error %v", lastCommit.ID.String(), entryPath, commitID, c.repoPath, err)
+ }
+
+ return lastCommit, nil
}
diff --git a/modules/git/last_commit_cache_gogit.go b/modules/git/last_commit_cache_gogit.go
index 8897000350db0..82c76bad20a49 100644
--- a/modules/git/last_commit_cache_gogit.go
+++ b/modules/git/last_commit_cache_gogit.go
@@ -9,71 +9,25 @@ package git
import (
"context"
- "code.gitea.io/gitea/modules/log"
-
- "github.com/go-git/go-git/v5/plumbing/object"
cgobject "github.com/go-git/go-git/v5/plumbing/object/commitgraph"
)
-// LastCommitCache represents a cache to store last commit
-type LastCommitCache struct {
- repoPath string
- ttl func() int64
- repo *Repository
- commitCache map[string]*object.Commit
- cache Cache
-}
-
-// NewLastCommitCache creates a new last commit cache for repo
-func NewLastCommitCache(repoPath string, gitRepo *Repository, ttl func() int64, cache Cache) *LastCommitCache {
- if cache == nil {
+// CacheCommit will cache the commit from the gitRepository
+func (c *Commit) CacheCommit(ctx context.Context) error {
+ if c.repo.LastCommitCache == nil {
return nil
}
- return &LastCommitCache{
- repoPath: repoPath,
- repo: gitRepo,
- commitCache: make(map[string]*object.Commit),
- ttl: ttl,
- cache: cache,
- }
-}
-
-// Get get the last commit information by commit id and entry path
-func (c *LastCommitCache) Get(ref, entryPath string) (interface{}, error) {
- v := c.cache.Get(c.getCacheKey(c.repoPath, ref, entryPath))
- if vs, ok := v.(string); ok {
- log.Debug("LastCommitCache hit level 1: [%s:%s:%s]", ref, entryPath, vs)
- if commit, ok := c.commitCache[vs]; ok {
- log.Debug("LastCommitCache hit level 2: [%s:%s:%s]", ref, entryPath, vs)
- return commit, nil
- }
- id, err := c.repo.ConvertToSHA1(vs)
- if err != nil {
- return nil, err
- }
- commit, err := c.repo.GoGitRepo().CommitObject(id)
- if err != nil {
- return nil, err
- }
- c.commitCache[vs] = commit
- return commit, nil
- }
- return nil, nil
-}
-
-// CacheCommit will cache the commit from the gitRepository
-func (c *LastCommitCache) CacheCommit(ctx context.Context, commit *Commit) error {
- commitNodeIndex, _ := commit.repo.CommitNodeIndex()
+ commitNodeIndex, _ := c.repo.CommitNodeIndex()
- index, err := commitNodeIndex.Get(commit.ID)
+ index, err := commitNodeIndex.Get(c.ID)
if err != nil {
return err
}
- return c.recursiveCache(ctx, index, &commit.Tree, "", 1)
+ return c.recursiveCache(ctx, index, &c.Tree, "", 1)
}
-func (c *LastCommitCache) recursiveCache(ctx context.Context, index cgobject.CommitNode, tree *Tree, treePath string, level int) error {
+func (c *Commit) recursiveCache(ctx context.Context, index cgobject.CommitNode, tree *Tree, treePath string, level int) error {
if level == 0 {
return nil
}
@@ -90,7 +44,7 @@ func (c *LastCommitCache) recursiveCache(ctx context.Context, index cgobject.Com
entryMap[entry.Name()] = entry
}
- commits, err := GetLastCommitForPaths(ctx, c, index, treePath, entryPaths)
+ commits, err := GetLastCommitForPaths(ctx, c.repo.LastCommitCache, index, treePath, entryPaths)
if err != nil {
return err
}
diff --git a/modules/git/last_commit_cache_nogogit.go b/modules/git/last_commit_cache_nogogit.go
index 030d5486b6302..1f4d693a262d9 100644
--- a/modules/git/last_commit_cache_nogogit.go
+++ b/modules/git/last_commit_cache_nogogit.go
@@ -7,67 +7,18 @@
package git
import (
- "bufio"
"context"
-
- "code.gitea.io/gitea/modules/log"
)
-// LastCommitCache represents a cache to store last commit
-type LastCommitCache struct {
- repoPath string
- ttl func() int64
- repo *Repository
- commitCache map[string]*Commit
- cache Cache
-}
-
-// NewLastCommitCache creates a new last commit cache for repo
-func NewLastCommitCache(repoPath string, gitRepo *Repository, ttl func() int64, cache Cache) *LastCommitCache {
- if cache == nil {
+// CacheCommit will cache the commit from the gitRepository
+func (c *Commit) CacheCommit(ctx context.Context) error {
+ if c.repo.LastCommitCache == nil {
return nil
}
- return &LastCommitCache{
- repoPath: repoPath,
- repo: gitRepo,
- commitCache: make(map[string]*Commit),
- ttl: ttl,
- cache: cache,
- }
-}
-
-// Get get the last commit information by commit id and entry path
-func (c *LastCommitCache) Get(ref, entryPath string, wr WriteCloserError, rd *bufio.Reader) (interface{}, error) {
- v := c.cache.Get(c.getCacheKey(c.repoPath, ref, entryPath))
- if vs, ok := v.(string); ok {
- log.Debug("LastCommitCache hit level 1: [%s:%s:%s]", ref, entryPath, vs)
- if commit, ok := c.commitCache[vs]; ok {
- log.Debug("LastCommitCache hit level 2: [%s:%s:%s]", ref, entryPath, vs)
- return commit, nil
- }
- id, err := c.repo.ConvertToSHA1(vs)
- if err != nil {
- return nil, err
- }
- if _, err := wr.Write([]byte(vs + "\n")); err != nil {
- return nil, err
- }
- commit, err := c.repo.getCommitFromBatchReader(rd, id)
- if err != nil {
- return nil, err
- }
- c.commitCache[vs] = commit
- return commit, nil
- }
- return nil, nil
-}
-
-// CacheCommit will cache the commit from the gitRepository
-func (c *LastCommitCache) CacheCommit(ctx context.Context, commit *Commit) error {
- return c.recursiveCache(ctx, commit, &commit.Tree, "", 1)
+ return c.recursiveCache(ctx, &c.Tree, "", 1)
}
-func (c *LastCommitCache) recursiveCache(ctx context.Context, commit *Commit, tree *Tree, treePath string, level int) error {
+func (c *Commit) recursiveCache(ctx context.Context, tree *Tree, treePath string, level int) error {
if level == 0 {
return nil
}
@@ -82,7 +33,7 @@ func (c *LastCommitCache) recursiveCache(ctx context.Context, commit *Commit, tr
entryPaths[i] = entry.Name()
}
- _, err = WalkGitLog(ctx, c, commit.repo, commit, treePath, entryPaths...)
+ _, err = WalkGitLog(ctx, c.repo, c, treePath, entryPaths...)
if err != nil {
return err
}
@@ -94,7 +45,7 @@ func (c *LastCommitCache) recursiveCache(ctx context.Context, commit *Commit, tr
if err != nil {
return err
}
- if err := c.recursiveCache(ctx, commit, subTree, treeEntry.Name(), level-1); err != nil {
+ if err := c.recursiveCache(ctx, subTree, treeEntry.Name(), level-1); err != nil {
return err
}
}
diff --git a/modules/git/log_name_status.go b/modules/git/log_name_status.go
index e1e117ff4b842..80f1602708471 100644
--- a/modules/git/log_name_status.go
+++ b/modules/git/log_name_status.go
@@ -281,7 +281,7 @@ func (g *LogNameStatusRepoParser) Close() {
}
// WalkGitLog walks the git log --name-status for the head commit in the provided treepath and files
-func WalkGitLog(ctx context.Context, cache *LastCommitCache, repo *Repository, head *Commit, treepath string, paths ...string) (map[string]string, error) {
+func WalkGitLog(ctx context.Context, repo *Repository, head *Commit, treepath string, paths ...string) (map[string]string, error) {
headRef := head.ID.String()
tree, err := head.SubTree(treepath)
@@ -374,14 +374,14 @@ heaploop:
changed[i] = false
if results[i] == "" {
results[i] = current.CommitID
- if err := cache.Put(headRef, path.Join(treepath, paths[i]), current.CommitID); err != nil {
+ if err := repo.LastCommitCache.Put(headRef, path.Join(treepath, paths[i]), current.CommitID); err != nil {
return nil, err
}
delete(path2idx, paths[i])
remaining--
if results[0] == "" {
results[0] = current.CommitID
- if err := cache.Put(headRef, treepath, current.CommitID); err != nil {
+ if err := repo.LastCommitCache.Put(headRef, treepath, current.CommitID); err != nil {
return nil, err
}
delete(path2idx, "")
diff --git a/modules/git/notes_gogit.go b/modules/git/notes_gogit.go
index 76bc828957b3d..fe6d1f1e580c8 100644
--- a/modules/git/notes_gogit.go
+++ b/modules/git/notes_gogit.go
@@ -83,7 +83,7 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note)
log.Error("Unable to get the commit for the path %q. Error: %v", path, err)
return err
}
- note.Commit = convertCommit(lastCommits[path])
+ note.Commit = lastCommits[path]
return nil
}
diff --git a/modules/git/notes_nogogit.go b/modules/git/notes_nogogit.go
index 1476805dcdc03..ba216ce3e4a41 100644
--- a/modules/git/notes_nogogit.go
+++ b/modules/git/notes_nogogit.go
@@ -81,7 +81,7 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note)
path = path[idx+1:]
}
- lastCommits, err := GetLastCommitForPaths(ctx, nil, notes, treePath, []string{path})
+ lastCommits, err := GetLastCommitForPaths(ctx, notes, treePath, []string{path})
if err != nil {
log.Error("Unable to get the commit for the path %q. Error: %v", treePath, err)
return err
diff --git a/modules/git/repo_base_gogit.go b/modules/git/repo_base_gogit.go
index cd2ca25dfbadf..8fe9c404c3dbb 100644
--- a/modules/git/repo_base_gogit.go
+++ b/modules/git/repo_base_gogit.go
@@ -31,7 +31,8 @@ type Repository struct {
gogitStorage *filesystem.Storage
gpgSettings *GPGSettings
- Ctx context.Context
+ Ctx context.Context
+ LastCommitCache *LastCommitCache
}
// openRepositoryWithDefaultContext opens the repository at the given path with DefaultContext.
@@ -79,6 +80,8 @@ func (repo *Repository) Close() (err error) {
if err := repo.gogitStorage.Close(); err != nil {
gitealog.Error("Error closing storage: %v", err)
}
+ repo.LastCommitCache = nil
+ repo.tagCache = nil
return
}
diff --git a/modules/git/repo_base_nogogit.go b/modules/git/repo_base_nogogit.go
index 63c278c26137a..56af2c640fd4a 100644
--- a/modules/git/repo_base_nogogit.go
+++ b/modules/git/repo_base_nogogit.go
@@ -32,7 +32,8 @@ type Repository struct {
checkReader *bufio.Reader
checkWriter WriteCloserError
- Ctx context.Context
+ Ctx context.Context
+ LastCommitCache *LastCommitCache
}
// openRepositoryWithDefaultContext opens the repository at the given path with DefaultContext.
@@ -101,5 +102,7 @@ func (repo *Repository) Close() (err error) {
repo.checkReader = nil
repo.checkWriter = nil
}
+ repo.LastCommitCache = nil
+ repo.tagCache = nil
return err
}
diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go
index 8e455480e7279..17d243808e9c0 100644
--- a/modules/git/repo_branch.go
+++ b/modules/git/repo_branch.go
@@ -7,6 +7,7 @@ package git
import (
"context"
+ "errors"
"fmt"
"strings"
)
@@ -72,7 +73,14 @@ func (repo *Repository) SetDefaultBranch(name string) error {
// GetDefaultBranch gets default branch of repository.
func (repo *Repository) GetDefaultBranch() (string, error) {
stdout, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunStdString(&RunOpts{Dir: repo.Path})
- return stdout, err
+ if err != nil {
+ return "", err
+ }
+ stdout = strings.TrimSpace(stdout)
+ if !strings.HasPrefix(stdout, BranchPrefix) {
+ return "", errors.New("the HEAD is not a branch: " + stdout)
+ }
+ return strings.TrimPrefix(stdout, BranchPrefix), nil
}
// GetBranch returns a branch by it's name
diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go
index e6fec4d1a32e2..7ff23af42eb84 100644
--- a/modules/git/repo_commit.go
+++ b/modules/git/repo_commit.go
@@ -11,6 +11,7 @@ import (
"strconv"
"strings"
+ "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/setting"
)
@@ -434,3 +435,20 @@ func (repo *Repository) IsCommitInBranch(commitID, branch string) (r bool, err e
}
return len(stdout) > 0, err
}
+
+func (repo *Repository) AddLastCommitCache(cacheKey, fullName, sha string) error {
+ if repo.LastCommitCache == nil {
+ commitsCount, err := cache.GetInt64(cacheKey, func() (int64, error) {
+ commit, err := repo.GetCommit(sha)
+ if err != nil {
+ return 0, err
+ }
+ return commit.CommitsCount()
+ })
+ if err != nil {
+ return err
+ }
+ repo.LastCommitCache = NewLastCommitCache(commitsCount, fullName, repo, cache.GetCache())
+ }
+ return nil
+}
diff --git a/modules/highlight/highlight.go b/modules/highlight/highlight.go
index acd3bebb9f408..af3376e8d7127 100644
--- a/modules/highlight/highlight.go
+++ b/modules/highlight/highlight.go
@@ -10,6 +10,7 @@ import (
"bytes"
"fmt"
gohtml "html"
+ "io"
"path/filepath"
"strings"
"sync"
@@ -26,7 +27,7 @@ import (
)
// don't index files larger than this many bytes for performance purposes
-const sizeLimit = 1000000
+const sizeLimit = 1024 * 1024
var (
// For custom user mapping
@@ -40,11 +41,12 @@ var (
// NewContext loads custom highlight map from local config
func NewContext() {
once.Do(func() {
- keys := setting.Cfg.Section("highlight.mapping").Keys()
- for i := range keys {
- highlightMapping[keys[i].Name()] = keys[i].Value()
+ if setting.Cfg != nil {
+ keys := setting.Cfg.Section("highlight.mapping").Keys()
+ for i := range keys {
+ highlightMapping[keys[i].Name()] = keys[i].Value()
+ }
}
-
// The size 512 is simply a conservative rule of thumb
c, err := lru.New2Q(512)
if err != nil {
@@ -58,7 +60,7 @@ func NewContext() {
func Code(fileName, language, code string) string {
NewContext()
- // diff view newline will be passed as empty, change to literal \n so it can be copied
+ // diff view newline will be passed as empty, change to literal '\n' so it can be copied
// preserve literal newline in blame view
if code == "" || code == "\n" {
return "\n"
@@ -126,36 +128,32 @@ func CodeFromLexer(lexer chroma.Lexer, code string) string {
return code
}
- htmlw.Flush()
+ _ = htmlw.Flush()
// Chroma will add newlines for certain lexers in order to highlight them properly
- // Once highlighted, strip them here so they don't cause copy/paste trouble in HTML output
+ // Once highlighted, strip them here, so they don't cause copy/paste trouble in HTML output
return strings.TrimSuffix(htmlbuf.String(), "\n")
}
-// File returns a slice of chroma syntax highlighted lines of code
-func File(numLines int, fileName, language string, code []byte) []string {
+// File returns a slice of chroma syntax highlighted HTML lines of code
+func File(fileName, language string, code []byte) ([]string, error) {
NewContext()
if len(code) > sizeLimit {
- return plainText(string(code), numLines)
+ return PlainText(code), nil
}
+
formatter := html.New(html.WithClasses(true),
html.WithLineNumbers(false),
html.PreventSurroundingPre(true),
)
- if formatter == nil {
- log.Error("Couldn't create chroma formatter")
- return plainText(string(code), numLines)
- }
-
- htmlbuf := bytes.Buffer{}
- htmlw := bufio.NewWriter(&htmlbuf)
+ htmlBuf := bytes.Buffer{}
+ htmlWriter := bufio.NewWriter(&htmlBuf)
var lexer chroma.Lexer
// provided language overrides everything
- if len(language) > 0 {
+ if language != "" {
lexer = lexers.Get(language)
}
@@ -166,9 +164,9 @@ func File(numLines int, fileName, language string, code []byte) []string {
}
if lexer == nil {
- language := analyze.GetCodeLanguage(fileName, code)
+ guessLanguage := analyze.GetCodeLanguage(fileName, code)
- lexer = lexers.Get(language)
+ lexer = lexers.Get(guessLanguage)
if lexer == nil {
lexer = lexers.Match(fileName)
if lexer == nil {
@@ -179,54 +177,43 @@ func File(numLines int, fileName, language string, code []byte) []string {
iterator, err := lexer.Tokenise(nil, string(code))
if err != nil {
- log.Error("Can't tokenize code: %v", err)
- return plainText(string(code), numLines)
+ return nil, fmt.Errorf("can't tokenize code: %w", err)
}
- err = formatter.Format(htmlw, styles.GitHub, iterator)
+ err = formatter.Format(htmlWriter, styles.GitHub, iterator)
if err != nil {
- log.Error("Can't format code: %v", err)
- return plainText(string(code), numLines)
+ return nil, fmt.Errorf("can't format code: %w", err)
}
- htmlw.Flush()
- finalNewLine := false
- if len(code) > 0 {
- finalNewLine = code[len(code)-1] == '\n'
- }
+ _ = htmlWriter.Flush()
- m := make([]string, 0, numLines)
- for _, v := range strings.SplitN(htmlbuf.String(), "\n", numLines) {
- content := v
- // need to keep lines that are only \n so copy/paste works properly in browser
- if content == "" {
- content = "\n"
- } else if content == `` {
- content += "\n"
- } else if content == `` {
- content += "\n"
- }
- content = strings.TrimSuffix(content, ``)
- content = strings.TrimPrefix(content, ``)
- m = append(m, content)
+ // at the moment, Chroma generates stable output `...\n` for each line
+ htmlStr := htmlBuf.String()
+ lines := strings.Split(htmlStr, ``)
+ m := make([]string, 0, len(lines))
+ for i := 1; i < len(lines); i++ {
+ line := lines[i]
+ line = strings.TrimSuffix(line, "")
+ m = append(m, line)
}
- if finalNewLine {
- m = append(m, "\n")
- }
-
- return m
+ return m, nil
}
-// return unhiglighted map
-func plainText(code string, numLines int) []string {
- m := make([]string, 0, numLines)
- for _, v := range strings.SplitN(code, "\n", numLines) {
- content := v
- // need to keep lines that are only \n so copy/paste works properly in browser
- if content == "" {
- content = "\n"
+// PlainText returns non-highlighted HTML for code
+func PlainText(code []byte) []string {
+ r := bufio.NewReader(bytes.NewReader(code))
+ m := make([]string, 0, bytes.Count(code, []byte{'\n'})+1)
+ for {
+ content, err := r.ReadString('\n')
+ if err != nil && err != io.EOF {
+ log.Error("failed to read string from buffer: %v", err)
+ break
+ }
+ if content == "" && err == io.EOF {
+ break
}
- m = append(m, gohtml.EscapeString(content))
+ s := gohtml.EscapeString(content)
+ m = append(m, s)
}
return m
}
diff --git a/modules/highlight/highlight_test.go b/modules/highlight/highlight_test.go
index e5dfedd2b3c8e..8f83f4a2f6128 100644
--- a/modules/highlight/highlight_test.go
+++ b/modules/highlight/highlight_test.go
@@ -8,97 +8,146 @@ import (
"strings"
"testing"
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
-
"github.com/stretchr/testify/assert"
- "gopkg.in/ini.v1"
)
+func lines(s string) []string {
+ return strings.Split(strings.ReplaceAll(strings.TrimSpace(s), `\n`, "\n"), "\n")
+}
+
func TestFile(t *testing.T) {
- setting.Cfg = ini.Empty()
tests := []struct {
- name string
- numLines int
- fileName string
- code string
- want string
+ name string
+ code string
+ want []string
}{
{
- name: ".drone.yml",
- numLines: 12,
- fileName: ".drone.yml",
- code: util.Dedent(`
- kind: pipeline
- name: default
+ name: "empty.py",
+ code: "",
+ want: lines(""),
+ },
+ {
+ name: "tags.txt",
+ code: "<>",
+ want: lines("<>"),
+ },
+ {
+ name: "tags.py",
+ code: "<>",
+ want: lines(`<>`),
+ },
+ {
+ name: "eol-no.py",
+ code: "a=1",
+ want: lines(`a=1`),
+ },
+ {
+ name: "eol-newline1.py",
+ code: "a=1\n",
+ want: lines(`a=1\n`),
+ },
+ {
+ name: "eol-newline2.py",
+ code: "a=1\n\n",
+ want: lines(`
+a=1\n
+\n
+ `,
+ ),
+ },
+ {
+ name: "empty-line-with-space.py",
+ code: strings.ReplaceAll(strings.TrimSpace(`
+def:
+ a=1
- steps:
- - name: test
- image: golang:1.13
- environment:
- GOPROXY: https://goproxy.cn
- commands:
- - go get -u
- - go build -v
- - go test -v -race -coverprofile=coverage.txt -covermode=atomic
- `),
- want: util.Dedent(`
- kind:pipeline
- name:default
-
- steps:
- - name:test
- image:golang:1.13
- environment:
- GOPROXY:https://goproxy.cn
- commands:
- - go get -u
- - go build -v
- - go test -v -race -coverprofile=coverage.txt -covermode=atomic
+b=''
+{space}
+c=2
+ `), "{space}", " "),
+ want: lines(`
+def:\n
+ a=1\n
+\n
+b=''\n
+ \n
+c=2`,
+ ),
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ out, err := File(tt.name, "", []byte(tt.code))
+ assert.NoError(t, err)
+ expected := strings.Join(tt.want, "\n")
+ actual := strings.Join(out, "\n")
+ assert.Equal(t, strings.Count(actual, ""))
+ assert.EqualValues(t, expected, actual)
+ })
+ }
+}
+
+func TestPlainText(t *testing.T) {
+ tests := []struct {
+ name string
+ code string
+ want []string
+ }{
+ {
+ name: "empty.py",
+ code: "",
+ want: lines(""),
+ },
+ {
+ name: "tags.py",
+ code: "<>",
+ want: lines("<>"),
+ },
+ {
+ name: "eol-no.py",
+ code: "a=1",
+ want: lines(`a=1`),
+ },
+ {
+ name: "eol-newline1.py",
+ code: "a=1\n",
+ want: lines(`a=1\n`),
+ },
+ {
+ name: "eol-newline2.py",
+ code: "a=1\n\n",
+ want: lines(`
+a=1\n
+\n
`),
},
{
- name: ".drone.yml - trailing space",
- numLines: 13,
- fileName: ".drone.yml",
- code: strings.Replace(util.Dedent(`
- kind: pipeline
- name: default
+ name: "empty-line-with-space.py",
+ code: strings.ReplaceAll(strings.TrimSpace(`
+def:
+ a=1
- steps:
- - name: test
- image: golang:1.13
- environment:
- GOPROXY: https://goproxy.cn
- commands:
- - go get -u
- - go build -v
- - go test -v -race -coverprofile=coverage.txt -covermode=atomic
- `)+"\n", "name: default", "name: default ", 1),
- want: util.Dedent(`
- kind:pipeline
- name:default
-
- steps:
- - name:test
- image:golang:1.13
- environment:
- GOPROXY:https://goproxy.cn
- commands:
- - go get -u
- - go build -v
- - go test -v -race -coverprofile=coverage.txt -covermode=atomic
-
-
-
- `),
+b=''
+{space}
+c=2
+ `), "{space}", " "),
+ want: lines(`
+def:\n
+ a=1\n
+\n
+b=''\n
+ \n
+c=2`),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- got := strings.Join(File(tt.numLines, tt.fileName, "", []byte(tt.code)), "\n")
- assert.Equal(t, tt.want, got)
+ out := PlainText([]byte(tt.code))
+ expected := strings.Join(tt.want, "\n")
+ actual := strings.Join(out, "\n")
+ assert.EqualValues(t, expected, actual)
})
}
}
diff --git a/modules/httpcache/httpcache.go b/modules/httpcache/httpcache.go
index 5797e981cf80f..750233d4a71c2 100644
--- a/modules/httpcache/httpcache.go
+++ b/modules/httpcache/httpcache.go
@@ -17,16 +17,23 @@ import (
)
// AddCacheControlToHeader adds suitable cache-control headers to response
-func AddCacheControlToHeader(h http.Header, d time.Duration) {
+func AddCacheControlToHeader(h http.Header, maxAge time.Duration, additionalDirectives ...string) {
+ directives := make([]string, 0, 2+len(additionalDirectives))
+
if setting.IsProd {
- h.Set("Cache-Control", "private, max-age="+strconv.Itoa(int(d.Seconds())))
+ if maxAge == 0 {
+ directives = append(directives, "no-store")
+ } else {
+ directives = append(directives, "private", "max-age="+strconv.Itoa(int(maxAge.Seconds())))
+ }
} else {
- h.Set("Cache-Control", "no-store")
+ directives = append(directives, "no-store")
+
// to remind users they are using non-prod setting.
- // some users may be confused by "Cache-Control: no-store" in their setup if they did wrong to `RUN_MODE` in `app.ini`.
h.Add("X-Gitea-Debug", "RUN_MODE="+setting.RunMode)
- h.Add("X-Gitea-Debug", "CacheControl=no-store")
}
+
+ h.Set("Cache-Control", strings.Join(append(directives, additionalDirectives...), ", "))
}
// generateETag generates an ETag based on size, filename and file modification time
diff --git a/modules/lfs/content_store.go b/modules/lfs/content_store.go
index c794a1feccc6f..0eedf4de1798b 100644
--- a/modules/lfs/content_store.go
+++ b/modules/lfs/content_store.go
@@ -8,7 +8,6 @@ import (
"crypto/sha256"
"encoding/hex"
"errors"
- "fmt"
"hash"
"io"
"os"
@@ -24,21 +23,6 @@ var (
ErrSizeMismatch = errors.New("Content size does not match")
)
-// ErrRangeNotSatisfiable represents an error which request range is not satisfiable.
-type ErrRangeNotSatisfiable struct {
- FromByte int64
-}
-
-// IsErrRangeNotSatisfiable returns true if the error is an ErrRangeNotSatisfiable
-func IsErrRangeNotSatisfiable(err error) bool {
- _, ok := err.(ErrRangeNotSatisfiable)
- return ok
-}
-
-func (err ErrRangeNotSatisfiable) Error() string {
- return fmt.Sprintf("Requested range %d is not satisfiable", err.FromByte)
-}
-
// ContentStore provides a simple file system based storage.
type ContentStore struct {
storage.ObjectStorage
diff --git a/modules/markup/html.go b/modules/markup/html.go
index 6071180501c42..a5606dbb516ad 100644
--- a/modules/markup/html.go
+++ b/modules/markup/html.go
@@ -1176,7 +1176,7 @@ func genDefaultLinkProcessor(defaultLink string) processor {
node.DataAtom = atom.A
node.Attr = []html.Attribute{
{Key: "href", Val: defaultLink},
- {Key: "class", Val: "default-link"},
+ {Key: "class", Val: "default-link muted"},
}
node.FirstChild, node.LastChild = ch, ch
}
diff --git a/modules/markup/renderer.go b/modules/markup/renderer.go
index e88fa311875d5..5f69dc72354f0 100644
--- a/modules/markup/renderer.go
+++ b/modules/markup/renderer.go
@@ -310,14 +310,9 @@ func IsMarkupFile(name, markup string) bool {
}
// IsReadmeFile reports whether name looks like a README file
-// based on its name. If an extension is provided, it will strictly
-// match that extension.
-// Note that the '.' should be provided in ext, e.g ".md"
-func IsReadmeFile(name string, ext ...string) bool {
+// based on its name.
+func IsReadmeFile(name string) bool {
name = strings.ToLower(name)
- if len(ext) > 0 {
- return name == "readme"+ext[0]
- }
if len(name) < 6 {
return false
} else if len(name) == 6 {
@@ -325,3 +320,29 @@ func IsReadmeFile(name string, ext ...string) bool {
}
return name[:7] == "readme."
}
+
+// IsReadmeFileExtension reports whether name looks like a README file
+// based on its name. It will look through the provided extensions and check if the file matches
+// one of the extensions and provide the index in the extension list.
+// If the filename is `readme.` with an unmatched extension it will match with the index equaling
+// the length of the provided extension list.
+// Note that the '.' should be provided in ext, e.g ".md"
+func IsReadmeFileExtension(name string, ext ...string) (int, bool) {
+ name = strings.ToLower(name)
+ if len(name) < 6 || name[:6] != "readme" {
+ return 0, false
+ }
+
+ for i, extension := range ext {
+ extension = strings.ToLower(extension)
+ if name[6:] == extension {
+ return i, true
+ }
+ }
+
+ if name[6] == '.' {
+ return len(ext), true
+ }
+
+ return 0, false
+}
diff --git a/modules/markup/renderer_test.go b/modules/markup/renderer_test.go
index 4cfa022463190..950ee15b91072 100644
--- a/modules/markup/renderer_test.go
+++ b/modules/markup/renderer_test.go
@@ -40,24 +40,57 @@ func TestMisc_IsReadmeFile(t *testing.T) {
assert.False(t, IsReadmeFile(testCase))
}
- trueTestCasesStrict := [][]string{
- {"readme", ""},
- {"readme.md", ".md"},
- {"readme.txt", ".txt"},
- }
- falseTestCasesStrict := [][]string{
- {"readme", ".md"},
- {"readme.md", ""},
- {"readme.md", ".txt"},
- {"readme.md", "md"},
- {"readmee.md", ".md"},
- {"readme.i18n.md", ".md"},
+ type extensionTestcase struct {
+ name string
+ expected bool
+ idx int
}
- for _, testCase := range trueTestCasesStrict {
- assert.True(t, IsReadmeFile(testCase[0], testCase[1]))
+ exts := []string{".md", ".txt", ""}
+ testCasesExtensions := []extensionTestcase{
+ {
+ name: "readme",
+ expected: true,
+ idx: 2,
+ },
+ {
+ name: "readme.md",
+ expected: true,
+ idx: 0,
+ },
+ {
+ name: "README.md",
+ expected: true,
+ idx: 0,
+ },
+ {
+ name: "ReAdMe.Md",
+ expected: true,
+ idx: 0,
+ },
+ {
+ name: "readme.txt",
+ expected: true,
+ idx: 1,
+ },
+ {
+ name: "readme.doc",
+ expected: true,
+ idx: 3,
+ },
+ {
+ name: "readmee.md",
+ },
+ {
+ name: "readme..",
+ expected: true,
+ idx: 3,
+ },
}
- for _, testCase := range falseTestCasesStrict {
- assert.False(t, IsReadmeFile(testCase[0], testCase[1]))
+
+ for _, testCase := range testCasesExtensions {
+ idx, ok := IsReadmeFileExtension(testCase.name, exts...)
+ assert.Equal(t, testCase.expected, ok)
+ assert.Equal(t, testCase.idx, idx)
}
}
diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go
index 388af567123dc..57e88fdabc816 100644
--- a/modules/markup/sanitizer.go
+++ b/modules/markup/sanitizer.go
@@ -85,6 +85,12 @@ func createDefaultPolicy() *bluemonday.Policy {
// Allow icons, emojis, chroma syntax and keyword markup on span
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^((icon(\s+[\p{L}\p{N}_-]+)+)|(emoji))$|^([a-z][a-z0-9]{0,2})$|^` + keywordClass + `$`)).OnElements("span")
+ // Allow 'style' attribute on text elements.
+ policy.AllowAttrs("style").OnElements("span", "p")
+
+ // Allow 'color' property for the style attribute on text elements.
+ policy.AllowStyles("color").OnElements("span", "p")
+
// Allow generally safe attributes
generalSafeAttrs := []string{
"abbr", "accept", "accept-charset",
diff --git a/modules/markup/sanitizer_test.go b/modules/markup/sanitizer_test.go
index 7dfca7a468dbe..b3b07404b451b 100644
--- a/modules/markup/sanitizer_test.go
+++ b/modules/markup/sanitizer_test.go
@@ -45,6 +45,14 @@ func Test_Sanitizer(t *testing.T) {
`unchecked`, `unchecked`,
`NAUGHTY`, `NAUGHTY`,
`contents`, `contents`,
+
+ // Color property
+ `Hello World`, `Hello World`,
+ `