diff --git a/.air.conf b/.air.conf new file mode 100644 index 0000000000000..7b5a5cb86a7d0 --- /dev/null +++ b/.air.conf @@ -0,0 +1,9 @@ +root = "." +tmp_dir = ".air" + +[build] +cmd = "make backend" +bin = "gitea" +include_ext = ["go", "tmpl"] +exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata"] +include_dir = ["cmd", "models", "modules", "options", "routers", "services", "templates"] diff --git a/.changelog.yml b/.changelog.yml index c5a9078e03ad1..942138327875e 100644 --- a/.changelog.yml +++ b/.changelog.yml @@ -22,6 +22,10 @@ groups: name: SECURITY labels: - kind/security + - + name: API + labels: + - kind/api - name: BUGFIXES labels: diff --git a/.drone.yml b/.drone.yml index 1b68e212e2911..9edfae72a828d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -13,20 +13,19 @@ workspace: steps: - name: deps-frontend pull: always - image: node:12 + image: node:14 commands: - make node_modules - name: lint-frontend - pull: always - image: node:12 + image: node:14 commands: - make lint-frontend depends_on: [deps-frontend] - name: lint-backend pull: always - image: golang:1.14 + image: golang:1.15 commands: - make lint-backend environment: @@ -34,40 +33,84 @@ steps: GOSUMDB: sum.golang.org TAGS: bindata sqlite sqlite_unlock_notify - - name: build-frontend + - name: lint-backend-windows pull: always - image: node:10 # this step is kept at the lowest version of node that we support + image: golang:1.15 + commands: + - make golangci-lint vet + environment: + GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not + GOSUMDB: sum.golang.org + TAGS: bindata sqlite sqlite_unlock_notify + GOOS: windows + GOARCH: amd64 + + - name: lint-backend-gogit + pull: always + image: golang:1.15 + commands: + - make lint-backend + environment: + GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not + GOSUMDB: sum.golang.org + TAGS: bindata gogit sqlite sqlite_unlock_notify + + - name: checks-frontend + image: node:14 + commands: + - make checks-frontend + depends_on: [deps-frontend] + + - name: checks-backend + pull: always + image: golang:1.14 + commands: + - make checks-backend + depends_on: [lint-backend] + + - name: build-frontend + image: node:14 commands: - make frontend depends_on: [lint-frontend] - name: build-backend-no-gcc pull: always - image: golang:1.12 # this step is kept as the lowest version of golang that we support + image: golang:1.13 # this step is kept as the lowest version of golang that we support environment: GO111MODULE: on GOPROXY: off commands: - go build -mod=vendor -o gitea_no_gcc # test if build succeeds without the sqlite tag - depends_on: [lint-backend] + depends_on: [checks-backend] - name: build-backend-arm64 - pull: always - image: golang:1.14 + image: golang:1.15 environment: GO111MODULE: on GOPROXY: off GOOS: linux GOARCH: arm64 - TAGS: bindata + TAGS: bindata gogit commands: - make backend # test cross compile - rm ./gitea # clean - depends_on: [lint-backend] + depends_on: [checks-backend] + + - name: build-backend-windows + image: golang:1.15 + environment: + GO111MODULE: on + GOPROXY: off + GOOS: windows + GOARCH: amd64 + TAGS: bindata gogit + commands: + - go build -mod=vendor -o gitea_windows + depends_on: [checks-backend] - name: build-backend-386 - pull: always - image: golang:1.14 + image: golang:1.15 environment: GO111MODULE: on GOPROXY: off @@ -75,7 +118,7 @@ steps: GOARCH: 386 commands: - go build -mod=vendor -o gitea_linux_386 # test if compatible with 32 bit - depends_on: [lint-backend] + depends_on: [checks-backend] --- kind: pipeline @@ -94,33 +137,18 @@ workspace: services: - name: mysql - pull: default image: mysql:5.7 environment: MYSQL_ALLOW_EMPTY_PASSWORD: yes MYSQL_DATABASE: test - GOPROXY: off - TAGS: bindata sqlite sqlite_unlock_notify - GITLAB_READ_TOKEN: - from_secret: gitlab_read_token - depends_on: - - build - when: - branch: - - master - event: - - push - - pull_request - name: mysql8 - pull: default image: mysql:8.0 environment: MYSQL_ALLOW_EMPTY_PASSWORD: yes MYSQL_DATABASE: testgitea - name: mssql - pull: default image: mcr.microsoft.com/mssql/server:latest environment: ACCEPT_EULA: Y @@ -128,18 +156,23 @@ services: SA_PASSWORD: MwantsaSecurePassword1 - name: ldap - pull: default image: gitea/test-openldap:latest - name: elasticsearch - pull: default environment: discovery.type: single-node image: elasticsearch:7.5.0 + - name: minio + image: minio/minio:RELEASE.2020-10-09T22-55-05Z + commands: + - minio server /data + environment: + MINIO_ACCESS_KEY: 123456 + MINIO_SECRET_KEY: 12345678 + steps: - name: fetch-tags - pull: default image: docker:git commands: - git fetch --tags --force @@ -150,7 +183,7 @@ steps: - name: build pull: always - image: golang:1.14 + image: golang:1.15 commands: - make backend environment: @@ -165,8 +198,7 @@ steps: - git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA} - name: unit-test - pull: always - image: golang:1.14 + image: golang:1.15 commands: - make unit-test-coverage test-check environment: @@ -175,9 +207,19 @@ steps: GITHUB_READ_TOKEN: from_secret: github_read_token - - name: test-mysql + - name: unit-test-gogit pull: always - image: golang:1.14 + image: golang:1.15 + commands: + - make unit-test-coverage test-check + environment: + GOPROXY: off + TAGS: bindata gogit sqlite sqlite_unlock_notify + GITHUB_READ_TOKEN: + from_secret: github_read_token + + - name: test-mysql + image: golang:1.15 commands: - "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash" - apt-get install -y git-lfs @@ -187,12 +229,12 @@ steps: TAGS: bindata TEST_LDAP: 1 USE_REPO_TEST_DIR: 1 + TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200" depends_on: - build - name: test-mysql8 - pull: always - image: golang:1.14 + image: golang:1.15 commands: - "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash" - apt-get install -y git-lfs @@ -206,8 +248,7 @@ steps: - build - name: test-mssql - pull: always - image: golang:1.14 + image: golang:1.15 commands: - "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash" - apt-get install -y git-lfs @@ -221,8 +262,7 @@ steps: - build - name: generate-coverage - pull: always - image: golang:1.14 + image: golang:1.15 commands: - make coverage environment: @@ -238,14 +278,13 @@ steps: - push - pull_request - - name: coverage + - name: coverage-codecov pull: always - image: robertstettner/drone-codecov + image: plugins/codecov settings: files: - coverage.all - environment: - CODECOV_TOKEN: + token: from_secret: codecov_token depends_on: - generate-coverage @@ -285,7 +324,6 @@ services: steps: - name: fetch-tags - pull: default image: docker:git commands: - git fetch --tags --force @@ -296,7 +334,7 @@ steps: - name: build pull: always - image: golang:1.14 + image: golang:1.15 commands: - make backend environment: @@ -305,29 +343,29 @@ steps: TAGS: bindata sqlite sqlite_unlock_notify - name: test-sqlite - pull: always - image: golang:1.14 + image: golang:1.15 commands: - "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash" - apt-get install -y git-lfs - timeout -s ABRT 40m make test-sqlite-migration test-sqlite environment: GOPROXY: off - TAGS: bindata + TAGS: bindata gogit sqlite sqlite_unlock_notify + TEST_TAGS: gogit sqlite sqlite_unlock_notify USE_REPO_TEST_DIR: 1 depends_on: - build - name: test-pgsql - pull: always - image: golang:1.14 + image: golang:1.15 commands: - "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash" - apt-get install -y git-lfs - timeout -s ABRT 40m make test-pgsql-migration test-pgsql environment: GOPROXY: off - TAGS: bindata + TAGS: bindata gogit + TEST_TAGS: gogit TEST_LDAP: 1 USE_REPO_TEST_DIR: 1 depends_on: @@ -366,7 +404,7 @@ steps: - name: update pull: default - image: alpine:3.12 + image: alpine:3.13 commands: - ./build/update-locales.sh @@ -395,6 +433,45 @@ steps: CROWDIN_KEY: from_secret: crowdin_key +--- +kind: pipeline +name: update_gitignore_and_licenses + +platform: + os: linux + arch: amd64 + +workspace: + base: /go + path: src/code.gitea.io/gitea + +trigger: + branch: + - master + event: + - cron + cron: + - update_gitignore_and_licenses + +steps: + - name: download + image: golang:1.15 + commands: + - timeout -s ABRT 40m make generate-license generate-gitignore + + - name: push + pull: always + image: appleboy/drone-git-push + settings: + author_email: "teabot@gitea.io" + author_name: GiteaBot + commit: true + commit_message: "[skip ci] Updated licenses and gitignores " + remote: "git@github.com:go-gitea/gitea.git" + environment: + GIT_PUSH_SSH_KEY: + from_secret: git_push_ssh_key + --- kind: pipeline name: release-latest @@ -421,17 +498,15 @@ depends_on: steps: - name: fetch-tags - pull: default image: docker:git commands: - git fetch --tags --force - name: static pull: always - image: techknowlogick/xgo:go-1.14.x + image: techknowlogick/xgo:go-1.15.x commands: - - apt update && apt -y install curl - - curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt -y install nodejs + - curl -sL https://deb.nodesource.com/setup_14.x | bash - && apt -y install nodejs - export PATH=$PATH:$GOPATH/bin - make release environment: @@ -476,7 +551,6 @@ steps: - push - name: release-master - pull: always image: plugins/s3:1 settings: acl: public-read @@ -526,10 +600,9 @@ steps: - name: static pull: always - image: techknowlogick/xgo:go-1.14.x + image: techknowlogick/xgo:go-1.15.x commands: - - apt update && apt -y install curl - - curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt -y install nodejs + - curl -sL https://deb.nodesource.com/setup_14.x | bash - && apt -y install nodejs - export PATH=$PATH:$GOPATH/bin - make release environment: @@ -636,7 +709,6 @@ trigger: steps: - name: fetch-tags - pull: default image: docker:git commands: - git fetch --tags --force @@ -659,6 +731,27 @@ steps: exclude: - pull_request + - name: publish-rootless + image: plugins/docker:linux-amd64 + settings: + dockerfile: Dockerfile.rootless + auto_tag: true + auto_tag_suffix: linux-amd64-rootless + repo: gitea/gitea + build_args: + - GOPROXY=off + password: + from_secret: docker_password + username: + from_secret: docker_username + environment: + PLUGIN_MIRROR: + from_secret: plugin_mirror + when: + event: + exclude: + - pull_request + --- kind: pipeline name: docker-linux-arm64-dry-run @@ -688,6 +781,9 @@ steps: tags: linux-arm64 build_args: - GOPROXY=off + environment: + PLUGIN_MIRROR: + from_secret: plugin_mirror when: event: - pull_request @@ -714,7 +810,6 @@ trigger: - "refs/tags/**" steps: - name: fetch-tags - pull: default image: docker:git commands: - git fetch --tags --force @@ -732,6 +827,30 @@ steps: from_secret: docker_password username: from_secret: docker_username + environment: + PLUGIN_MIRROR: + from_secret: plugin_mirror + when: + event: + exclude: + - pull_request + + - name: publish-rootless + image: plugins/docker:linux-arm64 + settings: + dockerfile: Dockerfile.rootless + auto_tag: true + auto_tag_suffix: linux-arm64-rootless + repo: gitea/gitea + build_args: + - GOPROXY=off + password: + from_secret: docker_password + username: + from_secret: docker_username + environment: + PLUGIN_MIRROR: + from_secret: plugin_mirror when: event: exclude: @@ -746,8 +865,19 @@ platform: arch: amd64 steps: - - name: manifest + - name: manifest-rootless pull: always + image: plugins/manifest + settings: + auto_tag: true + ignore_missing: true + spec: docker/manifest.rootless.tmpl + password: + from_secret: docker_password + username: + from_secret: docker_username + + - name: manifest image: plugins/manifest settings: auto_tag: true diff --git a/.editorconfig b/.editorconfig index 5b3a4ff79fdcc..54738e8838d66 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,25 +1,22 @@ root = true [*] +indent_style = space +indent_size = 2 +tab_width = 2 +end_of_line = lf charset = utf-8 -insert_final_newline = true trim_trailing_whitespace = true -end_of_line = lf - -[*.md] -trim_trailing_whitespace = false +insert_final_newline = true [*.{go,tmpl,html}] indent_style = tab -indent_size = 4 - -[*.{less,css}] -indent_style = space -indent_size = 4 - -[*.{js,json,yml}] -indent_style = space -indent_size = 2 [Makefile] indent_style = tab + +[*.svg] +insert_final_newline = false + +[*.md] +trim_trailing_whitespace = false diff --git a/.eslintrc b/.eslintrc index 1a7551aee7480..0a56f6aaadaf3 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,20 +3,25 @@ reportUnusedDisableDirectives: true ignorePatterns: - /web_src/js/vendor + - /templates/base/head.tmpl + - /templates/repo/activity.tmpl + - /templates/repo/view_file.tmpl parserOptions: sourceType: module - ecmaVersion: 2020 + ecmaVersion: 2021 plugins: - eslint-plugin-unicorn - eslint-plugin-import - - eslint-plugin-sonarjs + - eslint-plugin-vue + - eslint-plugin-html + +extends: + - plugin:vue/recommended env: - browser: true - es6: true - jquery: true + es2021: true node: true globals: @@ -25,12 +30,29 @@ globals: Dropzone: false SimpleMDE: false u2fApi: false - Tribute: false + +settings: + html/html-extensions: [".tmpl"] overrides: - - files: ["web_src/**/*.worker.js", "web_src/js/serviceworker.js"] + - files: ["web_src/**/*.js", "web_src/**/*.vue", "templates/**/*.tmpl"] + env: + browser: true + jquery: 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] + - files: ["build/generate-images.js"] + rules: + import/no-unresolved: [0] + import/no-extraneous-dependencies: [0] rules: accessor-pairs: [2] @@ -92,7 +114,7 @@ rules: import/no-amd: [0] import/no-anonymous-default-export: [0] import/no-commonjs: [0] - import/no-cycle: [0] + import/no-cycle: [2, {ignoreExternal: true}] import/no-default-export: [0] import/no-deprecated: [0] import/no-dynamic-require: [0] @@ -110,13 +132,13 @@ rules: import/no-self-import: [2] import/no-unassigned-import: [0] import/no-unresolved: [2, {commonjs: true}] - import/no-unused-modules: [0] + import/no-unused-modules: [2, {unusedExports: true}] import/no-useless-path-segments: [2, {commonjs: true}] import/no-webpack-loader-syntax: [2] import/order: [0] import/prefer-default-export: [0] import/unambiguous: [0] - indent: [2, 2, {ignoreComments: true, SwitchCase: 1}] + indent: [2, 2, {SwitchCase: 1}] init-declarations: [0] key-spacing: [2] keyword-spacing: [2] @@ -165,7 +187,7 @@ rules: no-dupe-keys: [2] no-duplicate-case: [2] no-duplicate-imports: [2] - no-else-return: [0] + no-else-return: [2] no-empty-character-class: [2] no-empty-function: [0] no-empty-pattern: [2] @@ -204,7 +226,7 @@ rules: no-mixed-operators: [0] no-mixed-spaces-and-tabs: [2] no-multi-assign: [0] - no-multi-spaces: [2, {ignoreEOLComments: true, exceptions: {Property: true, VariableDeclarator: true}}] + no-multi-spaces: [2, {ignoreEOLComments: true, exceptions: {Property: true}}] no-multi-str: [2] no-negated-condition: [0] no-nested-ternary: [0] @@ -213,17 +235,19 @@ rules: no-new-symbol: [2] no-new-wrappers: [2] no-new: [0] + no-nonoctal-decimal-escape: [2] no-obj-calls: [2] no-octal-escape: [2] no-octal: [2] no-param-reassign: [0] no-plusplus: [0] + no-promise-executor-return: [0] no-proto: [2] no-prototype-builtins: [2] no-redeclare: [2] no-regex-spaces: [2] no-restricted-exports: [0] - no-restricted-globals: [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-imports: [0] no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement] no-return-assign: [0] @@ -249,6 +273,7 @@ rules: no-unexpected-multiline: [2] no-unmodified-loop-condition: [2] no-unneeded-ternary: [0] + no-unreachable-loop: [2] no-unreachable: [2] no-unsafe-finally: [2] no-unsafe-negation: [2] @@ -264,7 +289,7 @@ rules: no-useless-constructor: [2] no-useless-escape: [2] no-useless-rename: [2] - no-useless-return: [0] + no-useless-return: [2] no-var: [2] no-void: [2] no-warning-comments: [0] @@ -303,31 +328,6 @@ rules: semi-spacing: [2, {before: false, after: true}] semi-style: [2, last] semi: [2, always, {omitLastInOneLineBlock: true}] - sonarjs/cognitive-complexity: [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-extra-arguments: [0] - sonarjs/no-identical-conditions: [2] - sonarjs/no-identical-expressions: [0] - sonarjs/no-identical-functions: [0] - sonarjs/no-inverted-boolean-check: [2] - 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/prefer-immediate-return: [0] - sonarjs/prefer-object-literal: [2] - sonarjs/prefer-single-boolean-return: [0] - sonarjs/prefer-while: [2] sort-imports: [0] sort-keys: [0] sort-vars: [0] @@ -346,12 +346,14 @@ rules: unicorn/catch-error-name: [0] unicorn/consistent-function-scoping: [2] unicorn/custom-error-definition: [0] + unicorn/empty-brace-spaces: [2] unicorn/error-message: [0] unicorn/escape-case: [0] unicorn/expiring-todo-comments: [0] unicorn/explicit-length-check: [0] unicorn/filename-case: [0] unicorn/import-index: [0] + unicorn/import-style: [0] unicorn/new-for-builtins: [2] unicorn/no-abusive-eslint-disable: [0] unicorn/no-array-instanceof: [0] @@ -360,9 +362,11 @@ rules: unicorn/no-for-loop: [0] unicorn/no-hex-escape: [0] unicorn/no-keyword-prefix: [0] + unicorn/no-lonely-if: [2] unicorn/no-nested-ternary: [0] unicorn/no-new-buffer: [0] unicorn/no-null: [0] + unicorn/no-object-as-default-parameter: [2] unicorn/no-process-exit: [0] unicorn/no-reduce: [2] unicorn/no-unreadable-array-destructuring: [0] @@ -371,10 +375,14 @@ rules: unicorn/no-useless-undefined: [0] unicorn/no-zero-fractions: [2] unicorn/number-literal-case: [0] + unicorn/numeric-separators-style: [0] unicorn/prefer-add-event-listener: [2] + unicorn/prefer-array-find: [2] unicorn/prefer-dataset: [2] + unicorn/prefer-date-now: [2] unicorn/prefer-event-key: [2] unicorn/prefer-includes: [2] + unicorn/prefer-math-trunc: [2] unicorn/prefer-modern-dom-apis: [0] unicorn/prefer-negative-index: [2] unicorn/prefer-node-append: [0] @@ -388,6 +396,7 @@ rules: unicorn/prefer-spread: [0] unicorn/prefer-starts-ends-with: [2] unicorn/prefer-string-slice: [0] + unicorn/prefer-ternary: [0] unicorn/prefer-text-content: [2] unicorn/prefer-trim-start-end: [2] unicorn/prefer-type-error: [0] @@ -397,6 +406,11 @@ 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/.gitattributes b/.gitattributes index f76f5a63821de..e8d2162cf8119 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,10 +1,6 @@ * text=auto eol=lf -/vendor/** -text -eol -/public/vendor/** -text -eol - -conf/* linguist-vendored -docker/* linguist-vendored -options/* linguist-vendored -public/* linguist-vendored -build/* linguist-vendored -templates/* linguist-vendored +/vendor/** -text -eol linguist-vendored +/public/vendor/** -text -eol linguist-vendored +/templates/**/*.tmpl linguist-language=Handlebars +/.eslintrc linguist-language=YAML +/.stylelintrc linguist-language=YAML diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 1447a6ea322bf..624a2d97db19f 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1,2 @@ open_collective: gitea +custom: https://www.bountysource.com/teams/gitea diff --git a/.github/issue_template.md b/.github/issue_template.md index ab2b73c565dc3..69ff704bbc142 100644 --- a/.github/issue_template.md +++ b/.github/issue_template.md @@ -2,16 +2,20 @@ - Gitea version (or commit ref): - Git version: - Operating system: + + + - Database (use `[x]`): - [ ] PostgreSQL - [ ] MySQL @@ -20,8 +24,10 @@ - Can you reproduce the bug at https://try.gitea.io: - [ ] Yes (provide example URL) - [ ] No - - [ ] Not relevant - Log gist: + + + ## Description diff --git a/.github/lock.yml b/.github/lock.yml new file mode 100644 index 0000000000000..6beadcaf11095 --- /dev/null +++ b/.github/lock.yml @@ -0,0 +1,23 @@ +# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app + +# Number of days of inactivity before a closed issue or pull request is locked +daysUntilLock: 60 + +# Skip issues and pull requests created before a given timestamp. Timestamp must +# follow ISO 8601 (`YYYY-MM-DD`). `false` is disabled +skipCreatedBefore: false + +# Issues and pull requests with these labels will be ignored. +exemptLabels: [] + +# Label to add before locking, such as `outdated`. `false` is disabled +lockLabel: false + +# Comment to post before locking. +lockComment: > + This thread has been automatically locked since there has not been + any recent activity after it was closed. Please open a new issue for + related bugs and link to relevant comments in this thread. + +# Assign `resolved` as the reason for locking. Set to `false` to disable +setLockReason: true diff --git a/.gitignore b/.gitignore index 9c4a15c9cccde..8d8863546a1b4 100644 --- a/.gitignore +++ b/.gitignore @@ -53,7 +53,7 @@ coverage.all /custom/* !/custom/conf /custom/conf/* -!/custom/conf/app.ini.sample +!/custom/conf/app.example.ini /data /indexers /log @@ -79,9 +79,20 @@ coverage.all /public/serviceworker.js /public/css /public/fonts -/public/fomantic -/public/img/svg +/public/img/webpack +/web_src/fomantic/build/* +!/web_src/fomantic/build/semantic.js +!/web_src/fomantic/build/semantic.css +!/web_src/fomantic/build/themes +/web_src/fomantic/build/themes/* +!/web_src/fomantic/build/themes/default +/web_src/fomantic/build/themes/default/assets/* +!/web_src/fomantic/build/themes/default/assets/fonts +/web_src/fomantic/build/themes/default/assets/fonts/* +!/web_src/fomantic/build/themes/default/assets/fonts/icons.woff2 +!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2 /VERSION +/.air # Snapcraft snap/.snapcraft/ diff --git a/.golangci.yml b/.golangci.yml index 0bd71b7fb1d72..34752127e006a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -70,7 +70,7 @@ issues: - path: modules/log/ linters: - errcheck - - path: routers/routes/routes.go + - path: routers/routes/macaron.go linters: - dupl - path: routers/api/v1/repo/issue_subscription.go @@ -98,3 +98,15 @@ issues: - path: models/update.go linters: - unused + - path: cmd/dump.go + linters: + - dupl + - path: services/webhook/webhook.go + linters: + - structcheck + - text: "commentFormatting: put a space between `//` and comment text" + linters: + - gocritic + - text: "exitAfterDefer:" + linters: + - gocritic diff --git a/.ignore b/.ignore index cb51f92f7883c..7decea94e02b4 100644 --- a/.ignore +++ b/.ignore @@ -1,6 +1,5 @@ /vendor /public/vendor/plugins -/public/vendor/assets /modules/options/bindata.go /modules/public/bindata.go /modules/templates/bindata.go diff --git a/.npmrc b/.npmrc index dc8b06aad23d2..c5ac9901c938c 100644 --- a/.npmrc +++ b/.npmrc @@ -1,2 +1,4 @@ +audit=false +fund=false package-lock=true save-exact=true diff --git a/.stylelintrc b/.stylelintrc index 102b90f1fdaf1..1d95b964bd287 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -1,17 +1,15 @@ extends: stylelint-config-standard -ignoreFiles: - - web_src/less/vendor/**/* - rules: at-rule-empty-line-before: null block-closing-brace-empty-line-before: null color-hex-length: null comment-empty-line-before: null + declaration-block-single-line-max-declarations: null declaration-empty-line-before: null - indentation: 4 + indentation: 2 no-descending-specificity: null number-leading-zero: never rule-empty-line-before: null - selector-pseudo-element-colon-notation: null + selector-pseudo-element-colon-notation: double shorthand-property-no-redundant-values: true diff --git a/CHANGELOG.md b/CHANGELOG.md index bfcd1c6b9bea0..020212043fa21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,826 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.13.1](https://github.com/go-gitea/gitea/releases/tag/v1.13.1) - 2020-12-29 + +* SECURITY + * Hide private participation in Orgs (#13994) (#14031) + * Fix escaping issue in diff (#14153) (#14154) +* BUGFIXES + * Fix bug of link query order on markdown render (#14156) (#14171) + * Drop long repo topics during migration (#14152) (#14155) + * Ensure that search term and page are not lost on adoption page-turn (#14133) (#14143) + * Fix storage config implementation (#14091) (#14095) + * Fix panic in BasicAuthDecode (#14046) (#14048) + * Always wait for the cmd to finish (#14006) (#14039) + * Don't use simpleMDE editor on mobile devices for 1.13 (#14029) + * Fix incorrect review comment diffs (#14002) (#14011) + * Trim the branch prefix from action.GetBranch (#13981) (#13986) + * Ensure template renderer is available before storage handler (#13164) (#13982) + * Whenever the password is updated ensure that the hash algorithm is too (#13966) (#13967) + * Enforce setting HEAD in wiki to master (#13950) (#13961) + * Fix feishu webhook caused by API changed (#13938) + * Fix Quote Reply button on review diff (#13830) (#13898) + * Fix Pull Merge when tag with same name as base branch exist (#13882) (#13896) + * Fix mermaid chart size (#13865) + * Fix branch/tag notifications in mirror sync (#13855) (#13862) + * Fix crash in short link processor (#13839) (#13841) + * Update font stack to bootstrap's latest (#13834) (#13837) + * Make sure email recipients can see issue (#13820) (#13827) + * Reply button is not removed when deleting a code review comment (#13824) + * When reinitialising DBConfig reset the database use flags (#13796) (#13811) +* ENHANCEMENTS + * Add emoji in label to project boards (#13978) (#14021) + * Send webhook when tag is removed via Web UI (#14015) (#14019) + * Use Process Manager to create own Context (#13792) (#13793) +* API + * GetCombinedCommitStatusByRef always return json & swagger doc fixes (#14047) + * 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) + * Disallow urlencoded new lines in git protocol paths if there is a port (#13521) (#13524) + * Mitigate Security vulnerability in the git hook feature (#13058) + * Disable DSA ssh keys by default (#13056) + * Set TLS minimum version to 1.2 (#12689) + * Use argon as default password hash algorithm (#12688) +* BREAKING + * Set RUN_MODE prod by default (#13765) (#13767) + * Don't replace underscores in auto-generated IDs in goldmark (#12805) + * Add Primary Key to Topic and RepoTopic tables (#12639) + * Disable password complexity check default (#12557) + * Change PIDFile default from /var/run/gitea.pid to /run/gitea.pid (#12500) + * Add extension Support to Attachments (allow all types for releases) (#12465) + * Remove IE11 Support (#11470) +* FEATURES + * Adopt repositories (#12920) + * Check passwords against HaveIBeenPwned (#12716) + * Gitea 2 Gitea migration (#12657) + * Support storing Avatars in minio (#12516) + * Allow addition of gpg keyring with multiple keys (#12487) + * Add email notify for new release (#12463) + * Add Access-Control-Expose-Headers (#12446) + * UserProfile Page: Render Description (#12415) + * Add command to recreate tables (#12407) + * Add mermaid JS renderer (#12334) + * Add ssh certificate support (#12281) + * Add spent time to referenced issue in commit message (#12220) + * Initial support for push options (#12169) + * Provide option to unlink a fork (#11858) + * Show exact tag for commit on diff view (#11846) + * Pause, Resume, Release&Reopen, Add and Remove Logging from command line (#11777) + * Issue templates directory (#11450) + * Add a storage layer for attachments (#11387) + * Add hide activity option (#11353) + * Add push commits history comment on PR time-line (#11167) + * Support elastic search for code search (#10273) + * Kanban board (#8346) +* API + * If User is Admin, show 500 error message on PROD mode too (#13115) + * Add Timestamp to Tag list API (#13026) + * Return sample message for login error in api context (#12994) + * Add IsTemplate option in create repo ui and api (#12942) + * GetReleaseByID return 404 if not found (#12933) + * Get release by tags endpoint (#12932) + * NotificationSubject show Issue/Pull State (#12901) + * Expose its limitation settings (#12714) + * Add Created & Updated to Milestone (#12662) + * Milestone endpoints accept names too (#12649) + * Expose Attachment Settings in the API (#12514) + * Add Issue and Repo info to StopWatch (#12458) + * Add cron running API (#12421) + * Add Update Pull HeadBranch Function (#12419) + * Add TOTP header to Swagger Documentation (#12402) + * Delete Token accept names too (#12366) + * Add name filter for GetMilestoneList (#12336) + * Fixed count of filtered issues when api request. (#12275) + * Do not override API issue pagination with UI settings (#12068) + * Expose useful General Repo settings settings (#11758) + * Return error when trying to create Mirrors but Mirrors are globally disabled (#11757) + * Provide diff and patch API endpoints (#11751) + * Allow to create closed milestones (#11745) + * Add language Statistics endpoint (#11737) + * Add Endpoint to get GetGeneralUI Settings (#11735) & (#11854) + * Issue/Pull expose IsLocked Property on API (#11708) + * Add endpoint for Branch Creation (#11607) + * Add pagination headers on endpoints that support total count from database (#11145) +* BUGFIXES + * Fix bogus http requests on diffs (#13760) (#13761) + * Show 'owner' tag for real owner (#13689) (#13743) + * Validate email before inserting/updating (#13475) (#13666) + * Fix issue/pull request list assignee filter (#13647) (#13651) + * Gitlab migration support for subdirectories (#13563) (#13591) + * Fix logic for preferred license setting (#13550) (#13557) + * Add missed sync branch/tag webhook (#13538) (#13556) + * Migration won't fail on non-migrated reactions (#13507) + * Fix Italian language file parsing error (#13156) + * Show outdated comments in pull request (#13148) (#13162) + * Fix parsing of pre-release git version (#13169) (#13172) + * Fix diff skipping lines (#13154) (#13155) + * When handling errors in storageHandler check underlying error (#13178) (#13193) + * Fix size and clickable area on file table back link (#13205) (#13207) + * Add better error checking for inline html diff code (#13251) + * Fix initial commit page & binary munching problem (#13249) (#13258) + * Fix migrations from remote Gitea instances when configuration not set (#13229) (#13273) + * Store task errors following migrations and display them (#13246) (#13287) + * Fix bug isEnd detection on getIssues/getPullRequests (#13299) (#13301) + * When the git ref is unable to be found return broken pr (#13218) (#13303) + * Ensure topics added using the API are added to the repository (#13285) (#13302) + * Fix avatar autogeneration (#13233) (#13282) + * Add migrated pulls to pull request task queue (#13331) (#13334) + * Issue comment reactions should also check pull type on API (#13349) (#13350) + * Fix links to repositories in /user/setting/repos (#13360) (#13362) + * Remove obsolete change of email on profile page (#13341) (#13347) + * Fix scrolling to resolved comment anchors (#13343) (#13371) + * Storage configuration support `[storage]` (#13314) (#13379) + * When creating line diffs do not split within an html entity (#13357) (#13375) (#13425) (#13427) + * Fix reactions on code comments (#13390) (#13401) + * Add missing full names when DEFAULT_SHOW_FULL_NAME is enabled (#13424) + * Replies to outdated code comments should also be outdated (#13217) (#13433) + * Fix panic bug in handling multiple references in commit (#13486) (#13487) + * Prevent panic on git blame by limiting lines to 4096 bytes at most (#13470) (#13491) + * Show original author's reviews on pull summary box (#13127) + * Update golangci-lint to version 1.31.0 (#13102) + * Fix line break for MS teams webhook (#13081) + * Fix Issue & Pull Request comment headers on mobile (#13039) + * Avoid setting the CONN_STR in queues unless it is meant to be set (#13025) + * Remove code-view class from diff view (#13011) + * Fix the color of PR comment hyperlinks. (#13009) + * (Re)Load issue labels when changing them (#13007) + * Fix Media links in org files not liked to media files (#12997) + * Always return a list from GetCommitsFromIDs (#12981) + * Only set the user password if the password field would have been shown (#12980) + * Fix admin/config page (#12979) + * Changed width of commit signature avatar (#12961) + * Completely quote AppPath and CustomConf paths (#12955) + * Fix handling of migration errors (#12928) + * Fix anonymous GL migration (#12862) + * Fix git open close bug (#12834) + * Fix markdown meta parsing (#12817) + * Add default storage configurations (#12813) + * Show PR settings on empty repos (#12808) + * Disable watch and star if not signed in (#12807) + * Whilst changing the character set to utf8mb4 we should set ROW_FORMAT=dynamic too (#12804) + * Set opengraph attributes on org pages (#12803) + * Return error when creating gitlabdownloader failed (#12790) + * Add migration for password algorithm change (#12784) + * Compare SSH_DOMAIN when parsing submodule URLs (#12753) + * Fix editor.commit_empty_file_text locale string (#12744) + * Fix wrong poster message for code comment on Pull view (#11721) + * Escape failed highlighted files (#12685) + * Ensure that all migration requests are cancellable (#12669) + * Ensure RepoPath is lowercased in gitea serv (#12668) + * Do not disable commit changes button on repost (#12644) + * Dark theme for line numbers in blame view (#12632) + * Fix message when deleting last owner from an organization (#12628) + * Use shellquote to unpack arguments to gitea serv (#12624) + * Fix signing.wont_sign.%!s() if Require Signing commits but not signed in. (#12581) + * Set utf8mb4 as the default charset on MySQL if CHARSET is unset (#12563) + * Set context for running CreateArchive to that of the request (#12555) + * Prevent redirect back to /user/events (#12462) + * Re-attempt to delete temporary upload if the file is locked by another process (#12447) + * Mirror System Notice reports are too frequent (#12438) + * Do not show arrows on comment diffs on pull comment pages (#12434) + * Fix milestone links (#12405) + * Increase size of the language column in language_stat (#12396) + * Use transaction in V102 migration (#12395) + * Only use --exclude on name-rev with git >= 2.13 (#12347) + * Add action feed for new release (#12324) + * Set NoAutoTime when updating is_archived (#12266) + * Support Force-update in Mirror and improve Tracing in mirror (#12242) + * Avoid sending "0 new commits" webhooks (#12212) + * Fix U2F button icon (#12167) + * models/repo_sign.go: break out of loops (#12159) + * Ensure that git commit tree continues properly over the page (#12142) + * Rewrite GitGraph.js (#12137) + * Fix repo API listing stability (#12057) + * Add team support for review request (#12039) + * Fix 500 error on repos with no tags (#11870) + * Fix nil pointer in default issue mail template (#11862) + * Fix commit search in all branches (#11849) + * Don't consider tag refs as valid for branch name (#11847) + * Don't add same line code comment box twice (#11837) + * Fix visibility of forked public repos from private orgs (#11717) + * Fix chardet test and add ordering option (#11621) + * Fix number of files, total additions, and deletions on Diff pages (#11614) + * Properly handle and return empty string for dangling commits in GetBranchName (#11587) + * Include query in sign in redirect (#11579) + * Fix Enter not working in SimpleMDE (#11564) + * Fix bug about can't skip commits base on base branch (#11555) +* ENHANCEMENTS + * Only Return JSON for responses (#13511) (#13565) + * Use existing analyzer module for language detection for highlighting (#13522) (#13551) + * Return the full rejection message and errors in flash errors (#13221) (#13237) + * Remove PAM from auth dropdown when unavailable (#13276) (#13281) + * Add HostCertificate to sshd_config in Docker image (#13143) + * Save TimeStamps for Star, Label, Follow, Watch and Collaboration to Database (#13124) + * Improve error feedback for duplicate deploy keys (#13112) + * Set appropriate `autocomplete` attributes on password fields (#13078) + * Adding visual cue for "Limited" & "Private" organizations. (#13040) + * Fix Pull Request merge buttons on mobile (#13035) + * Gitea serv, hooks, manager and the like should always display Fatals (#13032) + * CSS tweaks to warning/error segments and misc fixes (#13024) + * Fix formatting of branches ahead-behind on narrow windows (#12989) + * Add config option to make create-on-push repositories public by default (#12936) + * Disable migration items when mirror is selected (#12918) + * Add the checkbox quick button to the comment tool bar also (#12885) + * Support GH enterprise (#12863) + * Simplify CheckUnitUser logic (#12854) + * Fix background of signed-commits on arc-green of timeline commits (#12837) + * Move git update-server-info to hooks (#12826) + * Add ui style for "Open a blank issue" button (#12824) + * Use a simple format for the big number on ui (#12822) + * Make SVG size argument optional (#12814) + * Add placeholder text for bio profile text form (#12792) + * Set language via AJAX (#12785) + * Show git-pull-request icon for closed pull request (#12742) + * Migrate version parsing library to hashicorp/go-version (#12719) + * Only use async pre-empt hack if go < 1.15 (#12718) + * Inform user about meaning of an hourglass on reviews (#12713) + * Add a migrate service type switch page (#12697) + * Migrations: Gitlab Add Reactions Support for Issues & MergeRequests (#12695) + * Remove duplicate logic in initListSubmits (#12660) + * Set avatar image dimensions (#12654) + * Rename models.ProtectedBranchRepoID/PRID to models.EnvRepoID/PRID and ensure EnvPusherEmail is set (#12646) + * Set setting.AppURL as GITEA_ROOT_URL environment variable during pushes (#12752) + * Add postgres schema to the search_path on database connection (#12634) + * Git migration UX improvements (#12619) + * Add link to home page on swagger ui (#12601) + * hCaptcha Support (#12594) + * OpenGraph: use repo avatar if exist (#12586) + * Reaction picker display improvements (#12576) + * Fix emoji replacements, make emoji images consistent (#12567) + * Increase clickable area on files table links (#12553) + * Set z-index for sticky diff box lower (#12537) + * Report error if API merge is not allowed (#12528) + * LFS support to be stored on minio (#12518) + * Show 2FA info on Admin Pannel: Users List (#12515) + * Milestone Issue/Pull List: Add octicons type (#12499) + * Make dashboard newsfeed list length a configurable item (#12469) + * Add placeholder text for send testing email button in admin/config (#12452) + * Add SVG favicon (#12437) + * In issue comments, put issue participants also in completion list when hitting @ (#12433) + * Collapse Swagger UI tags by default (#12428) + * Detect full references to issues and pulls in commit messages (#12399) + * Allow common redis and leveldb connections (#12385) + * Don't use legacy method to send Matrix Webhook (#12348) + * Remove padding/border-radius on image diffs (#12346) + * Render the git graph on the server (#12333) + * Fix clone panel in wiki position not always align right (#12326) + * Rework 'make generate-images' (#12316) + * Refactor webhook payload convertion (#12310) + * Move jquery-minicolors to npm/webpack (#12305) + * Support use nvarchar for all varchar columns when using mssql (#12269) + * Update Octicons to v10 (#12240) + * Disable search box autofocus (#12229) + * Replace code fold icons with octicons (#12222) + * Ensure syntax highlighting is the same inside diffs (#12205) + * Auto-init repo on license, .gitignore select (#12202) + * Default to showing closed Issues/PR list when there are only closed issues/PRs (#12200) + * Enable cloning via Git Wire Protocol v2 over HTTP (#12170) + * Direct SVG rendering (#12157) + * Improve arc-green code colors (#12111) + * Allow admin to merge pr with protected file changes (#12078) + * Show description on individual milestone view (#12055) + * Update the wiki repository remote origin while update the mirror repository's Clone From URL (#12053) + * Server-side syntax highlighting for all code (#12047) + * Use Fomantic's fluid padded for blame full width (#12023) + * Use custom SVGs for commit signing lock icon (#12017) + * Make tabs smaller (#12003) + * Fix sticky diff stats container (#12002) + * Move fomantic and jQuery to main webpack bundle (#11997) + * Use enry language type to detect special languages (#11974) + * Use only first line of commit when creating referenced comment (#11960) + * Rename custom/conf/app.ini.sample to custom/conf/app.example.ini for better syntax light on editor (#11926) + * Fix double divider on issue sidebar (#11919) + * Shorten markdown heading anchors links (#11903) + * Add org avatar on top of internal repo icon (#11895) + * Use label to describe repository type (#11891) + * Make repository size unclickable on repo summary bar (#11887) + * Rework blame template and styling (#11885) + * Fix icon alignment for show/hide outdated link on resolved conversation (#11881) + * Vertically align review icons on repository sidebar (#11880) + * Better align items using flex within review request box (#11879) + * Only write to global gitconfig if necessary (#11876) + * Disable all typographic replacements in markdown renderer (#11871) + * Improve label edit buttons labels (#11841) + * Use crispEdges rendering for octicon-internal-repo (#11801) + * Show update branch item in merge box when it's necessary (#11761) + * Add compare link to releases (#11752) + * Allow site admin to disable mirrors (#11740) + * Export monaco editor on window.codeEditors (#11739) + * Add configurable Trust Models (#11712) + * Show full GPG commit status on PR commit history (#11702) + * Fix align issues and decrease avatar size on PR timeline (#11689) + * Replace jquery-datetimepicker with native date input (#11684) + * Change Style of Tags on Comments (#11668) + * Fix missing styling for shabox on PR commit history (#11625) + * Apply padding to approval icons on PR list (#11622) + * Fix message wrapping on PR commit list (#11616) + * Right-align status icon on pull request commit history (#11594) + * Add missing padding for multi-commit list on PR view (#11593) + * Do not show avatar for "{{user}} added X commits" (#11591) + * Fix styling and padding for commit list on PR view (#11588) + * Style code review comment for arc-green (#11572) + * Use default commit message for wiki edits (#11550) + * Add internal-repo octicon for public repos of private org (#11529) + * Fix dropzone color on arc-green (#11514) + * Insert ui divider directly in templates instead of from inside heatmap vue component (#11508) + * Move tributejs to npm/webpack (#11497) + * Fix text-transform on wiki revisions page (#11486) + * Do not show lock icon on repo list for public repos in private org (#11445) + * Include LFS when calculating repo size (#11060) + * Add check for LDAP group membership (#10869) + * When starting new stopwatch stop previous if it is still running (#10533) + * Add queue for code indexer (#10332) + * Move all push update operations to a queue (#10133) + * Cache last commit when pushing for big repository (#10109) + * Change/remove a branch of an open issue (#9080) + * Sortable Tables Header By Click (#7980) +* TESTING + * Use community codecov drone plugin (#12468) + * Add more tests for diff highlighting (#12467) + * Don't put integration test data outside of test folder (#11746) + * Add debug option to hooks (#11624) + * Log slow tests (#11487) +* TRANSLATION + * Translate two small lables on commit statuse list (#12821) + * Make issues.force_push_codes message shorter (#11575) +* BUILD + * Bump min required golang to 1.13 (#12717) + * Add 'make watch' (#12636) + * Extract Swagger CSS to its own file (#12616) + * Update eslint config (#12609) + * Avoid unnecessary system-ui expansion (#12522) + * Make the default PID file compile-time settable (#12485) + * Add 'watch-backend' (#12330) + * Detect version of sed in Makefile (#12319) + * Update gitea-vet to v0.2.1 (#12282) + * Add logic to build stable and edge builds for gitea snap (#12052) + * Fix missing CGO_EXTRA_FLAGS build arg for docker (#11782) + * Alpine 3.12 (#11720) + * Enable stylelint's shorthand-property-no-redundant-values (#11436) +* DOCS + * Change default log configuration (#13088) + * Add automatic JS license generation (#11810) + * Remove page size limit comment from swagger (#11806) + * Narrow down Edge version in browser support docs (#11640) + +## [1.12.5](https://github.com/go-gitea/gitea/releases/tag/v1.12.5) - 2020-10-01 + +* BUGFIXES + * Allow U2F with default settings for gitea in subpath (#12990) (#13001) + * Prevent empty div when editing comment (#12404) (#12991) + * On mirror update also update address in DB (#12964) (#12967) + * Allow extended config on cron settings (#12939) (#12943) + * Open transaction when adding Avatar email-hash pairs to the DB (#12577) (#12940) + * Fix internal server error from ListUserOrgs API (#12910) (#12915) + * Update only the repository columns that need updating (#12900) (#12912) + * Fix panic when adding long comment (#12892) (#12894) + * Add size limit for content of comment on action ui (#12881) (#12890) + * Convert User expose ID each time (#12855) (#12883) + * Support slashes in release tags (#12864) (#12882) + * Add missing information to CreateRepo API endpoint (#12848) (#12867) + * On Migration respect old DefaultBranch (#12843) (#12858) + * Fix notifications page links (#12838) (#12853) + * Stop cloning unnecessarily on PR update (#12839) (#12852) + * Escape more things that are passed through str2html (#12622) (#12850) + * Remove double escape on labels addition in comments (#12809) (#12810) + * Fix "only mail on mention" bug (#12775) (#12789) + * Fix yet another bug with diff file names (#12771) (#12776) + * RepoInit Respect AlternateDefaultBranch (#12746) (#12751) + * Fix Avatar Resize (resize algo NearestNeighbor -> Bilinear) (#12745) (#12750) +* ENHANCEMENTS + * gitea dump: include version & Check InstallLock (#12760) (#12762) + +## [1.12.4](https://github.com/go-gitea/gitea/releases/tag/v1.12.4) - 2020-09-02 + +* SECURITY + * Escape provider name in oauth2 provider redirect (#12648) (#12650) + * Escape Email on password reset page (#12610) (#12612) + * When reading expired sessions - expire them (#12686) (#12690) +* ENHANCEMENTS + * StaticRootPath configurable at compile time (#12371) (#12652) +* BUGFIXES + * Fix to show an issue that is related to a deleted issue (#12651) (#12692) + * Expire time acknowledged for cache (#12605) (#12611) + * Fix diff path unquoting (#12554) (#12575) + * Improve HTML escaping helper (#12562) + * models: break out of loop (#12386) (#12561) + * Default empty merger list to those with write permissions (#12535) (#12560) + * Skip SSPI authentication attempts for /api/internal (#12556) (#12559) + * Prevent NPE on commenting on lines with invalidated comments (#12549) (#12550) + * Remove hardcoded ES indexername (#12521) (#12526) + * Fix bug preventing transfer to private organization (#12497) (#12501) + * Keys should not verify revoked email addresses (#12486) (#12495) + * Do not add prefix on http/https submodule links (#12477) (#12479) + * Fix ignored login on compare (#12476) (#12478) + * Fix incorrect error logging in Stats indexer and OAuth2 (#12387) (#12422) + * Upgrade google/go-github to v32.1.0 (#12361) (#12390) + * Render emoji's of Commit message on feed-page (#12373) + * Fix handling of diff on unrelated branches when Git 2.28 used (#12370) + +## [1.12.3](https://github.com/go-gitea/gitea/releases/tag/v1.12.3) - 2020-07-28 + +* BUGFIXES + * Don't change creation date when updating Release (#12343) (#12351) + * Show 404 page when release not found (#12328) (#12332) + * Fix emoji detection in certain cases (#12320) (#12327) + * Reduce emoji size (#12317) (#12327) + * Fix double-indirection bug in logging IDs (#12294) (#12308) + * Link to pull list page on sidebar when view pr (#12256) (#12263) + * Extend Notifications API and return pinned notifications by default (#12164) (#12232) + +## [1.12.2](https://github.com/go-gitea/gitea/releases/tag/v1.12.2) - 2020-07-11 + +* BUGFIXES + * When deleting repository decrese user repository count in cache (#11954) (#12188) + * Return full commit message instead of summary in commits API (#12186) (#12187) + * Properly set HEAD when a repo is created with a default branch that is not named 'master' (#12135) (#12182) + * Ensure GPG Subkeys are verified (#12155) (#12168) + * Fix failing to cache last commit with key being to long (#12151) (#12161) + * Multiple small admin dashboard fixes (#12153) (#12156) + * Remove spurious logging of " Delete all repository archives" at startup (#12139) (#12148) + * Fix repository setup instructions when default branch is not named 'master' (#12122) (#12147) + * Move EventSource to SharedWorker (#12095) (#12130) + * Fix ui bug in wiki commit page (#12089) (#12125) + * Fix gitgraph branch continues after merge (#12044) (#12105) + * Set the base url when migrating from Gitlab using access token or username without password (#11852) (#12104) + * Ensure BlameReaders close at end of request (#12102) (#12103) + * Fix panic when adding review comment (#12058) +* ENHANCEMENTS + * Disable dropzone's timeout for file uploads (#12024) (#12032) + +## [1.12.1](https://github.com/go-gitea/gitea/releases/tag/v1.12.1) - 2020-06-21 + +* BUGFIXES + * Handle multiple merges in gitgraph.js (#11996) (#12000) + * Add serviceworker.js to KnownPublicEntries (#11992) (#11994) + * For language detection do not try to analyze big files by content (#11971) (#11975) +* ENHANCEMENTS + * Fix scrollable header on dropdowns (#11893) (#11965) + +## [1.11.8](https://github.com/go-gitea/gitea/releases/tag/v1.11.8) - 2020-06-21 + +* BUGFIXES + * Really fix __webpack_public_path__ for 1.11 (#11961) + +## [1.12.0](https://github.com/go-gitea/gitea/releases/tag/v1.12.0) - 2020-06-17 + +* BREAKING + * When using API CreateRelease set created_unix to the tag commit time (#11218) + * Enable ENABLE_HARD_LINE_BREAK by default for rendering markdown (#11162) + * Fix sanitizer config - multiple rules (#11133) + * Remove check on username when using AccessToken authentication for the API (#11015) + * Return 404 from Contents API when items don't exist (#10323) + * Notification API should always return a JSON object with the current count of notifications (#10059) + * Remove migration support from versions earlier than 1.6.0 (#10026) +* SECURITY + * Use -1 to disable key algorithm type in ssh.minimum_key_sizes (#11635) (#11662) +* FEATURES + * Improve config logging when WrappedQueue times out (#11174) + * Add branch delete to API (#11112) + * Use markdown frontmatter to provide Table of contents, language and frontmatter rendering (#11047) + * Add a way to mark Conversation (code comment) resolved (#11037) + * Handle yaml frontmatter in markdown (#11016) + * Cache PullRequest Divergence (#10914) + * Make `gitea admin auth list` formatting configurable (#10844) + * Add Matrix webhook (#10831) + * Add Organization Wide Labels (#10814) + * Allow to set protected file patterns for files that can not be changed under no conditions (#10806) + * Option to set default branch at repository creation (#10803) + * Add request review from specific reviewers feature in pull request (#10756) + * Add NextCloud oauth (#10562) + * System-wide webhooks (#10546) + * Relax sanitization as per https://github.com/jch/html-pipeline (#10527) + * Use media links for img in post-process (#10515) + * Add API endpoints to manage OAuth2 Application (list/create/delete) (#10437) + * Render READMEs in docs/ .gitea or .github from root (#10361) + * Add feishu webhook support (#10229) + * Cache last commit to accelerate the repository directory page visit (#10069) + * Implement basic app.ini and path checks to doctor cmd (#10064) + * Make WorkerPools and Queues flushable (#10001) + * Implement "embedded" command to extract static resources (#9982) + * Add API endpoint for repo transfer (#9947) + * Make archive prefixing configurable with a global setting (#9943) + * Add Unique Queue infrastructure and move TestPullRequests to this (#9856) + * Issue/PR Context Popups (#9822) + * Add "Update Branch" button to Pull Requests (#9784) + * Add require signed commit for protected branch (#9708) + * Mark PR reviews as stale at push and allow to dismiss stale approvals (#9532) + * Add API notification endpoints (#9488) + * Issue search support elasticsearch (#9428) + * Add API branch protection endpoint (#9311) + * Add a new command doctor to check if some wrong configurations on gitea instance (#9095) + * Add support for migrating from Gitlab (#9084) + * Add support for database schema in PostgreSQL (#8819) + * Add setting to set default and global disabled repository units. (#8788) + * Language statistics bar for repositories (#8037) + * Restricted users (#6274) +* BUGFIXES + * Fix commenting on non-utf8 encoded files (#11916) (#11950) + * Use google/uuid to instead satori/go.uuid (#11943) (#11946) + * Align show/hide outdated button on code review block (#11932) (#11944) + * Update to go-git v5.1.0 (#11936) (#11941) + * Use ID or Where to instead directly use Get when load object from database (#11925) (#11934) + * Update CommitsAhead CommitsBehind on Pull BaseBranch Change too (#11912) (#11915) + * Invalidate comments when file is shortened (#11882) (#11884) + * Rework api/user/repos for pagination (#11827) (#11877) + * Handle more pathological branch and tag names (#11843) (#11863) + * Add doctor check to set IsArchived false if it is null (partial #11853) (#11859) + * Prevent panic on empty HOST for mysql (#11850) (#11856) + * Use DEFAULT_PAGING_NUM instead of MAX_RESPONSE_ITEMS in ListOptions (#11831) (#11836) + * Fix reply octicon (#11821) (#11822) + * Honor DEFAULT_PAGING_NUM for API (#11805) (#11813) + * Ensure rejected push to refs/pull/index/head fails nicely (#11724) (#11809) + * In File Create/Update API return 404 if Branch does not exist (#11791) (#11795) + * Fix doer of rename repo (#11789) (#11794) + * Initialize SimpleMDE when making a code comment (#11749) (#11785) + * Fix timezone on issue deadline (#11697) (#11784) + * Fix to allow comment poster to edit or delete his own comments (#11671) (#11774) + * Show full 500 error in API when Gitea in dev mode (#11641) (#11753) + * Add missing templates for Matrix system webhooks (#11729) (#11748) + * Fix verification of subkeys of default gpg key (#11713) (#11747) + * Fix styling for commiter on diff view (#11715) (#11744) + * Properly truncate system notices (#11714) (#11742) + * Handle expected errors in FileCreate & FileUpdate API (#11643) (#11718) + * Fix missing authorization check on pull for public repos of private/limited org (#11656) (#11682) + * Doctor check & fix db consistency (#11111) (#11676) + * Exclude generated files from language statistics (#11653) (#11670) + * Return json on 500 error from API (#11574) (#11659) + * When must change password only show Signout (#11600) (#11637) + * Backport various styling fixes (#11619) + * Fix wrong milestone in webhook message (#11596) (#11611) + * Fix serviceworker output file and misc improvements (#11562) (#11610) + * When initialising repositories ensure that the user doing the creation is the initializer (#11601) (#11608) + * Prevent empty query parameter being set on dashboard (#11561) (#11604) + * Fix images in wiki edit preview (#11546) (#11602) + * Prevent (caught) panic on login (#11590) (#11597) + * Prevent transferring repos to invisible orgs (#11517) (#11549) + * Move serviceworker to workbox and fix SSE interference (#11538) (#11547) + * API PullReviewComment HTMLPullURL should return the HTMLURL (#11501) (#11533) + * Fix repo-list private and total count bugs (#11500) (#11532) + * Fix form action template substitutions on admin pages (backport #11519) (#11531) + * Fix a bug where the reaction emoji doesn't disappear. (#11489) (#11530) + * TrimSpace when reading InternalToken from a file (#11502) (#11524) + * Fix selected line color in arc-green (#11492) (#11520) + * Make localstorage read ssh or https correctly (#11483) (#11490) + * Check branch protection on IsUserAllowedToUpdate (#11448) + * Fix margin on attached segment headers when they are separated by other element (#11425) + * Fix webhook template when validation errors occur (#11421) + * Fix NPE in template due to missing signing key on commit page (#11392) + * Restore active background to Register button on Register page (#11390) + * Fix hook failure due to relative LFS_CONTENT_PATH (#11362) + * Correctly set the organization num repos (#11339) + * Prevent 500 with badly formed task list (#11328) + * Allow compare page to look up base, head, own-fork, forkbase-of-head (#11327) + * Handle panics that percolate up to the graceful module (#11291) + * Don't allow registration via the web form, when AllowOnlyExternalRegistration is True (#11248) + * Patch fomantic-ui to workaround build issue (#11244) + * Prevent panic during wrappedConn close at hammertime (#11219) + * On logout force redirect to start page (#11202) + * Fix creation of Organization repos by Users with max created personal repos (#11183) + * Add option to increase provided OAuth2 token maximum size (#11180) + * Log the indexer path on failure (#11172) + * Ensure that relative paths in edit preview work (#11143) + * Make API EditIssue and EditPullRequest issue notifications (#11123) + * Send 404 immediately for known public requests (#11117) + * Remove nil inserts in models (#11096) + * Add GetReviews() to RetryDownloader (#11093) + * Remove nonexistent serviceworker entries (#11091) + * Simplify and fix GetApprovalCounts (#11086) + * Fix wiki revision template and simplify some tmpl conditions (#11080) + * Make branch parameter optional for /api/v1/repos/{owner}/{repo}/contents/{filepath} (#11067) + * Align review-item svg octicons (#11065) + * Automatically remove Watches, Assignments, etc if user loses access due to being removed as collaborator or from a team (#10997) + * Users should not be able to prohibit their own login (#10970) + * Fix scrollbar issues in dropdowns (#10897) + * Change the order of issues.closed_by to list opening user first (#10876) + * Allow site admin to check /api/v1/orgs endpoints (#10867) + * Avoid logging []byte in queue failures - convert to string first (#10865) + * Use ErrKeyUnableToVerify if fail to calc fingerprint in ssh-keygen (#10863) + * Fix assignees double load bug (#10856) + * Handle push rejection in branch and upload (#10854) + * In authorized_keys use double-quote for windows compatibility (#10841) + * Fix milestone template (#10824) + * log.Fatal on failure to listen to SSH port (#10795) + * Fix forked repo has no icon and language stat. (#10791) + * Fix tag/release deletion (#10663) + * Fix webhook migration (#10641) + * Migration for deleting orphaned dependencies (#10617) + * Add migration to fix the old broken merge-bases (#10604) + * Update templates for Go 1.14 (#10596) + * Remove unnecessary parentheses in wiki/view template (#10583) + * Change default value of DefaultCommandExecutionTimeout to match docs (#10581) + * Handle panic in indexer initialisation better (#10534) + * Set correct content_type value for Gogs/Gitea webhooks (#9504) (#10456) + * Fixed wrong AppSubUrl in multiple templates (#10447) + * Fix profile page CSS (#10406) + * Inject SVG sprite via ajax (#10320) + * Fix migration information update bug when linked github account (#10310) + * Allow admin to check org membership by API for other users (#10201) + * Fix topics dropdown (#10167) + * Ensure DeleteUser is not allowed to Delete Orgs and visa versa (#10134) + * Fix IsErrPullClosed (#10093) + * Accept punctuation after simple+cross repository issue references (#10091) + * On merge of already closed PR redirect back to the pulls page (#10010) + * Fix crowdin update script (#9969) + * Fix pull view when head repository or head branch missed and close related pull requests when delete head repository or head branch (#9927) + * Add option to prevent LDAP from deactivating everything on empty search (#9879) + * Fix admin handling at merge of PR (#9749) + * err_admin_name_pattern_not_allowed String Clarification (#9731) + * Fix wrong original git service type on a migrated repository (#9693) + * Fix ref links in issue overviews for tags (#8742) +* ENHANCEMENTS + * Fix search form button overlap (#11840) (#11864) + * Make tabular menu styling consistent for arc-green (#11570) (#11798) + * Add option to API to update PullRequest base branch (#11666) (#11796) + * Increase maximum SQLite variables count to 32766 (#11696) (#11783) + * Update emoji dataset with skin tone variants (#11678) (#11763) + * Add logging to long migrations (#11647) (#11691) + * Change language statistics to save size instead of percentage (#11681) (#11690) + * Allow different HardBreaks settings for documents and comments (#11515) (#11599) + * Fix alignment for commits on dashboard (#11595) (#11680) + * Default MSSQL port 0 to allow automatic detection by default (#11642) (#11673) + * Handle expected errors in AddGPGkey API (#11644) (#11661) + * Close EventSource before unloading the page (#11539) (#11557) + * Ensure emoji render with regular font-weight (#11541) (#11545) + * Fix webpack chunk loading with STATIC_URL_PREFIX (#11526) (#11542) + * Tweak reaction buttons (#11516) + * Use more toned colors for selected line (#11493) (#11511) + * Increase width for authors on commit view (#11441) + * Hide archived repos by default in repo-list (#11440) + * Better styling for code review comment textarea (#11428) + * Support view individual commit for wiki pages (#11415) + * Fix yellow background on active elements in code review (#11414) + * Better styling for code review comment form (#11413) + * Change install description on homepage (#11395) + * Ensure search action button is coalesced to adjacent input (#11385) + * Switch code editor to Monaco (#11366) + * Add paging and archive/private repository filtering to dashboard list (#11321) + * Changed image of openid-connect logo for better look on arc-green theme (#11312) + * Load Repo Topics on blame view too (#11307) + * Change the style in admin notice content view from `

` to `

` (#11301)
+  * Allow log.xxx.default to set logging settings for the default logger only (#11292)
+  * Automatically attempt auto recovery of broken disk queues (Update lunny/levelqueue to 0.3.0) (#11285)
+  * Make sendmail a Process and have default timeout (#11256)
+  * Check value of skip-repository flag in dump command (#11254)
+  * Fix submit review form (#11252)
+  * Allow unauthenticated users to compare (#11240)
+  * Add EventSource support (#11235)
+  * Refactor Milestone related (#11225)
+  * Add pull review API endpoints (#11224)
+  * Add a 'this' to issue close/reopened messages (#11204)
+  * When migrating from Gitlab map Approvals to approving Reviews (#11147)
+  * Improve representation of attachments in issues (#11141)
+  * Protect default branch against deletion (#11115)
+  * Add X-Total-Count on /repos/{owner]/{repo}/pulls API endpoint (#11113)
+  * Fix status label on branches list vertical alignment (#11109)
+  * Add single release page and latest redirect (#11102)
+  * Add missing commit states to PR checks template (#11085)
+  * Change icon on title for merged PR to git-merge (#11064)
+  * Add MergePull comment type instead of close for merge PR (#11058)
+  * Upgrade jQuery to 3.5.0, remove jQuery-Migrate, fix deprecations (#11055)
+  * Consolidate author name across timeline (#11053)
+  * Refactor UpdateOAuth2Application (#11034)
+  * Support unicode emojis and remove emojify.js (#11032)
+  * Add git hook "warning" to admin panel (#11030)
+  * Add flash notify for email preference setting success (#11027)
+  * Remove package code.gitea.io/gitea/modules/git import out of models (#11025)
+  * Match arc-green code tag color to code blocks (#11023)
+  * Move syntax highlighting to web worker (#11017)
+  * Prevent merge of outdated PRs on protected branches (#11012)
+  * Add Get/Update for api/v1/user/applications/oauth2 (#11008)
+  * Upgrade to most recent bluemonday (#11007)
+  * Tweak code tags in markdown (#11000)
+  * Reject duplicate AccessToken names (#10994)
+  * Fix Ctrl-Enter shortcut for issues (#10986)
+  * Provide `OwnerName` field for README template (#10981)
+  * Prettify Timeline (#10972)
+  * Add issue subscription check to API (#10967)
+  * Use AJAX for notifications table (#10961)
+  * Adjust label padding (#10957)
+  * Avoiding directory execution on hook (#10954) (#10955)
+  * Migrate ActivityHeatmap to Vue SFC (#10953)
+  * Change merge strategy: do not check write access if user in merge white list (#10951)
+  * Enable GO111MODULE=on globally in Makefile (#10939)
+  * API endpoint to get single commit via SHA and Ref (#10915)
+  * Add accordion to release list and hide non-latest (#10910)
+  * Split dashboard elements into separate template files (#10885)
+  * Add more message on sidebar menus (#10872)
+  * Set MySQL rowtype to dynamic for new tables (#10833)
+  * Completely fix task-list checkbox styling (#10798)
+  * Hide gear icon for user who can't use them on sidebar (#10750)
+  * Refactor Cron and merge dashboard tasks (#10745)
+  * Change review status icons on pr view style to github style (#10737)
+  * Make pagination optional for API list notification endpoints (#10714)
+  * Fix tab indentation in code view (#10671)
+  * Fix task-list checkbox styling (#10668)
+  * Multiple LFS improvements (#10667)
+  * Make PR message on pushes configurable (#10664)
+  * Move dropzone.js to npm/webpack (#10645)
+  * Ensure Update button is enabled even when CI has failed (#10640)
+  * Add restricted user filter to LDAP authentication (#10600)
+  * Add Yandex OAuth2 provider (#8335) (#10564)
+  * Make avatar lookup occur at image request (#10540)
+  * Prevent accidential selection of language stats bar (#10537)
+  * Add fluid-icon (#10491)
+  * Inform participants on UI too (#10473)
+  * Build with go 1.14 (and raise minimum go version to 1.12) (#10467)
+  * Add max-file-size to LFS (#10463)
+  * Enable paggination for ListRepoTags API (#10454)
+  * Update JS dependencies (#10450)
+  * Show the username as a fallback on feeds if full name is blank (#10438)
+  * Various dark theme fixes (#10416)
+  * Display pull request head branch even the branch deleted or repository deleted (#10413)
+  * Prevent Firefox from using apple-touch-icon (#10402)
+  * Fix input[type=file] on dark theme (#10382)
+  * Improve mobile review-box sizing (#10297)
+  * Notification: queue ui.go notification-service (#10281)
+  * Add detected file language to code search (#10256)
+  * Index code and stats only for non-empty repositories (#10251)
+  * Add Approval Counts to pulls list (#10238)
+  * Limit label list height on edit issue page (#10216)
+  * Improve 404 error message (#10214)
+  * Tweak locale to respect singular conflicting file message in PR list (#10177)
+  * Fix commit view (#10169)
+  * Reorganize frontend files and tooling (#10168)
+  * Allow emoji on popup label (#10166)
+  * ListIssues add filter for milestones API (#10148)
+  * Show if a PR has conflicting files on the PR lists (#10130)
+  * Fix inconsistent label color format in API (#10129)
+  * Show download count info in release list (#10124)
+  * Add Octicon SVG spritemap (#10107)
+  * Update aria-fixed semantic-dropdown to fomantic master (#10096)
+  * Fix apple-touch-icon, regenerate images (#10065)(#10006)
+  * Style blockquote for default issue mail template (#10024)
+  * More expansions in template repositories (#10021)
+  * Allow list collaborators for users with Read access to repo (#9995)
+  * Add explicit dimensions to navbar avatar (#9986)
+  * Remove loadCSS and preload woff2 icon fonts (#9976)
+  * Fix commit view JS features, reimplement folding (#9968)
+  * Fix review avatar image (#9962)
+  * Improve notification pager (#9821)
+  * Move jquery and jquery-migrate to npm/webpack (#9813)
+  * Change font to Roboto to support more charsets (#9803)
+  * Move mailer to use a queue (#9789)
+  * Issue search on my related repositories (#9758)
+  * Add "before" query to ListIssueComments and ListRepoIssueComments API (#9685)
+  * Move tracked time api convert to convert package (#9665)
+  * Improve PR info in default merge message (#9635)
+  * Granular webhook events (#9626)
+  * Add Reviewed-on in commit message (#9623)
+  * Add top author stats to activity page (#9615)
+  * Allow repo admin to merge PR regardless of review status (#9611)
+  * Migrate reactions when migrating repository from github (#9599)
+  * API orgEditTeam make Fields optional (#9556)
+  * Move create/fork repository from models to modules/repository (#9489)
+  * Migrate reviews when migrating repository from github (#9463)
+  * Times API add filters (#9373)
+  * Move push commits from models to modules/repository (#9370)
+  * Add API endpoint to check notifications [Extend #9488] (#9595)
+  * Add GET /orgs API endpoint (#9560)
+  * API add/generalize pagination (#9452)
+  * Make create org repo API call same as github (#9186)
+* BUILD
+  * Turn off go modules for xgo and gxz (#10963)
+  * Add gitea-vet (#10948)
+  * Rename scripts to build and add revive command as a new build tool command (#10942)
+  * Add 'make lint', restructure 'compliance' pipeline (#10861)
+  * Move JS build dependencies to 'dependencies' (#10763)
+  * Use whitelist to find go files, run find only once (#10594)
+  * Move vue and vue-calendar-heatmap to npm/webpack (#10188)
+  * Move jquery.are-you-sure to npm/webpack (#10063)
+  * Move highlight.js to npm/webpack (#10011)
+  * Generate Bindata if TAGS="bindata" and not up-to-date (#10004)
+  * Move CSS build to webpack (#9983)
+  * Move fomantic target, update 'make help' (#9945)
+  * Add css extraction and minification to webpack (#9944)
+  * Misc webpack tweaks (#9924)
+  * Make node_modules a order-only prerequisite (#9923)
+  * Update documentation for the go module era (#9751)
+  * Move swagger-ui to webpack/npm and update it to 3.24.3 (#9714)
+  * Use npm to manage fomantic and only build needed components (#9561)
+* MISC
+  * Add gnupg to Dockerfile (#11365)
+  * Update snapcraft.yaml for core18 and latest features (#11300)
+  * Update JS dependencies, min Node.js version 10.13 (#11246)
+  * Change default charset for MySQL on install to utf8mb4 (#10989)
+  * Return issue subscription status from API subscribe (#10966)
+  * Fix queue log param (#10733)
+  * Add warning when using relative path to app.ini (#10104)
+
+## [1.11.7](https://github.com/go-gitea/gitea/releases/tag/v1.11.7) - 2020-06-18
+
+* BUGFIXES
+  * Use ID or Where to instead directly use Get when load object from database (#11925) (#11935)
+  * Fix __webpack_public_path__ for 1.11 (#11907)
+  * Fix verification of subkeys of default gpg key (#11713) (#11902)
+  * Remove unnecessary parentheses in wiki/view template (#11781)
+  * Doctor fix xorm.Count nil on sqlite error (#11741)
+
 ## [1.11.6](https://github.com/go-gitea/gitea/releases/tag/v1.11.6) - 2020-05-30
 
 * SECURITY
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2b5ca56206dc1..f62c94c88ede2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -158,7 +158,7 @@ import (
 To maintain understandable code and avoid circular dependencies it is important to have a good structure of the code. The gitea code is divided into the following parts:
 
 - **integration:** Integrations tests
-- **models:** Contains the data structures used by xorm to construct database tables. It also contains supporting functions to query and update the database. Dependecies to other code in Gitea should be avoided although some modules might be needed (for example for logging).
+- **models:** Contains the data structures used by xorm to construct database tables. It also contains supporting functions to query and update the database. Dependencies to other code in Gitea should be avoided although some modules might be needed (for example for logging).
 - **models/fixtures:** Sample model data used in integration tests.
 - **models/migrations:** Handling of database migrations between versions. PRs that changes a database structure shall also have a migration step.
 - **modules:** Different modules to handle specific functionality in Gitea.
@@ -181,16 +181,16 @@ The same applies to status responses. If you notice a problem, feel free to leav
 All expected results (errors, success, fail messages) should be documented
 ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L319-L327)).
 
-All JSON input types must be defined as a struct in `models/structs/`
+All JSON input types must be defined as a struct in [modules/structs/](modules/structs/)
 ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L76-L91))
 and referenced in
 [routers/api/v1/swagger/options.go](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/options.go).  
 They can then be used like the following:
 ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L318)).
 
-All JSON responses must be defined as a struct in `models/structs/`
+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/`
+and referenced in its category in [routers/api/v1/swagger/](routers/api/v1/swagger/)
 ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/issue.go#L11-L16))  
 They can be used like the following:
 ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L277-L279))
@@ -199,7 +199,7 @@ 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 Obejcts (e.g. User) to something (e.g. Org-Team)
+ * **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
 
 
@@ -293,6 +293,11 @@ and lead the development of Gitea.
 To honor the past owners, here's the history of the owners and the time
 they served:
 
+* 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) 
diff --git a/Dockerfile b/Dockerfile
index a04324c94ef4c..1376dbdda90a9 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,14 +1,14 @@
 
 ###################################
 #Build stage
-FROM golang:1.14-alpine3.12 AS build-env
+FROM golang:1.15-alpine3.13 AS build-env
 
 ARG GOPROXY
 ENV GOPROXY ${GOPROXY:-direct}
 
 ARG GITEA_VERSION
 ARG TAGS="sqlite sqlite_unlock_notify"
-ENV TAGS "bindata $TAGS"
+ENV TAGS "bindata timetzdata $TAGS"
 ARG CGO_EXTRA_CFLAGS
 
 #Build deps
@@ -22,7 +22,7 @@ WORKDIR ${GOPATH}/src/code.gitea.io/gitea
 RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
  && make clean-all build
 
-FROM alpine:3.12
+FROM alpine:3.13
 LABEL maintainer="maintainers@gitea.io"
 
 EXPOSE 22 3000
@@ -38,7 +38,6 @@ RUN apk --no-cache add \
     s6 \
     sqlite \
     su-exec \
-    tzdata \
     gnupg
 
 RUN addgroup \
diff --git a/Dockerfile.rootless b/Dockerfile.rootless
new file mode 100644
index 0000000000000..d20d4d8b8b8a0
--- /dev/null
+++ b/Dockerfile.rootless
@@ -0,0 +1,67 @@
+
+###################################
+#Build stage
+FROM golang:1.15-alpine3.13 AS build-env
+
+ARG GOPROXY
+ENV GOPROXY ${GOPROXY:-direct}
+
+ARG GITEA_VERSION
+ARG TAGS="sqlite sqlite_unlock_notify"
+ENV TAGS "bindata timetzdata $TAGS"
+ARG CGO_EXTRA_CFLAGS 
+
+#Build deps
+RUN apk --no-cache add build-base git nodejs npm
+
+#Setup repo
+COPY . ${GOPATH}/src/code.gitea.io/gitea
+WORKDIR ${GOPATH}/src/code.gitea.io/gitea
+
+#Checkout version if set
+RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
+ && make clean-all build
+
+FROM alpine:3.13
+LABEL maintainer="maintainers@gitea.io"
+
+EXPOSE 2222 3000
+
+RUN apk --no-cache add \
+    bash \
+    ca-certificates \
+    gettext \
+    git \
+    gnupg
+
+RUN addgroup \
+    -S -g 1000 \
+    git && \
+  adduser \
+    -S -H -D \
+    -h /var/lib/gitea/git \
+    -s /bin/bash \
+    -u 1000 \
+    -G git \
+    git && \
+  echo "git:$(dd if=/dev/urandom bs=24 count=1 status=none | base64)" | chpasswd
+
+RUN mkdir -p /var/lib/gitea /etc/gitea
+RUN chown git:git /var/lib/gitea /etc/gitea
+
+COPY docker/rootless /
+COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /usr/local/bin/gitea
+
+USER git:git
+ENV GITEA_WORK_DIR /var/lib/gitea
+ENV GITEA_CUSTOM /var/lib/gitea/custom
+ENV GITEA_TEMP /tmp/gitea
+#TODO add to docs the ability to define the ini to load (usefull to test and revert a config)
+ENV GITEA_APP_INI /etc/gitea/app.ini
+ENV HOME "/var/lib/gitea/git"
+VOLUME ["/var/lib/gitea", "/etc/gitea"]
+WORKDIR /var/lib/gitea
+
+ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
+CMD []
+
diff --git a/MAINTAINERS b/MAINTAINERS
index d805520fd46f6..dadbb788a4319 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -36,4 +36,6 @@ Mura Li  (@typeless)
 6543 <6543@obermui.de> (@6543)
 jaqra  (@jaqra)
 David Svantesson  (@davidsvantesson)
-CirnoT  (@CirnoT)
+a1012112796 <1012112796@qq.com> (@a1012112796)
+Karl Heinz Marbaise  (@khmarbaise)
+Norwin Roosen  (@noerw)
diff --git a/Makefile b/Makefile
index 002f0318cf3d0..2de788345400e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,3 @@
-
 ifeq ($(USE_REPO_TEST_DIR),1)
 
 # This rule replaces the whole Makefile when we're trying to use /tmp repository temporary files
@@ -21,15 +20,18 @@ IMPORT := code.gitea.io/gitea
 export GO111MODULE=on
 
 GO ?= go
-SED_INPLACE := sed -i
 SHASUM ?= shasum -a 256
 HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
 COMMA := ,
 
-XGO_VERSION := go-1.14.x
-MIN_GO_VERSION := 001012000
+XGO_VERSION := go-1.15.x
+MIN_GO_VERSION := 001013000
 MIN_NODE_VERSION := 010013000
 
+DOCKER_IMAGE ?= gitea/gitea
+DOCKER_TAG ?= latest
+DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
+
 ifeq ($(HAS_GO), GO)
 	GOPATH ?= $(shell $(GO) env GOPATH)
 	export PATH := $(GOPATH)/bin:$(PATH)
@@ -38,23 +40,22 @@ ifeq ($(HAS_GO), GO)
 	CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
 endif
 
-
 ifeq ($(OS), Windows_NT)
+	GOFLAGS := -v -buildmode=exe
 	EXECUTABLE ?= gitea.exe
 else
+	GOFLAGS := -v
 	EXECUTABLE ?= gitea
-	UNAME_S := $(shell uname -s)
-	ifeq ($(UNAME_S),Darwin)
-		SED_INPLACE := sed -i ''
-	endif
-	ifeq ($(UNAME_S),FreeBSD)
-		SED_INPLACE := sed -i ''
-	endif
+endif
+
+ifeq ($(shell sed --version 2>/dev/null | grep -q GNU && echo gnu),gnu)
+	SED_INPLACE := sed -i
+else
+	SED_INPLACE := sed -i ''
 endif
 
 GOFMT ?= gofmt -s
 
-GOFLAGS := -v
 EXTRA_GOFLAGS ?=
 
 MAKE_VERSION := $(shell $(MAKE) -v | head -n 1)
@@ -88,19 +89,30 @@ LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(G
 
 GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/integrations/migration-test,$(filter-out code.gitea.io/gitea/integrations,$(shell $(GO) list -mod=vendor ./... | grep -v /vendor/)))
 
+FOMANTIC_CONFIGS := semantic.json web_src/fomantic/theme.config.less web_src/fomantic/_site/globals/site.variables
+FOMANTIC_DEST := web_src/fomantic/build/semantic.js web_src/fomantic/build/semantic.css
+FOMANTIC_DEST_DIR := web_src/fomantic/build
+
 WEBPACK_SOURCES := $(shell find web_src/js web_src/less -type f)
 WEBPACK_CONFIGS := webpack.config.js
 WEBPACK_DEST := public/js/index.js public/css/index.css
-WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/serviceworker.js
+WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/img/webpack public/serviceworker.js
 
 BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
 BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
 
+SVG_DEST_DIR := public/img/svg
+
+AIR_TMP_DIR := .air
+
 TAGS ?=
 TAGS_SPLIT := $(subst $(COMMA), ,$(TAGS))
 TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags
 
-GO_DIRS := cmd integrations models modules routers build services vendor
+TEST_TAGS ?= sqlite sqlite_unlock_notify
+
+GO_DIRS := cmd integrations models modules routers build services vendor tools
+
 GO_SOURCES := $(wildcard *.go)
 GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" -not -path modules/options/bindata.go -not -path modules/public/bindata.go -not -path modules/templates/bindata.go)
 
@@ -110,15 +122,12 @@ endif
 
 GO_SOURCES_OWN := $(filter-out vendor/% %/bindata.go, $(GO_SOURCES))
 
-FOMANTIC_CONFIGS := semantic.json web_src/fomantic/theme.config.less web_src/fomantic/_site/globals/site.variables
-FOMANTIC_DEST := public/fomantic/semantic.min.js public/fomantic/semantic.min.css
-FOMANTIC_DEST_DIR := public/fomantic
-
-#To update swagger use: GO111MODULE=on go get -u github.com/go-swagger/go-swagger/cmd/swagger@v0.20.1
+#To update swagger use: GO111MODULE=on go get -u github.com/go-swagger/go-swagger/cmd/swagger
 SWAGGER := $(GO) run -mod=vendor github.com/go-swagger/go-swagger/cmd/swagger
 SWAGGER_SPEC := templates/swagger/v1_json.tmpl
 SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl}}/api/v1"|g
 SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl}}/api/v1"|"basePath": "/api/v1"|g
+SWAGGER_EXCLUDE := code.gitea.io/sdk
 SWAGGER_NEWLINE_COMMAND := -e '$$a\'
 
 TEST_MYSQL_HOST ?= mysql:3306
@@ -142,40 +151,46 @@ TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
 .PHONY: all
 all: build
 
-include docker/Makefile
-
 .PHONY: help
 help:
 	@echo "Make Routines:"
-	@echo " - \"\"                             equivalent to \"build\""
+	@echo " - \"\"                               equivalent to \"build\""
 	@echo " - build                            build everything"
 	@echo " - frontend                         build frontend files"
 	@echo " - backend                          build backend files"
+	@echo " - watch                            watch everything and continuously rebuild"
+	@echo " - watch-frontend                   watch frontend files and continuously rebuild"
+	@echo " - watch-backend                    watch backend files and continuously rebuild"
 	@echo " - clean                            delete backend and integration files"
 	@echo " - clean-all                        delete backend, frontend and integration files"
 	@echo " - lint                             lint everything"
 	@echo " - lint-frontend                    lint frontend files"
 	@echo " - lint-backend                     lint backend files"
-	@echo " - watch-frontend                   watch frontend files and continuously rebuild"
+	@echo " - checks                           run various consistency checks"
+	@echo " - checks-frontend                  check frontend files"
+	@echo " - checks-backend                   check backend files"
 	@echo " - webpack                          build webpack files"
+	@echo " - svg                              build svg files"
 	@echo " - fomantic                         build fomantic files"
 	@echo " - generate                         run \"go generate\""
 	@echo " - fmt                              format the Go code"
+	@echo " - generate-license                 update license files"
+	@echo " - generate-gitignore               update gitignore files"
 	@echo " - generate-swagger                 generate the swagger spec from code comments"
 	@echo " - swagger-validate                 check if the swagger spec is valid"
 	@echo " - golangci-lint                    run golangci-lint linter"
 	@echo " - revive                           run revive linter"
 	@echo " - misspell                         check for misspellings"
 	@echo " - vet                              examines Go source code and reports suspicious constructs"
-	@echo " - test[\#TestSpecificName]    	   run unit test"
+	@echo " - test[\#TestSpecificName]    	    run unit test"
 	@echo " - test-sqlite[\#TestSpecificName]  run integration test for sqlite"
 	@echo " - pr#                       build and start gitea from a PR with integration test data loaded"
 
 .PHONY: go-check
 go-check:
-	$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell go version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
+	$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
 	@if [ "$(GO_VERSION)" -lt "$(MIN_GO_VERSION)" ]; then \
-		echo "Gitea requires Go 1.12 or greater to build. You can get it at https://golang.org/dl/"; \
+		echo "Gitea requires Go 1.13 or greater to build. You can get it at https://golang.org/dl/"; \
 		exit 1; \
 	fi
 
@@ -197,7 +212,7 @@ node-check:
 
 .PHONY: clean-all
 clean-all: clean
-	rm -rf $(WEBPACK_DEST_ENTRIES) $(FOMANTIC_DEST_DIR)
+	rm -rf $(WEBPACK_DEST_ENTRIES)
 
 .PHONY: clean
 clean:
@@ -210,15 +225,15 @@ clean:
 
 .PHONY: fmt
 fmt:
-	$(GOFMT) -w $(GO_SOURCES_OWN)
+	@echo "Running go fmt..."
+	@$(GOFMT) -w $(GO_SOURCES_OWN)
 
 .PHONY: vet
 vet:
-	# Default vet
-	$(GO) vet $(GO_PACKAGES)
-	# Custom vet
-	$(GO) build -mod=vendor gitea.com/jolheiser/gitea-vet
-	$(GO) vet -vettool=gitea-vet $(GO_PACKAGES)
+	@echo "Running go vet..."
+	@$(GO) vet $(GO_PACKAGES)
+	@GOOS= GOARCH= $(GO) build -mod=vendor code.gitea.io/gitea-vet
+	@$(GO) vet -vettool=gitea-vet $(GO_PACKAGES)
 
 .PHONY: $(TAGS_EVIDENCE)
 $(TAGS_EVIDENCE):
@@ -231,7 +246,7 @@ endif
 
 .PHONY: generate-swagger
 generate-swagger:
-	$(SWAGGER) generate spec -o './$(SWAGGER_SPEC)'
+	$(SWAGGER) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
 	$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
 	$(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)'
 
@@ -242,7 +257,7 @@ swagger-check: generate-swagger
 		echo "Please run 'make generate-swagger' and commit the result:"; \
 		echo "$${diff}"; \
 		exit 1; \
-	fi;
+	fi
 
 .PHONY: swagger-validate
 swagger-validate:
@@ -253,9 +268,10 @@ swagger-validate:
 .PHONY: errcheck
 errcheck:
 	@hash errcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
-		$(GO) get -u github.com/kisielk/errcheck; \
+		GO111MODULE=off $(GO) get -u github.com/kisielk/errcheck; \
 	fi
-	errcheck $(GO_PACKAGES)
+	@echo "Running errcheck..."
+	@errcheck $(GO_PACKAGES)
 
 .PHONY: revive
 revive:
@@ -264,16 +280,18 @@ revive:
 .PHONY: misspell-check
 misspell-check:
 	@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
-		$(GO) get -u github.com/client9/misspell/cmd/misspell; \
+		GO111MODULE=off $(GO) get -u github.com/client9/misspell/cmd/misspell; \
 	fi
-	misspell -error -i unknwon,destory $(GO_SOURCES_OWN)
+	@echo "Running misspell-check..."
+	@misspell -error -i unknwon,destory $(GO_SOURCES_OWN)
 
 .PHONY: misspell
 misspell:
 	@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
-		$(GO) get -u github.com/client9/misspell/cmd/misspell; \
+		GO111MODULE=off $(GO) get -u github.com/client9/misspell/cmd/misspell; \
 	fi
-	misspell -w -i unknwon $(GO_SOURCES_OWN)
+	@echo "Running go misspell..."
+	@misspell -w -i unknwon $(GO_SOURCES_OWN)
 
 .PHONY: fmt-check
 fmt-check:
@@ -283,31 +301,52 @@ fmt-check:
 		echo "Please run 'make fmt' and commit the result:"; \
 		echo "$${diff}"; \
 		exit 1; \
-	fi;
+	fi
 
-.PHONY: lint
-lint: lint-backend lint-frontend
+.PHONY: checks
+checks: checks-frontend checks-backend
 
-.PHONY: lint-backend
-lint-backend: golangci-lint revive vet swagger-check swagger-validate test-vendor
+.PHONY: checks-frontend
+checks-frontend: svg-check
+
+.PHONY: checks-backend
+checks-backend: misspell-check test-vendor swagger-check swagger-validate
+
+.PHONY: lint
+lint: lint-frontend lint-backend
 
 .PHONY: lint-frontend
 lint-frontend: node_modules
-	npx eslint web_src/js webpack.config.js
-	npx stylelint web_src/less
+	npx eslint --color --max-warnings=0 web_src/js build templates webpack.config.js
+	npx stylelint --color --max-warnings=0 web_src/less
+
+.PHONY: lint-backend
+lint-backend: golangci-lint revive vet
+
+.PHONY: watch
+watch:
+	bash tools/watch.sh
 
 .PHONY: watch-frontend
-watch-frontend: node_modules
+watch-frontend: node-check node_modules
 	rm -rf $(WEBPACK_DEST_ENTRIES)
-	NODE_ENV=development npx webpack --hide-modules --display-entrypoints=false --watch --progress
+	NODE_ENV=development npx webpack --watch --progress
+
+.PHONY: watch-backend
+watch-backend: go-check
+	@hash air > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
+		GO111MODULE=off $(GO) get -u github.com/cosmtrek/air; \
+	fi
+	air -c .air.conf
 
 .PHONY: test
 test:
-	$(GO) test $(GOTESTFLAGS) -mod=vendor -tags='sqlite sqlite_unlock_notify' $(GO_PACKAGES)
+	@echo "Running go test with -tags '$(TEST_TAGS)'..."
+	@$(GO) test $(GOTESTFLAGS) -mod=vendor -tags='$(TEST_TAGS)' $(GO_PACKAGES)
 
 .PHONY: test-check
 test-check:
-	@echo "Checking if tests have changed the source tree...";
+	@echo "Running test-check...";
 	@diff=$$(git status -s); \
 	if [ -n "$$diff" ]; then \
 		echo "make test has changed files in the source tree:"; \
@@ -315,11 +354,12 @@ test-check:
 		echo "You should change the tests to create these files in a temporary directory."; \
 		echo "Do not simply add these files to .gitignore"; \
 		exit 1; \
-	fi;
+	fi
 
 .PHONY: test\#%
 test\#%:
-	$(GO) test -mod=vendor -tags='sqlite sqlite_unlock_notify' -run $(subst .,/,$*) $(GO_PACKAGES)
+	@echo "Running go test with -tags '$(TEST_TAGS)'..."
+	@$(GO) test -mod=vendor -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_PACKAGES)
 
 .PHONY: coverage
 coverage:
@@ -327,7 +367,8 @@ coverage:
 
 .PHONY: unit-test-coverage
 unit-test-coverage:
-	$(GO) test $(GOTESTFLAGS) -mod=vendor -tags='sqlite sqlite_unlock_notify' -cover -coverprofile coverage.out $(GO_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
+	@echo "Running unit-test-coverage -tags '$(TEST_TAGS)'..."
+	@$(GO) test $(GOTESTFLAGS) -mod=vendor -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
 
 .PHONY: vendor
 vendor:
@@ -340,7 +381,7 @@ test-vendor: vendor
 		echo "Please run 'make vendor' and commit the result:"; \
 		echo "$${diff}"; \
 		exit 1; \
-	fi;
+	fi
 
 generate-ini-sqlite:
 	sed -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
@@ -348,15 +389,15 @@ generate-ini-sqlite:
 
 .PHONY: test-sqlite
 test-sqlite: integrations.sqlite.test generate-ini-sqlite
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test
 
 .PHONY: test-sqlite\#%
 test-sqlite\#%: integrations.sqlite.test generate-ini-sqlite
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*)
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*)
 
 .PHONY: test-sqlite-migration
 test-sqlite-migration:  migrations.sqlite.test generate-ini-sqlite
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./migrations.sqlite.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./migrations.sqlite.test
 
 generate-ini-mysql:
 	sed -e 's|{{TEST_MYSQL_HOST}}|${TEST_MYSQL_HOST}|g' \
@@ -368,15 +409,15 @@ generate-ini-mysql:
 
 .PHONY: test-mysql
 test-mysql: integrations.mysql.test generate-ini-mysql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./integrations.mysql.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mysql.ini ./integrations.mysql.test
 
 .PHONY: test-mysql\#%
 test-mysql\#%: integrations.mysql.test generate-ini-mysql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*)
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*)
 
 .PHONY: test-mysql-migration
 test-mysql-migration: migrations.mysql.test generate-ini-mysql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./migrations.mysql.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mysql.ini ./migrations.mysql.test
 
 generate-ini-mysql8:
 	sed -e 's|{{TEST_MYSQL8_HOST}}|${TEST_MYSQL8_HOST}|g' \
@@ -388,15 +429,15 @@ generate-ini-mysql8:
 
 .PHONY: test-mysql8
 test-mysql8: integrations.mysql8.test generate-ini-mysql8
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql8.ini ./integrations.mysql8.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mysql8.ini ./integrations.mysql8.test
 
 .PHONY: test-mysql8\#%
 test-mysql8\#%: integrations.mysql8.test generate-ini-mysql8
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql8.ini ./integrations.mysql8.test -test.run $(subst .,/,$*)
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mysql8.ini ./integrations.mysql8.test -test.run $(subst .,/,$*)
 
 .PHONY: test-mysql8-migration
 test-mysql8-migration: migrations.mysql8.test generate-ini-mysql8
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql8.ini ./migrations.mysql8.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mysql8.ini ./migrations.mysql8.test
 
 generate-ini-pgsql:
 	sed -e 's|{{TEST_PGSQL_HOST}}|${TEST_PGSQL_HOST}|g' \
@@ -409,15 +450,15 @@ generate-ini-pgsql:
 
 .PHONY: test-pgsql
 test-pgsql: integrations.pgsql.test generate-ini-pgsql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./integrations.pgsql.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/pgsql.ini ./integrations.pgsql.test
 
 .PHONY: test-pgsql\#%
 test-pgsql\#%: integrations.pgsql.test generate-ini-pgsql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*)
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*)
 
 .PHONY: test-pgsql-migration
 test-pgsql-migration: migrations.pgsql.test generate-ini-pgsql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./migrations.pgsql.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/pgsql.ini ./migrations.pgsql.test
 
 generate-ini-mssql:
 	sed -e 's|{{TEST_MSSQL_HOST}}|${TEST_MSSQL_HOST}|g' \
@@ -429,35 +470,35 @@ generate-ini-mssql:
 
 .PHONY: test-mssql
 test-mssql: integrations.mssql.test generate-ini-mssql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./integrations.mssql.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mssql.ini ./integrations.mssql.test
 
 .PHONY: test-mssql\#%
 test-mssql\#%: integrations.mssql.test generate-ini-mssql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*)
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*)
 
 .PHONY: test-mssql-migration
 test-mssql-migration: migrations.mssql.test generate-ini-mssql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./migrations.mssql.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mssql.ini ./migrations.mssql.test -test.failfast
 
 .PHONY: bench-sqlite
 bench-sqlite: integrations.sqlite.test generate-ini-sqlite
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
 
 .PHONY: bench-mysql
 bench-mysql: integrations.mysql.test generate-ini-mysql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
 
 .PHONY: bench-mssql
 bench-mssql: integrations.mssql.test generate-ini-mssql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./integrations.mssql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mssql.ini ./integrations.mssql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
 
 .PHONY: bench-pgsql
 bench-pgsql: integrations.pgsql.test generate-ini-pgsql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./integrations.pgsql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/pgsql.ini ./integrations.pgsql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
 
 .PHONY: integration-test-coverage
 integration-test-coverage: integrations.cover.test generate-ini-mysql
-	GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./integrations.cover.test -test.coverprofile=integration.coverage.out
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mysql.ini ./integrations.cover.test -test.coverprofile=integration.coverage.out
 
 integrations.mysql.test: git-check $(GO_SOURCES)
 	$(GO) test $(GOTESTFLAGS) -mod=vendor -c code.gitea.io/gitea/integrations -o integrations.mysql.test
@@ -472,7 +513,7 @@ integrations.mssql.test: git-check $(GO_SOURCES)
 	$(GO) test $(GOTESTFLAGS) -mod=vendor -c code.gitea.io/gitea/integrations -o integrations.mssql.test
 
 integrations.sqlite.test: git-check $(GO_SOURCES)
-	$(GO) test $(GOTESTFLAGS) -mod=vendor -c code.gitea.io/gitea/integrations -o integrations.sqlite.test -tags 'sqlite sqlite_unlock_notify'
+	$(GO) test $(GOTESTFLAGS) -mod=vendor -c code.gitea.io/gitea/integrations -o integrations.sqlite.test -tags '$(TEST_TAGS)'
 
 integrations.cover.test: git-check $(GO_SOURCES)
 	$(GO) test $(GOTESTFLAGS) -mod=vendor -c code.gitea.io/gitea/integrations -coverpkg $(shell echo $(GO_PACKAGES) | tr ' ' ',') -o integrations.cover.test
@@ -495,7 +536,7 @@ migrations.mssql.test: $(GO_SOURCES)
 
 .PHONY: migrations.sqlite.test
 migrations.sqlite.test: $(GO_SOURCES)
-	$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations/migration-test -o migrations.sqlite.test -tags 'sqlite sqlite_unlock_notify'
+	$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)'
 
 .PHONY: check
 check: test
@@ -508,20 +549,21 @@ install: $(wildcard *.go)
 build: frontend backend
 
 .PHONY: frontend
-frontend: node-check $(FOMANTIC_DEST) $(WEBPACK_DEST)
+frontend: node-check $(WEBPACK_DEST)
 
 .PHONY: backend
 backend: go-check generate $(EXECUTABLE)
 
 .PHONY: generate
 generate: $(TAGS_PREREQ)
-	CC= GOOS= GOARCH= $(GO) generate -mod=vendor -tags '$(TAGS)' $(GO_PACKAGES)
+	@echo "Running go generate..."
+	@CC= GOOS= GOARCH= $(GO) generate -mod=vendor -tags '$(TAGS)' $(GO_PACKAGES)
 
 $(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
 	CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build -mod=vendor $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
 
 .PHONY: release
-release: frontend generate release-windows release-linux release-darwin release-copy release-compress release-sources release-check
+release: frontend generate release-windows release-linux release-darwin release-copy release-compress release-sources release-docs release-check
 
 $(DIST_DIRS):
 	mkdir -p $(DIST_DIRS)
@@ -529,9 +571,10 @@ $(DIST_DIRS):
 .PHONY: release-windows
 release-windows: | $(DIST_DIRS)
 	@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
-		$(GO) get -u src.techknowlogick.com/xgo; \
+		GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \
 	fi
-	CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
+	@echo "Warning: windows version is built using golang 1.14"
+	CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
 ifeq ($(CI),drone)
 	cp /build/* $(DIST)/binaries
 endif
@@ -539,9 +582,9 @@ endif
 .PHONY: release-linux
 release-linux: | $(DIST_DIRS)
 	@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
-		$(GO) get -u src.techknowlogick.com/xgo; \
+		GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \
 	fi
-	CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/mips64le,linux/mips,linux/mipsle' -out gitea-$(VERSION) .
+	CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64' -out gitea-$(VERSION) .
 ifeq ($(CI),drone)
 	cp /build/* $(DIST)/binaries
 endif
@@ -549,7 +592,7 @@ endif
 .PHONY: release-darwin
 release-darwin: | $(DIST_DIRS)
 	@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
-		$(GO) get -u src.techknowlogick.com/xgo; \
+		GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \
 	fi
 	CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out gitea-$(VERSION) .
 ifeq ($(CI),drone)
@@ -574,9 +617,20 @@ release-compress: | $(DIST_DIRS)
 .PHONY: release-sources
 release-sources: | $(DIST_DIRS) node_modules
 	echo $(VERSION) > $(STORED_VERSION_FILE)
-	tar --exclude=./$(DIST) --exclude=./.git --exclude=./$(MAKE_EVIDENCE_DIR) --exclude=./node_modules/.cache -czf $(DIST)/release/gitea-src-$(VERSION).tar.gz .
+	tar --exclude=./$(DIST) --exclude=./.git --exclude=./$(MAKE_EVIDENCE_DIR) --exclude=./node_modules/.cache --exclude=./$(AIR_TMP_DIR) -czf $(DIST)/release/gitea-src-$(VERSION).tar.gz .
 	rm -f $(STORED_VERSION_FILE)
 
+.PHONY: release-docs
+release-docs: | $(DIST_DIRS) docs
+	tar -czf $(DIST)/release/gitea-docs-$(VERSION).tar.gz -C ./docs/public .
+
+.PHONY: docs
+docs:
+	@hash hugo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
+		curl -sL https://github.com/gohugoio/hugo/releases/download/v0.74.3/hugo_0.74.3_Linux-64bit.tar.gz | tar zxf - -C /tmp && mv /tmp/hugo /usr/bin/hugo && chmod +x /usr/bin/hugo; \
+	fi
+	cd docs; make trans-copy clean build-offline;
+
 node_modules: package-lock.json
 	npm install --no-save
 	@touch node_modules
@@ -586,14 +640,18 @@ npm-update: node-check | node_modules
 	npx updates -cu
 	rm -rf node_modules package-lock.json
 	npm install --package-lock
+	@touch node_modules
 
 .PHONY: fomantic
 fomantic: $(FOMANTIC_DEST)
 
-$(FOMANTIC_DEST): $(FOMANTIC_CONFIGS) package-lock.json | node_modules
+$(FOMANTIC_DEST): $(FOMANTIC_CONFIGS) | node_modules
+	@if [ ! -d node_modules/fomantic-ui ]; then \
+		npm install --no-save --no-package-lock fomantic-ui@2.8.7; \
+	fi
 	rm -rf $(FOMANTIC_DEST_DIR)
-	cp web_src/fomantic/theme.config.less node_modules/fomantic-ui/src/theme.config
-	cp -r web_src/fomantic/_site/* node_modules/fomantic-ui/src/_site/
+	cp -f web_src/fomantic/theme.config.less node_modules/fomantic-ui/src/theme.config
+	cp -rf web_src/fomantic/_site/* node_modules/fomantic-ui/src/_site/
 	npx gulp -f node_modules/fomantic-ui/gulpfile.js build
 	@touch $(FOMANTIC_DEST)
 
@@ -602,9 +660,24 @@ webpack: $(WEBPACK_DEST)
 
 $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json | node_modules
 	rm -rf $(WEBPACK_DEST_ENTRIES)
-	npx webpack --hide-modules --display-entrypoints=false
+	npx webpack
 	@touch $(WEBPACK_DEST)
 
+.PHONY: svg
+svg: node-check | node_modules
+	rm -rf $(SVG_DEST_DIR)
+	node build/generate-svg.js
+
+.PHONY: svg-check
+svg-check: svg
+	@git add $(SVG_DEST_DIR)
+	@diff=$$(git diff --cached $(SVG_DEST_DIR)); \
+	if [ -n "$$diff" ]; then \
+		echo "Please run 'make svg' and 'git add $(SVG_DEST_DIR)' and commit the result:"; \
+		echo "$${diff}"; \
+		exit 1; \
+	fi
+
 .PHONY: update-translations
 update-translations:
 	mkdir -p ./translations
@@ -615,36 +688,18 @@ update-translations:
 	mv ./translations/*.ini ./options/locale/
 	rmdir ./translations
 
+.PHONY: generate-license
+generate-license:
+	GO111MODULE=on $(GO) run build/generate-licenses.go
+
+.PHONY: generate-gitignore
+generate-gitignore:
+	GO111MODULE=on $(GO) run build/generate-gitignores.go
+
 .PHONY: generate-images
 generate-images:
-	$(eval TMPDIR := $(shell mktemp -d 2>/dev/null || mktemp -d -t 'gitea-temp'))
-	mkdir -p $(TMPDIR)/images
-	inkscape -f $(PWD)/assets/logo.svg -w 880 -h 880 -e $(PWD)/public/img/gitea-lg.png
-	inkscape -f $(PWD)/assets/logo.svg -w 512 -h 512 -e $(PWD)/public/img/gitea-512.png
-	inkscape -f $(PWD)/assets/logo.svg -w 192 -h 192 -e $(PWD)/public/img/gitea-192.png
-	inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer1 -e $(TMPDIR)/images/sm-1.png
-	inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer2 -e $(TMPDIR)/images/sm-2.png
-	composite -compose atop $(TMPDIR)/images/sm-2.png $(TMPDIR)/images/sm-1.png $(PWD)/public/img/gitea-sm.png
-	inkscape -f $(PWD)/assets/logo.svg -w 200 -h 200 -e $(PWD)/public/img/avatar_default.png
-	inkscape -f $(PWD)/assets/logo.svg -w 180 -h 180 -e $(PWD)/public/img/favicon.png
-	inkscape -f $(PWD)/assets/logo.svg -w 128 -h 128 -e $(TMPDIR)/images/128-raw.png
-	inkscape -f $(PWD)/assets/logo.svg -w 64 -h 64 -e $(TMPDIR)/images/64-raw.png
-	inkscape -f $(PWD)/assets/logo.svg -w 32 -h 32 -jC -i layer1 -e $(TMPDIR)/images/32-1.png
-	inkscape -f $(PWD)/assets/logo.svg -w 32 -h 32 -jC -i layer2 -e $(TMPDIR)/images/32-2.png
-	composite -compose atop $(TMPDIR)/images/32-2.png $(TMPDIR)/images/32-1.png $(TMPDIR)/images/32-raw.png
-	inkscape -f $(PWD)/assets/logo.svg -w 16 -h 16 -jC -i layer1 -e $(TMPDIR)/images/16-raw.png
-	zopflipng -m -y $(TMPDIR)/images/128-raw.png $(TMPDIR)/images/128.png
-	zopflipng -m -y $(TMPDIR)/images/64-raw.png $(TMPDIR)/images/64.png
-	zopflipng -m -y $(TMPDIR)/images/32-raw.png $(TMPDIR)/images/32.png
-	zopflipng -m -y $(TMPDIR)/images/16-raw.png $(TMPDIR)/images/16.png
-	rm -f $(TMPDIR)/images/*-*.png
-	convert $(TMPDIR)/images/16.png $(TMPDIR)/images/32.png \
-					$(TMPDIR)/images/64.png $(TMPDIR)/images/128.png \
-					$(PWD)/public/img/favicon.ico
-	convert -flatten $(PWD)/public/img/favicon.png $(PWD)/public/img/apple-touch-icon.png
-
-	rm -rf $(TMPDIR)/images
-	$(foreach file, $(shell find public/img -type f -name '*.png' ! -name 'loading.png'),zopflipng -m -y $(file) $(file);)
+	npm install --no-save --no-package-lock fabric imagemin-zopfli
+	node build/generate-images.js $(TAGS)
 
 .PHONY: pr\#%
 pr\#%: clean-all
@@ -654,9 +709,18 @@ pr\#%: clean-all
 golangci-lint:
 	@hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
 		export BINARY="golangci-lint"; \
-		curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.24.0; \
+		curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.35.2; \
 	fi
-	golangci-lint run --timeout 5m
+	golangci-lint run --timeout 10m
+
+.PHONY: docker
+docker:
+	docker build --disable-content-trust=false -t $(DOCKER_REF) .
+# support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify"  .
+
+.PHONY: docker-build
+docker-build:
+	docker run -ti --rm -v "$(CURDIR):/srv/app/src/code.gitea.io/gitea" -w /srv/app/src/code.gitea.io/gitea -e TAGS="bindata $(TAGS)" LDFLAGS="$(LDFLAGS)" CGO_EXTRA_CFLAGS="$(CGO_EXTRA_CFLAGS)" webhippie/golang:edge make clean build
 
 # This endif closes the if at the top of the file
 endif
diff --git a/README.md b/README.md
index f5aeaf3ca8906..ea0d83c9081af 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,55 @@
-[简体中文](README_ZH.md)
-
-

logo Gitea - Git with a cup of tea

- -[![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](https://drone.gitea.io/go-gitea/gitea) -[![Join the Discord chat at https://discord.gg/Gitea](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/Gitea) -[![](https://images.microbadger.com/badges/image/gitea/gitea.svg)](https://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com") -[![codecov](https://codecov.io/gh/go-gitea/gitea/branch/master/graph/badge.svg)](https://codecov.io/gh/go-gitea/gitea) -[![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea) -[![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea) -[![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest) -[![Help Contribute to Open Source](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea) -[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea) -[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) -[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea) +

+ + Gitea + +

+

Gitea - Git with a cup of tea

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +

+ View the chinese version of this document +

## Purpose @@ -39,12 +76,14 @@ or if sqlite support is required: The `build` target is split into two sub-targets: -- `make backend` which requires [Go 1.12](https://golang.org/dl/) or greater. +- `make backend` which requires [Go 1.13](https://golang.org/dl/) or greater. - `make frontend` which requires [Node.js 10.13](https://nodejs.org/en/download/) or greater. If pre-built frontend files are present it is possible to only build the backend: - TAGS="bindata" make backend + TAGS="bindata" make backend + +Parallelism is not supported for these targets, so please don't include `-j `. More info: https://docs.gitea.io/en-us/install-from-source/ @@ -66,11 +105,12 @@ NOTES: ## Further information -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 [forum](https://discourse.gitea.io/)! +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). +The official Gitea CLI is developed at [gitea/tea](https://gitea.com/gitea/tea). ## Authors diff --git a/README_ZH.md b/README_ZH.md index 5163e336d2eb4..037f27dc9d353 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -1,18 +1,55 @@ -[English](README.md) - -

logo Gitea - Git with a cup of tea

- -[![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](https://drone.gitea.io/go-gitea/gitea) -[![Join the Discord chat at https://discord.gg/Gitea](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/Gitea) -[![](https://images.microbadger.com/badges/image/gitea/gitea.svg)](https://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com") -[![codecov](https://codecov.io/gh/go-gitea/gitea/branch/master/graph/badge.svg)](https://codecov.io/gh/go-gitea/gitea) -[![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea) -[![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea) -[![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest) -[![Help Contribute to Open Source](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea) -[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea) -[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) -[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea) +

+ + Gitea + +

+

Gitea - Git with a cup of tea

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +

+ View the english version of this document +

## 目标 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000000..9846a94f7e835 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,10 @@ +# Reporting security issues + +The Gitea maintainers take security seriously. +If you discover a security issue, please bring it to their attention right away! + +### Reporting a Vulnerability + +Please **DO NOT** file a public issue, instead send your report privately to `security@gitea.io`. + +Security reports are greatly appreciated and we will publicly thank you for it, although we keep your name confidential if you request it. diff --git a/assets/logo.svg b/assets/logo.svg index ac1594adb808a..9df6b83b564bd 100644 --- a/assets/logo.svg +++ b/assets/logo.svg @@ -1,160 +1,31 @@ - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/build.go b/build.go index 4b13e5bbfc0fc..ab57fb1d9a0e0 100644 --- a/build.go +++ b/build.go @@ -11,12 +11,12 @@ package main import ( // for lint - _ "github.com/BurntSushi/toml" _ "github.com/mgechev/dots" _ "github.com/mgechev/revive/formatter" _ "github.com/mgechev/revive/lint" _ "github.com/mgechev/revive/rule" _ "github.com/mitchellh/go-homedir" + _ "github.com/pelletier/go-toml" // for embed _ "github.com/shurcooL/vfsgen" @@ -25,7 +25,7 @@ import ( _ "golang.org/x/tools/cover" // for vet - _ "gitea.com/jolheiser/gitea-vet" + _ "code.gitea.io/gitea-vet" // for swagger _ "github.com/go-swagger/go-swagger/cmd/swagger" diff --git a/build/generate-gitignores.go b/build/generate-gitignores.go index 0f56ff3a89710..846bb076365d2 100644 --- a/build/generate-gitignores.go +++ b/build/generate-gitignores.go @@ -15,16 +15,22 @@ import ( "path" "path/filepath" "strings" + + "code.gitea.io/gitea/modules/util" ) func main() { var ( - prefix = "gitea-gitignore" - url = "https://api.github.com/repos/github/gitignore/tarball" - destination = "" + prefix = "gitea-gitignore" + url = "https://api.github.com/repos/github/gitignore/tarball" + githubApiToken = "" + githubUsername = "" + destination = "" ) flag.StringVar(&destination, "dest", "options/gitignore/", "destination for the gitignores") + flag.StringVar(&githubUsername, "username", "", "github username") + flag.StringVar(&githubApiToken, "token", "", "github api token") flag.Parse() file, err := ioutil.TempFile(os.TempDir(), prefix) @@ -33,14 +39,21 @@ func main() { log.Fatalf("Failed to create temp file. %s", err) } - defer os.Remove(file.Name()) - - resp, err := http.Get(url) + defer util.Remove(file.Name()) + req, err := http.NewRequest("GET", url, nil) if err != nil { log.Fatalf("Failed to download archive. %s", err) } + if len(githubApiToken) > 0 && len(githubUsername) > 0 { + req.SetBasicAuth(githubUsername, githubApiToken) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + log.Fatalf("Failed to download archive. %s", err) + } defer resp.Body.Close() if _, err := io.Copy(file, resp.Body); err != nil { diff --git a/build/generate-images.js b/build/generate-images.js new file mode 100755 index 0000000000000..c9108ce71345f --- /dev/null +++ b/build/generate-images.js @@ -0,0 +1,82 @@ +#!/usr/bin/env node +'use strict'; + +const imageminZopfli = require('imagemin-zopfli'); +const Svgo = require('svgo'); +const {fabric} = require('fabric'); +const {readFile, writeFile} = require('fs').promises; +const {resolve} = require('path'); + +const logoFile = resolve(__dirname, '../assets/logo.svg'); + +function exit(err) { + if (err) console.error(err); + process.exit(err ? 1 : 0); +} + +function loadSvg(svg) { + return new Promise((resolve) => { + fabric.loadSVGFromString(svg, (objects, options) => { + resolve({objects, options}); + }); + }); +} + +async function generate(svg, outputFile, {size, bg}) { + if (outputFile.endsWith('.svg')) { + const svgo = new Svgo({ + plugins: [ + {removeDimensions: true}, + {addAttributesToSVGElement: {attributes: [{width: size}, {height: size}]}}, + ], + }); + + const {data} = await svgo.optimize(svg); + await writeFile(outputFile, data); + return; + } + + const {objects, options} = await loadSvg(svg); + const canvas = new fabric.Canvas(); + canvas.setDimensions({width: size, height: size}); + const ctx = canvas.getContext('2d'); + ctx.scale(options.width ? (size / options.width) : 1, options.height ? (size / options.height) : 1); + + if (bg) { + canvas.add(new fabric.Rect({ + left: 0, + top: 0, + height: size * (1 / (size / options.height)), + width: size * (1 / (size / options.width)), + fill: 'white', + })); + } + + canvas.add(fabric.util.groupSVGElements(objects, options)); + canvas.renderAll(); + + let png = Buffer.from([]); + for await (const chunk of canvas.createPNGStream()) { + png = Buffer.concat([png, chunk]); + } + + png = await imageminZopfli({more: true})(png); + await writeFile(outputFile, png); +} + +async function main() { + const gitea = process.argv.slice(2).includes('gitea'); + const svg = await readFile(logoFile, 'utf8'); + + await Promise.all([ + generate(svg, resolve(__dirname, '../public/img/logo.svg'), {size: 32}), + generate(svg, resolve(__dirname, '../public/img/logo.png'), {size: 512}), + generate(svg, resolve(__dirname, '../public/img/favicon.png'), {size: 180}), + generate(svg, resolve(__dirname, '../public/img/avatar_default.png'), {size: 200}), + generate(svg, resolve(__dirname, '../public/img/apple-touch-icon.png'), {size: 180, bg: true}), + gitea && generate(svg, resolve(__dirname, '../public/img/gitea.svg'), {size: 32}), + ]); +} + +main().then(exit).catch(exit); + diff --git a/build/generate-licenses.go b/build/generate-licenses.go index 15db19e70a391..9dd13adf9a7bc 100644 --- a/build/generate-licenses.go +++ b/build/generate-licenses.go @@ -15,16 +15,22 @@ import ( "path" "path/filepath" "strings" + + "code.gitea.io/gitea/modules/util" ) func main() { var ( - prefix = "gitea-licenses" - url = "https://api.github.com/repos/spdx/license-list-data/tarball" - destination = "" + prefix = "gitea-licenses" + url = "https://api.github.com/repos/spdx/license-list-data/tarball" + githubApiToken = "" + githubUsername = "" + destination = "" ) flag.StringVar(&destination, "dest", "options/license/", "destination for the licenses") + flag.StringVar(&githubUsername, "username", "", "github username") + flag.StringVar(&githubApiToken, "token", "", "github api token") flag.Parse() file, err := ioutil.TempFile(os.TempDir(), prefix) @@ -33,10 +39,18 @@ func main() { log.Fatalf("Failed to create temp file. %s", err) } - defer os.Remove(file.Name()) + defer util.Remove(file.Name()) + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + log.Fatalf("Failed to download archive. %s", err) + } - resp, err := http.Get(url) + if len(githubApiToken) > 0 && len(githubUsername) > 0 { + req.SetBasicAuth(githubUsername, githubApiToken) + } + resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatalf("Failed to download archive. %s", err) } diff --git a/build/generate-svg.js b/build/generate-svg.js new file mode 100755 index 0000000000000..52d2c519ef47b --- /dev/null +++ b/build/generate-svg.js @@ -0,0 +1,73 @@ +#!/usr/bin/env node +'use strict'; + +const fastGlob = require('fast-glob'); +const Svgo = require('svgo'); +const {resolve, parse} = require('path'); +const {readFile, writeFile, mkdir} = require('fs').promises; + +const glob = (pattern) => fastGlob.sync(pattern, {cwd: resolve(__dirname), absolute: true}); +const outputDir = resolve(__dirname, '../public/img/svg'); + +function exit(err) { + if (err) console.error(err); + process.exit(err ? 1 : 0); +} + +async function processFile(file, {prefix, fullName} = {}) { + let name; + + if (fullName) { + name = fullName; + } else { + name = parse(file).name; + if (prefix) name = `${prefix}-${name}`; + if (prefix === 'octicon') name = name.replace(/-[0-9]+$/, ''); // chop of '-16' on octicons + } + + const svgo = new Svgo({ + plugins: [ + {removeXMLNS: true}, + {removeDimensions: true}, + { + addClassesToSVGElement: { + classNames: [ + 'svg', + name, + ], + }, + }, + { + addAttributesToSVGElement: { + attributes: [ + {'width': '16'}, + {'height': '16'}, + {'aria-hidden': 'true'}, + ], + }, + }, + ], + }); + + const {data} = await svgo.optimize(await readFile(file, 'utf8')); + await writeFile(resolve(outputDir, `${name}.svg`), data); +} + +function processFiles(pattern, opts) { + return glob(pattern).map((file) => processFile(file, opts)); +} + +async function main() { + try { + await mkdir(outputDir); + } catch {} + + await Promise.all([ + ...processFiles('../node_modules/@primer/octicons/build/svg/*-16.svg', {prefix: 'octicon'}), + ...processFiles('../web_src/svg/*.svg'), + ...processFiles('../assets/logo.svg', {fullName: 'gitea-gitea'}), + ]); +} + +main().then(exit).catch(exit); + diff --git a/build/lint.go b/build/lint.go index bc6ddbec41462..60e93697aa7af 100644 --- a/build/lint.go +++ b/build/lint.go @@ -15,12 +15,12 @@ import ( "path/filepath" "strings" - "github.com/BurntSushi/toml" "github.com/mgechev/dots" "github.com/mgechev/revive/formatter" "github.com/mgechev/revive/lint" "github.com/mgechev/revive/rule" "github.com/mitchellh/go-homedir" + "github.com/pelletier/go-toml" ) func fail(err string) { @@ -133,7 +133,7 @@ func parseConfig(path string) *lint.Config { if err != nil { fail("cannot read the config file") } - _, err = toml.Decode(string(file), config) + err = toml.Unmarshal(file, config) if err != nil { fail("cannot parse the config file: " + err.Error()) } diff --git a/build/update-locales.sh b/build/update-locales.sh index 2dad93513b5cc..046f48ee86691 100755 --- a/build/update-locales.sh +++ b/build/update-locales.sh @@ -10,10 +10,10 @@ sed -i -r -e '/^[a-zA-Z0-9_.-]+[ ]*=[ ]*".*"$/ { }' ./options/locale/*.ini # Remove translation under 25% of en_us -baselines=`wc -l "./options/locale_en-US.ini" | cut -d" " -f1` +baselines=$(wc -l "./options/locale_en-US.ini" | cut -d" " -f1) baselines=$((baselines / 4)) for filename in ./options/locale/*.ini; do - lines=`wc -l "$filename" | cut -d" " -f1` + lines=$(wc -l "$filename" | cut -d" " -f1) if [ $lines -lt $baselines ]; then echo "Removing $filename: $lines/$baselines" rm "$filename" diff --git a/cmd/admin.go b/cmd/admin.go index a049f7f2cf17b..3ddf8eddf9e6c 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -6,9 +6,11 @@ package cmd import ( + "context" "errors" "fmt" "os" + "strings" "text/tabwriter" "code.gitea.io/gitea/models" @@ -29,16 +31,39 @@ var ( Name: "admin", Usage: "Command line interface to perform common administrative operations", Subcommands: []cli.Command{ - subcmdCreateUser, - subcmdChangePassword, + subcmdUser, subcmdRepoSyncReleases, subcmdRegenerate, subcmdAuth, + subcmdSendMail, }, } - subcmdCreateUser = cli.Command{ - Name: "create-user", + subcmdUser = cli.Command{ + Name: "user", + Usage: "Modify users", + Subcommands: []cli.Command{ + microcmdUserCreate, + microcmdUserList, + microcmdUserChangePassword, + microcmdUserDelete, + }, + } + + microcmdUserList = cli.Command{ + Name: "list", + Usage: "List users", + Action: runListUsers, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "admin", + Usage: "List only admin users", + }, + }, + } + + microcmdUserCreate = cli.Command{ + Name: "create", Usage: "Create a new user in database", Action: runCreateUser, Flags: []cli.Flag{ @@ -82,7 +107,7 @@ var ( }, } - subcmdChangePassword = cli.Command{ + microcmdUserChangePassword = cli.Command{ Name: "change-password", Usage: "Change a user's password", Action: runChangePassword, @@ -100,6 +125,26 @@ var ( }, } + microcmdUserDelete = cli.Command{ + Name: "delete", + Usage: "Delete specific user by id, name or email", + Flags: []cli.Flag{ + cli.Int64Flag{ + Name: "id", + Usage: "ID of user of the user to delete", + }, + cli.StringFlag{ + Name: "username,u", + Usage: "Username of the user to delete", + }, + cli.StringFlag{ + Name: "email,e", + Usage: "Email of the user to delete", + }, + }, + Action: runDeleteUser, + } + subcmdRepoSyncReleases = cli.Command{ Name: "repo-sync-releases", Usage: "Synchronize repository releases with tags", @@ -237,6 +282,11 @@ var ( Value: "", Usage: "Use a custom Email URL (option for GitHub)", }, + cli.StringFlag{ + Name: "icon-url", + Value: "", + Usage: "Custom icon URL for OAuth2 login source", + }, } microcmdAuthUpdateOauth = cli.Command{ @@ -252,6 +302,28 @@ var ( Action: runAddOauth, Flags: oauthCLIFlags, } + + subcmdSendMail = cli.Command{ + Name: "sendmail", + Usage: "Send a message to all users", + Action: runSendMail, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "title", + Usage: `a title of a message`, + Value: "", + }, + cli.StringFlag{ + Name: "content", + Usage: "a content of a message", + Value: "", + }, + cli.BoolFlag{ + Name: "force,f", + Usage: "A flag to bypass a confirmation step", + }, + }, + } ) func runChangePassword(c *cli.Context) error { @@ -265,17 +337,23 @@ func runChangePassword(c *cli.Context) error { if !pwd.IsComplexEnough(c.String("password")) { return errors.New("Password does not meet complexity requirements") } + pwned, err := pwd.IsPwned(context.Background(), c.String("password")) + if err != nil { + return err + } + if pwned { + return errors.New("The password you chose is on a list of stolen passwords previously exposed in public data breaches. Please try again with a different password.\nFor more details, see https://haveibeenpwned.com/Passwords") + } uname := c.String("username") user, err := models.GetUserByName(uname) if err != nil { return err } - if user.Salt, err = models.GetUserSalt(); err != nil { + if err = user.SetPassword(c.String("password")); err != nil { return err } - user.HashPassword(c.String("password")) - if err := models.UpdateUserCols(user, "passwd", "salt"); err != nil { + if err = models.UpdateUserCols(user, "passwd", "passwd_hash_algo", "salt"); err != nil { return err } @@ -369,6 +447,71 @@ func runCreateUser(c *cli.Context) error { return nil } +func runListUsers(c *cli.Context) error { + if err := initDB(); err != nil { + return err + } + + users, err := models.GetAllUsers() + + if err != nil { + return err + } + + w := tabwriter.NewWriter(os.Stdout, 5, 0, 1, ' ', 0) + + if c.IsSet("admin") { + fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\n") + for _, u := range users { + if u.IsAdmin { + fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", u.ID, u.Name, u.Email, u.IsActive) + } + } + } else { + fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\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) + } + + } + + w.Flush() + return nil + +} + +func runDeleteUser(c *cli.Context) error { + if !c.IsSet("id") && !c.IsSet("username") && !c.IsSet("email") { + return fmt.Errorf("You must provide the id, username or email of a user to delete") + } + + if err := initDB(); err != nil { + return err + } + + var err error + var user *models.User + if c.IsSet("email") { + user, err = models.GetUserByEmail(c.String("email")) + } else if c.IsSet("username") { + user, err = models.GetUserByName(c.String("username")) + } else { + user, err = models.GetUserByID(c.Int64("id")) + } + if err != nil { + return err + } + if c.IsSet("username") && user.LowerName != strings.ToLower(strings.TrimSpace(c.String("username"))) { + return fmt.Errorf("The user %s who has email %s does not match the provided username %s", user.Name, c.String("email"), c.String("username")) + } + + if c.IsSet("id") && user.ID != c.Int64("id") { + return fmt.Errorf("The user %s does not match the provided id %d", user.Name, c.Int64("id")) + } + + return models.DeleteUser(user) +} + func runRepoSyncReleases(c *cli.Context) error { if err := initDB(); err != nil { return err @@ -467,6 +610,7 @@ func parseOAuth2Config(c *cli.Context) *models.OAuth2Config { ClientSecret: c.String("secret"), OpenIDConnectAutoDiscoveryURL: c.String("auto-discover-url"), CustomURLMapping: customURLMapping, + IconURL: c.String("icon-url"), } } @@ -519,6 +663,10 @@ func runUpdateOauth(c *cli.Context) error { oAuth2Config.OpenIDConnectAutoDiscoveryURL = c.String("auto-discover-url") } + if c.IsSet("icon-url") { + oAuth2Config.IconURL = c.String("icon-url") + } + // update custom URL mapping var customURLMapping = &oauth2.CustomURLMapping{} diff --git a/cmd/cmd.go b/cmd/cmd.go index d05eb8b1a2c3f..bb768cc159d64 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -9,6 +9,7 @@ package cmd import ( "errors" "fmt" + "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/setting" @@ -32,6 +33,25 @@ func argsSet(c *cli.Context, args ...string) error { return nil } +// confirm waits for user input which confirms an action +func confirm() (bool, error) { + var response string + + _, err := fmt.Scanln(&response) + if err != nil { + return false, err + } + + switch strings.ToLower(response) { + case "y", "yes": + return true, nil + case "n", "no": + return false, nil + default: + return false, errors.New(response + " isn't a correct confirmation string") + } +} + func initDB() error { return initDBDisableConsole(false) } diff --git a/cmd/docs.go b/cmd/docs.go new file mode 100644 index 0000000000000..52233c7ac872d --- /dev/null +++ b/cmd/docs.go @@ -0,0 +1,61 @@ +// Copyright 2020 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 cmd + +import ( + "fmt" + "os" + "strings" + + "github.com/urfave/cli" +) + +// CmdDocs represents the available docs sub-command. +var CmdDocs = cli.Command{ + Name: "docs", + Usage: "Output CLI documentation", + Description: "A command to output Gitea's CLI documentation, optionally to a file.", + Action: runDocs, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "man", + Usage: "Output man pages instead", + }, + &cli.StringFlag{ + Name: "output, o", + Usage: "Path to output to instead of stdout (will overwrite if exists)", + }, + }, +} + +func runDocs(ctx *cli.Context) error { + docs, err := ctx.App.ToMarkdown() + if ctx.Bool("man") { + docs, err = ctx.App.ToMan() + } + if err != nil { + return err + } + + if !ctx.Bool("man") { + // Clean up markdown. The following bug was fixed in v2, but is present in v1. + // It affects markdown output (even though the issue is referring to man pages) + // https://github.com/urfave/cli/issues/1040 + docs = docs[strings.Index(docs, "#"):] + } + + out := os.Stdout + if ctx.String("output") != "" { + fi, err := os.Create(ctx.String("output")) + if err != nil { + return err + } + defer fi.Close() + out = fi + } + + _, err = fmt.Fprintln(out, docs) + return err +} diff --git a/cmd/doctor.go b/cmd/doctor.go index 3456f26f7020d..0152aebe39959 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -5,26 +5,20 @@ package cmd import ( - "bufio" - "bytes" "context" "fmt" - "io/ioutil" golog "log" "os" - "os/exec" - "path/filepath" "strings" "text/tabwriter" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/migrations" - "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/doctor" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/options" - "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" - "xorm.io/builder" + + "xorm.io/xorm" "github.com/urfave/cli" ) @@ -60,67 +54,73 @@ var CmdDoctor = cli.Command{ Name: "log-file", Usage: `Name of the log file (default: "doctor.log"). Set to "-" to output to stdout, set to "" to disable`, }, + cli.BoolFlag{ + Name: "color, H", + Usage: "Use color for outputted information", + }, + }, + Subcommands: []cli.Command{ + cmdRecreateTable, }, } -type check struct { - title string - name string - isDefault bool - f func(ctx *cli.Context) ([]string, error) - abortIfFailed bool - skipDatabaseInit bool +var cmdRecreateTable = cli.Command{ + Name: "recreate-table", + Usage: "Recreate tables from XORM definitions and copy the data.", + ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + Usage: "Print SQL commands sent", + }, + }, + Description: `The database definitions Gitea uses change across versions, sometimes changing default values and leaving old unused columns. + +This command will cause Xorm to recreate tables, copying over the data and deleting the old table. + +You should back-up your database before doing this and ensure that your database is up-to-date first.`, + Action: runRecreateTable, } -// checklist represents list for all checks -var checklist = []check{ - { - // NOTE: this check should be the first in the list - title: "Check paths and basic configuration", - name: "paths", - isDefault: true, - f: runDoctorPathInfo, - abortIfFailed: true, - skipDatabaseInit: true, - }, - { - title: "Check Database Version", - name: "check-db-version", - isDefault: true, - f: runDoctorCheckDBVersion, - abortIfFailed: false, - }, - { - title: "Check consistency of database", - name: "check-db-consistency", - isDefault: false, - f: runDoctorCheckDBConsistency, - }, - { - title: "Check if OpenSSH authorized_keys file is up-to-date", - name: "authorized_keys", - isDefault: true, - f: runDoctorAuthorizedKeys, - }, - { - title: "Check if SCRIPT_TYPE is available", - name: "script-type", - isDefault: false, - f: runDoctorScriptType, - }, - { - title: "Check if hook files are up-to-date and executable", - name: "hooks", - isDefault: false, - f: runDoctorHooks, - }, - { - title: "Recalculate merge bases", - name: "recalculate_merge_bases", - isDefault: false, - f: runDoctorPRMergeBase, - }, - // more checks please append here +func runRecreateTable(ctx *cli.Context) error { + // Redirect the default golog to here + golog.SetFlags(0) + golog.SetPrefix("") + golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT))) + + setting.NewContext() + setting.InitDBConfig() + + setting.EnableXORMLog = ctx.Bool("debug") + setting.Database.LogSQL = ctx.Bool("debug") + setting.Cfg.Section("log").Key("XORM").SetValue(",") + + setting.NewXORMLogService(!ctx.Bool("debug")) + if err := models.SetEngine(); err != nil { + fmt.Println(err) + fmt.Println("Check if you are using the right config file. You can use a --config directive to specify one.") + return nil + } + + args := ctx.Args() + names := make([]string, 0, ctx.NArg()) + for i := 0; i < ctx.NArg(); i++ { + names = append(names, args.Get(i)) + } + + beans, err := models.NamesToBean(names...) + if err != nil { + return err + } + recreateTables := migrations.RecreateTables(beans...) + + return models.NewEngine(context.Background(), func(x *xorm.Engine) error { + if err := migrations.EnsureUpToDate(x); err != nil { + return err + } + return recreateTables(x) + }) + } func runDoctor(ctx *cli.Context) error { @@ -135,10 +135,15 @@ func runDoctor(ctx *cli.Context) error { logFile = "doctor.log" } + colorize := log.CanColorStdout + if ctx.IsSet("color") { + colorize = ctx.Bool("color") + } + if len(logFile) == 0 { - log.NewLogger(1000, "doctor", "console", `{"level":"NONE","stacktracelevel":"NONE","colorize":"%t"}`) + log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"NONE","stacktracelevel":"NONE","colorize":%t}`, colorize)) } else if logFile == "-" { - log.NewLogger(1000, "doctor", "console", `{"level":"trace","stacktracelevel":"NONE"}`) + log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"trace","stacktracelevel":"NONE","colorize":%t}`, colorize)) } else { log.NewLogger(1000, "doctor", "file", fmt.Sprintf(`{"filename":%q,"level":"trace","stacktracelevel":"NONE"}`, logFile)) } @@ -149,24 +154,24 @@ func runDoctor(ctx *cli.Context) error { golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT))) if ctx.IsSet("list") { - w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0) + w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) _, _ = w.Write([]byte("Default\tName\tTitle\n")) - for _, check := range checklist { - if check.isDefault { + for _, check := range doctor.Checks { + if check.IsDefault { _, _ = w.Write([]byte{'*'}) } _, _ = w.Write([]byte{'\t'}) - _, _ = w.Write([]byte(check.name)) + _, _ = w.Write([]byte(check.Name)) _, _ = w.Write([]byte{'\t'}) - _, _ = w.Write([]byte(check.title)) + _, _ = w.Write([]byte(check.Title)) _, _ = w.Write([]byte{'\n'}) } return w.Flush() } - var checks []check + var checks []*doctor.Check if ctx.Bool("all") { - checks = checklist + checks = doctor.Checks } else if ctx.IsSet("run") { addDefault := ctx.Bool("default") names := ctx.StringSlice("run") @@ -174,407 +179,37 @@ func runDoctor(ctx *cli.Context) error { names[i] = strings.ToLower(strings.TrimSpace(name)) } - for _, check := range checklist { - if addDefault && check.isDefault { + for _, check := range doctor.Checks { + if addDefault && check.IsDefault { checks = append(checks, check) continue } for _, name := range names { - if name == check.name { + if name == check.Name { checks = append(checks, check) break } } } } else { - for _, check := range checklist { - if check.isDefault { + for _, check := range doctor.Checks { + if check.IsDefault { checks = append(checks, check) } } } - dbIsInit := false - - for i, check := range checks { - if !dbIsInit && !check.skipDatabaseInit { - // Only open database after the most basic configuration check - setting.EnableXORMLog = false - if err := initDBDisableConsole(true); err != nil { - fmt.Println(err) - fmt.Println("Check if you are using the right config file. You can use a --config directive to specify one.") - return nil - } - dbIsInit = true - } - fmt.Println("[", i+1, "]", check.title) - messages, err := check.f(ctx) - for _, message := range messages { - fmt.Println("-", message) - } - if err != nil { - fmt.Println("Error:", err) - if check.abortIfFailed { - return nil - } - } else { - fmt.Println("OK.") - } - fmt.Println() - } - return nil -} - -func runDoctorPathInfo(ctx *cli.Context) ([]string, error) { - - res := make([]string, 0, 10) - - if fi, err := os.Stat(setting.CustomConf); err != nil || !fi.Mode().IsRegular() { - res = append(res, fmt.Sprintf("Failed to find configuration file at '%s'.", setting.CustomConf)) - res = append(res, fmt.Sprintf("If you've never ran Gitea yet, this is normal and '%s' will be created for you on first run.", setting.CustomConf)) - res = append(res, "Otherwise check that you are running this command from the correct path and/or provide a `--config` parameter.") - return res, fmt.Errorf("can't proceed without a configuration file") - } - - setting.NewContext() - - fail := false - - check := func(name, path string, is_dir, required, is_write bool) { - res = append(res, fmt.Sprintf("%-25s '%s'", name+":", path)) - fi, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) && ctx.Bool("fix") && is_dir { - if err := os.MkdirAll(path, 0777); err != nil { - res = append(res, fmt.Sprintf(" ERROR: %v", err)) - fail = true - return - } - fi, err = os.Stat(path) - } - } - if err != nil { - if required { - res = append(res, fmt.Sprintf(" ERROR: %v", err)) - fail = true - return - } - res = append(res, fmt.Sprintf(" NOTICE: not accessible (%v)", err)) - return - } - - if is_dir && !fi.IsDir() { - res = append(res, " ERROR: not a directory") - fail = true - return - } else if !is_dir && !fi.Mode().IsRegular() { - res = append(res, " ERROR: not a regular file") - fail = true - } else if is_write { - if err := runDoctorWritableDir(path); err != nil { - res = append(res, fmt.Sprintf(" ERROR: not writable: %v", err)) - fail = true - } - } - } - - // Note print paths inside quotes to make any leading/trailing spaces evident - check("Configuration File Path", setting.CustomConf, false, true, false) - check("Repository Root Path", setting.RepoRootPath, true, true, true) - check("Data Root Path", setting.AppDataPath, true, true, true) - check("Custom File Root Path", setting.CustomPath, true, false, false) - check("Work directory", setting.AppWorkPath, true, true, false) - check("Log Root Path", setting.LogRootPath, true, true, true) - - if options.IsDynamic() { - // Do not check/report on StaticRootPath if data is embedded in Gitea (-tags bindata) - check("Static File Root Path", setting.StaticRootPath, true, true, false) - } - - if fail { - return res, fmt.Errorf("please check your configuration file and try again") - } - - return res, nil -} - -func runDoctorWritableDir(path string) error { - // There's no platform-independent way of checking if a directory is writable - // https://stackoverflow.com/questions/20026320/how-to-tell-if-folder-exists-and-is-writable - - tmpFile, err := ioutil.TempFile(path, "doctors-order") - if err != nil { + // Now we can set up our own logger to return information about what the doctor is doing + if err := log.NewNamedLogger("doctorouter", + 1000, + "console", + "console", + fmt.Sprintf(`{"level":"INFO","stacktracelevel":"NONE","colorize":%t,"flags":-1}`, colorize)); err != nil { + fmt.Println(err) return err } - if err := os.Remove(tmpFile.Name()); err != nil { - fmt.Printf("Warning: can't remove temporary file: '%s'\n", tmpFile.Name()) - } - tmpFile.Close() - return nil -} - -const tplCommentPrefix = `# gitea public key` - -func runDoctorAuthorizedKeys(ctx *cli.Context) ([]string, error) { - if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile { - return nil, nil - } - - fPath := filepath.Join(setting.SSH.RootPath, "authorized_keys") - f, err := os.Open(fPath) - if err != nil { - if ctx.Bool("fix") { - return []string{fmt.Sprintf("Error whilst opening authorized_keys: %v. Attempting regeneration", err)}, models.RewriteAllPublicKeys() - } - return nil, err - } - defer f.Close() - - linesInAuthorizedKeys := map[string]bool{} - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := scanner.Text() - if strings.HasPrefix(line, tplCommentPrefix) { - continue - } - linesInAuthorizedKeys[line] = true - } - f.Close() - - // now we regenerate and check if there are any lines missing - regenerated := &bytes.Buffer{} - if err := models.RegeneratePublicKeys(regenerated); err != nil { - return nil, err - } - scanner = bufio.NewScanner(regenerated) - for scanner.Scan() { - line := scanner.Text() - if strings.HasPrefix(line, tplCommentPrefix) { - continue - } - if ok := linesInAuthorizedKeys[line]; ok { - continue - } - if ctx.Bool("fix") { - return []string{"authorized_keys is out of date, attempting regeneration"}, models.RewriteAllPublicKeys() - } - return nil, fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized_keys --fix"`) - } - return nil, nil -} - -func runDoctorCheckDBVersion(ctx *cli.Context) ([]string, error) { - if err := models.NewEngine(context.Background(), migrations.EnsureUpToDate); err != nil { - if ctx.Bool("fix") { - return []string{fmt.Sprintf("WARN: Got Error %v during ensure up to date", err), "Attempting to migrate to the latest DB version to fix this."}, models.NewEngine(context.Background(), migrations.Migrate) - } - return nil, err - } - return nil, nil -} - -func iterateRepositories(each func(*models.Repository) ([]string, error)) ([]string, error) { - results := []string{} - err := models.Iterate( - models.DefaultDBContext(), - new(models.Repository), - builder.Gt{"id": 0}, - func(idx int, bean interface{}) error { - res, err := each(bean.(*models.Repository)) - results = append(results, res...) - return err - }, - ) - return results, err -} - -func iteratePRs(repo *models.Repository, each func(*models.Repository, *models.PullRequest) ([]string, error)) ([]string, error) { - results := []string{} - err := models.Iterate( - models.DefaultDBContext(), - new(models.PullRequest), - builder.Eq{"base_repo_id": repo.ID}, - func(idx int, bean interface{}) error { - res, err := each(repo, bean.(*models.PullRequest)) - results = append(results, res...) - return err - }, - ) - return results, err -} - -func runDoctorHooks(ctx *cli.Context) ([]string, error) { - // Need to iterate across all of the repositories - return iterateRepositories(func(repo *models.Repository) ([]string, error) { - results, err := repository.CheckDelegateHooks(repo.RepoPath()) - if err != nil { - return nil, err - } - if len(results) > 0 && ctx.Bool("fix") { - return []string{fmt.Sprintf("regenerated hooks for %s", repo.FullName())}, repository.CreateDelegateHooks(repo.RepoPath()) - } - - return results, nil - }) -} - -func runDoctorPRMergeBase(ctx *cli.Context) ([]string, error) { - numRepos := 0 - numPRs := 0 - numPRsUpdated := 0 - results, err := iterateRepositories(func(repo *models.Repository) ([]string, error) { - numRepos++ - return iteratePRs(repo, func(repo *models.Repository, pr *models.PullRequest) ([]string, error) { - numPRs++ - results := []string{} - pr.BaseRepo = repo - repoPath := repo.RepoPath() - - oldMergeBase := pr.MergeBase - - if !pr.HasMerged { - var err error - pr.MergeBase, err = git.NewCommand("merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunInDir(repoPath) - if err != nil { - var err2 error - pr.MergeBase, err2 = git.NewCommand("rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath) - if err2 != nil { - results = append(results, fmt.Sprintf("WARN: Unable to get merge base for PR ID %d, #%d onto %s in %s/%s", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name)) - log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err, err2) - return results, nil - } - } - } else { - parentsString, err := git.NewCommand("rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath) - if err != nil { - results = append(results, fmt.Sprintf("WARN: Unable to get parents for merged PR ID %d, #%d onto %s in %s/%s", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name)) - log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err) - return results, nil - } - parents := strings.Split(strings.TrimSpace(parentsString), " ") - if len(parents) < 2 { - return results, nil - } - - args := append([]string{"merge-base", "--"}, parents[1:]...) - args = append(args, pr.GetGitRefName()) - - pr.MergeBase, err = git.NewCommand(args...).RunInDir(repoPath) - if err != nil { - results = append(results, fmt.Sprintf("WARN: Unable to get merge base for merged PR ID %d, #%d onto %s in %s/%s", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name)) - log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err) - return results, nil - } - } - pr.MergeBase = strings.TrimSpace(pr.MergeBase) - if pr.MergeBase != oldMergeBase { - if ctx.Bool("fix") { - if err := pr.UpdateCols("merge_base"); err != nil { - return results, err - } - } else { - results = append(results, fmt.Sprintf("#%d onto %s in %s/%s: MergeBase should be %s but is %s", pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, oldMergeBase, pr.MergeBase)) - } - numPRsUpdated++ - } - return results, nil - }) - }) - - if ctx.Bool("fix") { - results = append(results, fmt.Sprintf("%d PR mergebases updated of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos)) - } else { - if numPRsUpdated > 0 && err == nil { - return results, fmt.Errorf("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos) - } - results = append(results, fmt.Sprintf("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos)) - } - - return results, err -} - -func runDoctorScriptType(ctx *cli.Context) ([]string, error) { - path, err := exec.LookPath(setting.ScriptType) - if err != nil { - return []string{fmt.Sprintf("ScriptType %s is not on the current PATH", setting.ScriptType)}, err - } - return []string{fmt.Sprintf("ScriptType %s is on the current PATH at %s", setting.ScriptType, path)}, nil -} - -func runDoctorCheckDBConsistency(ctx *cli.Context) ([]string, error) { - var results []string - - // make sure DB version is uptodate - if err := models.NewEngine(context.Background(), migrations.EnsureUpToDate); err != nil { - return nil, fmt.Errorf("model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded") - } - - //find labels without existing repo or org - count, err := models.CountOrphanedLabels() - if err != nil { - return nil, err - } - if count > 0 { - if ctx.Bool("fix") { - if err = models.DeleteOrphanedLabels(); err != nil { - return nil, err - } - results = append(results, fmt.Sprintf("%d labels without existing repository/organisation deleted", count)) - } else { - results = append(results, fmt.Sprintf("%d labels without existing repository/organisation", count)) - } - } - - //find issues without existing repository - count, err = models.CountOrphanedIssues() - if err != nil { - return nil, err - } - if count > 0 { - if ctx.Bool("fix") { - if err = models.DeleteOrphanedIssues(); err != nil { - return nil, err - } - results = append(results, fmt.Sprintf("%d issues without existing repository deleted", count)) - } else { - results = append(results, fmt.Sprintf("%d issues without existing repository", count)) - } - } - - //find pulls without existing issues - count, err = models.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id") - if err != nil { - return nil, err - } - if count > 0 { - if ctx.Bool("fix") { - if err = models.DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id"); err != nil { - return nil, err - } - results = append(results, fmt.Sprintf("%d pull requests without existing issue deleted", count)) - } else { - results = append(results, fmt.Sprintf("%d pull requests without existing issue", count)) - } - } - - //find tracked times without existing issues/pulls - count, err = models.CountOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id") - if err != nil { - return nil, err - } - if count > 0 { - if ctx.Bool("fix") { - if err = models.DeleteOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id"); err != nil { - return nil, err - } - results = append(results, fmt.Sprintf("%d tracked times without existing issue deleted", count)) - } else { - results = append(results, fmt.Sprintf("%d tracked times without existing issue", count)) - } - } - - //ToDo: function to recalc all counters - return results, nil + logger := log.GetLogger("doctorouter") + defer logger.Close() + return doctor.RunChecks(logger, ctx.Bool("fix"), checks) } diff --git a/cmd/dump.go b/cmd/dump.go index dd259575fa78d..1a2e62576792f 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -18,10 +18,11 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/util" "gitea.com/macaron/session" archiver "github.com/mholt/archiver/v3" - "github.com/unknwon/com" "github.com/urfave/cli" ) @@ -56,6 +57,8 @@ func addRecursive(w archiver.Writer, dirPath string, absPath string, verbose boo if err != nil { return fmt.Errorf("Could not open directory %s: %s", absPath, err) } + defer dir.Close() + files, err := dir.Readdir(0) if err != nil { return fmt.Errorf("Unable to list files in %s: %s", absPath, err) @@ -185,6 +188,10 @@ func runDump(ctx *cli.Context) error { if _, err := setting.Cfg.Section("log.console").NewKey("STDERR", "true"); err != nil { fatal("Setting console logger to stderr failed: %v", err) } + if !setting.InstallLock { + log.Error("Is '%s' really the right config path?\n", setting.CustomConf) + return fmt.Errorf("gitea is not initialized") + } setting.NewServices() // cannot access session settings otherwise err := models.SetEngine() @@ -192,6 +199,10 @@ func runDump(ctx *cli.Context) error { return err } + if err := storage.Init(); err != nil { + return err + } + if file == nil { file, err = os.Create(fileName) if err != nil { @@ -226,11 +237,21 @@ func runDump(ctx *cli.Context) error { fatal("Failed to include repositories: %v", err) } - if _, err := os.Stat(setting.LFS.ContentPath); !os.IsNotExist(err) { - log.Info("Dumping lfs... %s", setting.LFS.ContentPath) - if err := addRecursive(w, "lfs", setting.LFS.ContentPath, verbose); err != nil { - fatal("Failed to include lfs: %v", err) + if err := storage.LFS.IterateObjects(func(objPath string, object storage.Object) error { + info, err := object.Stat() + if err != nil { + return err } + + return w.Write(archiver.File{ + FileInfo: archiver.FileInfo{ + FileInfo: info, + CustomName: path.Join("data", "lfs", objPath), + }, + ReadCloser: object, + }) + }); err != nil { + fatal("Failed to dump LFS objects: %v", err) } } @@ -243,7 +264,11 @@ func runDump(ctx *cli.Context) error { if err != nil { fatal("Failed to create tmp file: %v", err) } - defer os.Remove(dbDump.Name()) + defer func() { + if err := util.Remove(dbDump.Name()); err != nil { + log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err) + } + }() targetDBType := ctx.String("database") if len(targetDBType) > 0 && targetDBType != setting.Database.Type { @@ -280,7 +305,11 @@ func runDump(ctx *cli.Context) error { log.Info("Custom dir %s doesn't exist, skipped", setting.CustomPath) } - if com.IsExist(setting.AppDataPath) { + isExist, err := util.IsExist(setting.AppDataPath) + if err != nil { + log.Error("Unable to check if %s exists. Error: %v", setting.AppDataPath, err) + } + if isExist { log.Info("Packing data directory...%s", setting.AppDataPath) var excludes []string @@ -293,27 +322,51 @@ func runDump(ctx *cli.Context) error { } excludes = append(excludes, setting.RepoRootPath) - excludes = append(excludes, setting.LFS.ContentPath) + excludes = append(excludes, setting.LFS.Path) + excludes = append(excludes, setting.Attachment.Path) excludes = append(excludes, setting.LogRootPath) if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil { fatal("Failed to include data directory: %v", err) } } + if err := storage.Attachments.IterateObjects(func(objPath string, object storage.Object) error { + info, err := object.Stat() + if err != nil { + return err + } + + return w.Write(archiver.File{ + FileInfo: archiver.FileInfo{ + FileInfo: info, + CustomName: path.Join("data", "attachments", objPath), + }, + ReadCloser: object, + }) + }); err != nil { + fatal("Failed to dump attachments: %v", err) + } + // Doesn't check if LogRootPath exists before processing --skip-log intentionally, // ensuring that it's clear the dump is skipped whether the directory's initialized // yet or not. if ctx.IsSet("skip-log") && ctx.Bool("skip-log") { log.Info("Skip dumping log files") - } else if com.IsExist(setting.LogRootPath) { - if err := addRecursive(w, "log", setting.LogRootPath, verbose); err != nil { - fatal("Failed to include log: %v", err) + } else { + isExist, err := util.IsExist(setting.LogRootPath) + if err != nil { + log.Error("Unable to check if %s exists. Error: %v", setting.LogRootPath, err) + } + if isExist { + if err := addRecursive(w, "log", setting.LogRootPath, verbose); err != nil { + fatal("Failed to include log: %v", err) + } } } if fileName != "-" { if err = w.Close(); err != nil { - _ = os.Remove(fileName) + _ = util.Remove(fileName) fatal("Failed to save %s: %v", fileName, err) } diff --git a/cmd/dump_repo.go b/cmd/dump_repo.go new file mode 100644 index 0000000000000..cea640b53438d --- /dev/null +++ b/cmd/dump_repo.go @@ -0,0 +1,162 @@ +// Copyright 2020 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 cmd + +import ( + "context" + "errors" + "strings" + + "code.gitea.io/gitea/modules/convert" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/migrations" + "code.gitea.io/gitea/modules/migrations/base" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" + + "github.com/urfave/cli" +) + +// CmdDumpRepository represents the available dump repository sub-command. +var CmdDumpRepository = cli.Command{ + Name: "dump-repo", + Usage: "Dump the repository from git/github/gitea/gitlab", + Description: "This is a command for dumping the repository data.", + Action: runDumpRepository, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "git_service", + Value: "", + Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.", + }, + cli.StringFlag{ + Name: "repo_dir, r", + Value: "./data", + Usage: "Repository dir path to store the data", + }, + cli.StringFlag{ + Name: "clone_addr", + Value: "", + Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL", + }, + cli.StringFlag{ + Name: "auth_username", + Value: "", + Usage: "The username to visit the clone_addr", + }, + cli.StringFlag{ + Name: "auth_password", + Value: "", + Usage: "The password to visit the clone_addr", + }, + cli.StringFlag{ + Name: "auth_token", + Value: "", + Usage: "The personal token to visit the clone_addr", + }, + cli.StringFlag{ + Name: "owner_name", + Value: "", + Usage: "The data will be stored on a directory with owner name if not empty", + }, + cli.StringFlag{ + Name: "repo_name", + Value: "", + Usage: "The data will be stored on a directory with repository name if not empty", + }, + cli.StringFlag{ + Name: "units", + Value: "", + Usage: `Which items will be migrated, one or more units should be separated as comma. +wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`, + }, + }, +} + +func runDumpRepository(ctx *cli.Context) error { + if err := initDB(); err != nil { + return err + } + + log.Trace("AppPath: %s", setting.AppPath) + log.Trace("AppWorkPath: %s", setting.AppWorkPath) + log.Trace("Custom path: %s", setting.CustomPath) + log.Trace("Log path: %s", setting.LogRootPath) + setting.InitDBConfig() + + var ( + serviceType structs.GitServiceType + cloneAddr = ctx.String("clone_addr") + serviceStr = ctx.String("git_service") + ) + + if strings.HasPrefix(strings.ToLower(cloneAddr), "https://github.com/") { + serviceStr = "github" + } else if strings.HasPrefix(strings.ToLower(cloneAddr), "https://gitlab.com/") { + serviceStr = "gitlab" + } else if strings.HasPrefix(strings.ToLower(cloneAddr), "https://gitea.com/") { + serviceStr = "gitea" + } + if serviceStr == "" { + return errors.New("git_service missed or clone_addr cannot be recognized") + } + serviceType = convert.ToGitServiceType(serviceStr) + + var opts = base.MigrateOptions{ + GitServiceType: serviceType, + CloneAddr: cloneAddr, + AuthUsername: ctx.String("auth_username"), + AuthPassword: ctx.String("auth_password"), + AuthToken: ctx.String("auth_token"), + RepoName: ctx.String("repo_name"), + } + + if len(ctx.String("units")) == 0 { + opts.Wiki = true + opts.Issues = true + opts.Milestones = true + opts.Labels = true + opts.Releases = true + opts.Comments = true + opts.PullRequests = true + opts.ReleaseAssets = true + } else { + units := strings.Split(ctx.String("units"), ",") + for _, unit := range units { + switch strings.ToLower(unit) { + case "wiki": + opts.Wiki = true + case "issues": + opts.Issues = true + case "milestones": + opts.Milestones = true + case "labels": + opts.Labels = true + case "releases": + opts.Releases = true + case "release_assets": + opts.ReleaseAssets = true + case "comments": + opts.Comments = true + case "pull_requests": + opts.PullRequests = true + } + } + } + + if err := migrations.DumpRepository( + context.Background(), + ctx.String("repo_dir"), + ctx.String("owner_name"), + opts, + ); err != nil { + log.Fatal("Failed to dump repository: %v", err) + return err + } + + log.Trace("Dump finished!!!") + + return nil +} diff --git a/cmd/hook.go b/cmd/hook.go index f5658de7cd75c..1fcc0a18c3167 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -170,7 +170,7 @@ Gitea or set your environment appropriately.`, "") username := os.Getenv(models.EnvRepoUsername) reponame := os.Getenv(models.EnvRepoName) userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64) - prID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchPRID), 10, 64) + prID, _ := strconv.ParseInt(os.Getenv(models.EnvPRID), 10, 64) isDeployKey, _ := strconv.ParseBool(os.Getenv(models.EnvIsDeployKey)) hookOptions := private.HookOptions{ @@ -178,6 +178,7 @@ Gitea or set your environment appropriately.`, "") GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories), GitObjectDirectory: os.Getenv(private.GitObjectDirectory), GitQuarantinePath: os.Getenv(private.GitQuarantinePath), + GitPushOptions: pushOptions(), ProtectedBranchID: prID, IsDeployKey: isDeployKey, } @@ -284,6 +285,12 @@ func runHookUpdate(c *cli.Context) error { } func runHookPostReceive(c *cli.Context) error { + // First of all run update-server-info no matter what + if _, err := git.NewCommand("update-server-info").Run(); err != nil { + return fmt.Errorf("Failed to call 'git update-server-info': %v", err) + } + + // Now if we're an internal don't do anything else if os.Getenv(models.EnvIsInternal) == "true" { return nil } @@ -326,6 +333,7 @@ Gitea or set your environment appropriately.`, "") GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories), GitObjectDirectory: os.Getenv(private.GitObjectDirectory), GitQuarantinePath: os.Getenv(private.GitQuarantinePath), + GitPushOptions: pushOptions(), } oldCommitIDs := make([]string, hookBatchSize) newCommitIDs := make([]string, hookBatchSize) @@ -438,3 +446,17 @@ func hookPrintResults(results []private.HookPostReceiveBranchResult) { os.Stderr.Sync() } } + +func pushOptions() map[string]string { + opts := make(map[string]string) + if pushCount, err := strconv.Atoi(os.Getenv(private.GitPushOptionCount)); err == nil { + for idx := 0; idx < pushCount; idx++ { + opt := os.Getenv(fmt.Sprintf("GIT_PUSH_OPTION_%d", idx)) + kv := strings.SplitN(opt, "=", 2) + if len(kv) == 2 { + opts[kv[0]] = kv[1] + } + } + } + return opts +} diff --git a/cmd/mailer.go b/cmd/mailer.go new file mode 100644 index 0000000000000..ee11b56cc77bf --- /dev/null +++ b/cmd/mailer.go @@ -0,0 +1,51 @@ +// Copyright 2020 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 cmd + +import ( + "fmt" + "net/http" + + "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/setting" + "github.com/urfave/cli" +) + +func runSendMail(c *cli.Context) error { + setting.NewContext() + + if err := argsSet(c, "title"); err != nil { + return err + } + + subject := c.String("title") + confirmSkiped := c.Bool("force") + body := c.String("content") + + if !confirmSkiped { + if len(body) == 0 { + fmt.Print("warning: Content is empty") + } + + fmt.Print("Proceed with sending email? [Y/n] ") + isConfirmed, err := confirm() + if err != nil { + return err + } else if !isConfirmed { + fmt.Println("The mail was not sent") + return nil + } + } + + status, message := private.SendEmail(subject, body, nil) + if status != http.StatusOK { + fmt.Printf("error: %s\n", message) + return nil + } + + fmt.Printf("Success: %s\n", message) + + return nil +} diff --git a/cmd/manager.go b/cmd/manager.go index eed0a9e823079..20c7858682aca 100644 --- a/cmd/manager.go +++ b/cmd/manager.go @@ -10,6 +10,7 @@ import ( "os" "time" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" "github.com/urfave/cli" @@ -25,16 +26,27 @@ var ( subcmdShutdown, subcmdRestart, subcmdFlushQueues, + subcmdLogging, }, } subcmdShutdown = cli.Command{ - Name: "shutdown", - Usage: "Gracefully shutdown the running process", + Name: "shutdown", + Usage: "Gracefully shutdown the running process", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, Action: runShutdown, } subcmdRestart = cli.Command{ - Name: "restart", - Usage: "Gracefully restart the running process - (not implemented for windows servers)", + Name: "restart", + Usage: "Gracefully restart the running process - (not implemented for windows servers)", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, Action: runRestart, } subcmdFlushQueues = cli.Command{ @@ -46,17 +58,331 @@ var ( Name: "timeout", Value: 60 * time.Second, Usage: "Timeout for the flushing process", - }, - cli.BoolFlag{ + }, cli.BoolFlag{ Name: "non-blocking", Usage: "Set to true to not wait for flush to complete before returning", }, + cli.BoolFlag{ + Name: "debug", + }, + }, + } + defaultLoggingFlags = []cli.Flag{ + cli.StringFlag{ + Name: "group, g", + Usage: "Group to add logger to - will default to \"default\"", + }, cli.StringFlag{ + Name: "name, n", + Usage: "Name of the new logger - will default to mode", + }, cli.StringFlag{ + Name: "level, l", + Usage: "Logging level for the new logger", + }, cli.StringFlag{ + Name: "stacktrace-level, L", + Usage: "Stacktrace logging level", + }, cli.StringFlag{ + Name: "flags, F", + Usage: "Flags for the logger", + }, cli.StringFlag{ + Name: "expression, e", + Usage: "Matching expression for the logger", + }, cli.StringFlag{ + Name: "prefix, p", + Usage: "Prefix for the logger", + }, cli.BoolFlag{ + Name: "color", + Usage: "Use color in the logs", + }, cli.BoolFlag{ + Name: "debug", + }, + } + subcmdLogging = cli.Command{ + Name: "logging", + Usage: "Adjust logging commands", + Subcommands: []cli.Command{ + { + Name: "pause", + Usage: "Pause logging (Gitea will buffer logs up to a certain point and will drop them after that point)", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, + Action: runPauseLogging, + }, { + Name: "resume", + Usage: "Resume logging", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, + Action: runResumeLogging, + }, { + Name: "release-and-reopen", + Usage: "Cause Gitea to release and re-open files used for logging", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, + Action: runReleaseReopenLogging, + }, { + Name: "remove", + Usage: "Remove a logger", + ArgsUsage: "[name] Name of logger to remove", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, cli.StringFlag{ + Name: "group, g", + Usage: "Group to add logger to - will default to \"default\"", + }, + }, + Action: runRemoveLogger, + }, { + Name: "add", + Usage: "Add a logger", + Subcommands: []cli.Command{ + { + Name: "console", + Usage: "Add a console logger", + Flags: append(defaultLoggingFlags, + cli.BoolFlag{ + Name: "stderr", + Usage: "Output console logs to stderr - only relevant for console", + }), + Action: runAddConsoleLogger, + }, { + Name: "file", + Usage: "Add a file logger", + Flags: append(defaultLoggingFlags, []cli.Flag{ + cli.StringFlag{ + Name: "filename, f", + Usage: "Filename for the logger - this must be set.", + }, cli.BoolTFlag{ + Name: "rotate, r", + Usage: "Rotate logs", + }, cli.Int64Flag{ + Name: "max-size, s", + Usage: "Maximum size in bytes before rotation", + }, cli.BoolTFlag{ + Name: "daily, d", + Usage: "Rotate logs daily", + }, cli.IntFlag{ + Name: "max-days, D", + Usage: "Maximum number of daily logs to keep", + }, cli.BoolTFlag{ + Name: "compress, z", + Usage: "Compress rotated logs", + }, cli.IntFlag{ + Name: "compression-level, Z", + Usage: "Compression level to use", + }, + }...), + Action: runAddFileLogger, + }, { + Name: "conn", + Usage: "Add a net conn logger", + Flags: append(defaultLoggingFlags, []cli.Flag{ + cli.BoolFlag{ + Name: "reconnect-on-message, R", + Usage: "Reconnect to host for every message", + }, cli.BoolFlag{ + Name: "reconnect, r", + Usage: "Reconnect to host when connection is dropped", + }, cli.StringFlag{ + Name: "protocol, P", + Usage: "Set protocol to use: tcp, unix, or udp (defaults to tcp)", + }, cli.StringFlag{ + Name: "address, a", + Usage: "Host address and port to connect to (defaults to :7020)", + }, + }...), + Action: runAddConnLogger, + }, { + Name: "smtp", + Usage: "Add an SMTP logger", + Flags: append(defaultLoggingFlags, []cli.Flag{ + cli.StringFlag{ + Name: "username, u", + Usage: "Mail server username", + }, cli.StringFlag{ + Name: "password, P", + Usage: "Mail server password", + }, cli.StringFlag{ + Name: "host, H", + Usage: "Mail server host (defaults to: 127.0.0.1:25)", + }, cli.StringSliceFlag{ + Name: "send-to, s", + Usage: "Email address(es) to send to", + }, cli.StringFlag{ + Name: "subject, S", + Usage: "Subject header of sent emails", + }, + }...), + Action: runAddSMTPLogger, + }, + }, + }, }, } ) +func runRemoveLogger(c *cli.Context) error { + setup("manager", c.Bool("debug")) + group := c.String("group") + if len(group) == 0 { + group = log.DEFAULT + } + name := c.Args().First() + statusCode, msg := private.RemoveLogger(group, name) + switch statusCode { + case http.StatusInternalServerError: + fail("InternalServerError", msg) + } + + fmt.Fprintln(os.Stdout, msg) + return nil +} + +func runAddSMTPLogger(c *cli.Context) error { + setup("manager", c.Bool("debug")) + vals := map[string]interface{}{} + mode := "smtp" + if c.IsSet("host") { + vals["host"] = c.String("host") + } else { + vals["host"] = "127.0.0.1:25" + } + + if c.IsSet("username") { + vals["username"] = c.String("username") + } + if c.IsSet("password") { + vals["password"] = c.String("password") + } + + if !c.IsSet("send-to") { + return fmt.Errorf("Some recipients must be provided") + } + vals["sendTos"] = c.StringSlice("send-to") + + if c.IsSet("subject") { + vals["subject"] = c.String("subject") + } else { + vals["subject"] = "Diagnostic message from Gitea" + } + + return commonAddLogger(c, mode, vals) +} + +func runAddConnLogger(c *cli.Context) error { + setup("manager", c.Bool("debug")) + vals := map[string]interface{}{} + mode := "conn" + vals["net"] = "tcp" + if c.IsSet("protocol") { + switch c.String("protocol") { + case "udp": + vals["net"] = "udp" + case "unix": + vals["net"] = "unix" + } + } + if c.IsSet("address") { + vals["address"] = c.String("address") + } else { + vals["address"] = ":7020" + } + if c.IsSet("reconnect") { + vals["reconnect"] = c.Bool("reconnect") + } + if c.IsSet("reconnect-on-message") { + vals["reconnectOnMsg"] = c.Bool("reconnect-on-message") + } + return commonAddLogger(c, mode, vals) +} + +func runAddFileLogger(c *cli.Context) error { + setup("manager", c.Bool("debug")) + vals := map[string]interface{}{} + mode := "file" + if c.IsSet("filename") { + vals["filename"] = c.String("filename") + } else { + return fmt.Errorf("filename must be set when creating a file logger") + } + if c.IsSet("rotate") { + vals["rotate"] = c.Bool("rotate") + } + if c.IsSet("max-size") { + vals["maxsize"] = c.Int64("max-size") + } + if c.IsSet("daily") { + vals["daily"] = c.Bool("daily") + } + if c.IsSet("max-days") { + vals["maxdays"] = c.Int("max-days") + } + if c.IsSet("compress") { + vals["compress"] = c.Bool("compress") + } + if c.IsSet("compression-level") { + vals["compressionLevel"] = c.Int("compression-level") + } + return commonAddLogger(c, mode, vals) +} + +func runAddConsoleLogger(c *cli.Context) error { + setup("manager", c.Bool("debug")) + vals := map[string]interface{}{} + mode := "console" + if c.IsSet("stderr") && c.Bool("stderr") { + vals["stderr"] = c.Bool("stderr") + } + return commonAddLogger(c, mode, vals) +} + +func commonAddLogger(c *cli.Context, mode string, vals map[string]interface{}) error { + if len(c.String("level")) > 0 { + vals["level"] = log.FromString(c.String("level")).String() + } + if len(c.String("stacktrace-level")) > 0 { + vals["stacktraceLevel"] = log.FromString(c.String("stacktrace-level")).String() + } + if len(c.String("expression")) > 0 { + vals["expression"] = c.String("expression") + } + if len(c.String("prefix")) > 0 { + vals["prefix"] = c.String("prefix") + } + if len(c.String("flags")) > 0 { + vals["flags"] = log.FlagsFromString(c.String("flags")) + } + if c.IsSet("color") { + vals["colorize"] = c.Bool("color") + } + group := "default" + if c.IsSet("group") { + group = c.String("group") + } + name := mode + if c.IsSet("name") { + name = c.String("name") + } + statusCode, msg := private.AddLogger(group, name, mode, vals) + switch statusCode { + case http.StatusInternalServerError: + fail("InternalServerError", msg) + } + + fmt.Fprintln(os.Stdout, msg) + return nil +} + func runShutdown(c *cli.Context) error { - setup("manager", false) + setup("manager", c.Bool("debug")) statusCode, msg := private.Shutdown() switch statusCode { case http.StatusInternalServerError: @@ -68,7 +394,7 @@ func runShutdown(c *cli.Context) error { } func runRestart(c *cli.Context) error { - setup("manager", false) + setup("manager", c.Bool("debug")) statusCode, msg := private.Restart() switch statusCode { case http.StatusInternalServerError: @@ -80,7 +406,7 @@ func runRestart(c *cli.Context) error { } func runFlushQueues(c *cli.Context) error { - setup("manager", false) + setup("manager", c.Bool("debug")) statusCode, msg := private.FlushQueues(c.Duration("timeout"), c.Bool("non-blocking")) switch statusCode { case http.StatusInternalServerError: @@ -90,3 +416,39 @@ func runFlushQueues(c *cli.Context) error { fmt.Fprintln(os.Stdout, msg) return nil } + +func runPauseLogging(c *cli.Context) error { + setup("manager", c.Bool("debug")) + statusCode, msg := private.PauseLogging() + switch statusCode { + case http.StatusInternalServerError: + fail("InternalServerError", msg) + } + + fmt.Fprintln(os.Stdout, msg) + return nil +} + +func runResumeLogging(c *cli.Context) error { + setup("manager", c.Bool("debug")) + statusCode, msg := private.ResumeLogging() + switch statusCode { + case http.StatusInternalServerError: + fail("InternalServerError", msg) + } + + fmt.Fprintln(os.Stdout, msg) + return nil +} + +func runReleaseReopenLogging(c *cli.Context) error { + setup("manager", c.Bool("debug")) + statusCode, msg := private.ReleaseReopenLogging() + switch statusCode { + case http.StatusInternalServerError: + fail("InternalServerError", msg) + } + + fmt.Fprintln(os.Stdout, msg) + return nil +} diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go new file mode 100644 index 0000000000000..871baed92de9e --- /dev/null +++ b/cmd/migrate_storage.go @@ -0,0 +1,190 @@ +// Copyright 2020 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 cmd + +import ( + "context" + "fmt" + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/migrations" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" + + "github.com/urfave/cli" +) + +// CmdMigrateStorage represents the available migrate storage sub-command. +var CmdMigrateStorage = cli.Command{ + Name: "migrate-storage", + Usage: "Migrate the storage", + Description: "This is a command for migrating storage.", + Action: runMigrateStorage, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "type, t", + Value: "", + Usage: "Kinds of files to migrate, currently only 'attachments' is supported", + }, + cli.StringFlag{ + Name: "storage, s", + Value: "", + Usage: "New storage type: local (default) or minio", + }, + cli.StringFlag{ + Name: "path, p", + Value: "", + Usage: "New storage placement if store is local (leave blank for default)", + }, + cli.StringFlag{ + Name: "minio-endpoint", + Value: "", + Usage: "Minio storage endpoint", + }, + cli.StringFlag{ + Name: "minio-access-key-id", + Value: "", + Usage: "Minio storage accessKeyID", + }, + cli.StringFlag{ + Name: "minio-secret-access-key", + Value: "", + Usage: "Minio storage secretAccessKey", + }, + cli.StringFlag{ + Name: "minio-bucket", + Value: "", + Usage: "Minio storage bucket", + }, + cli.StringFlag{ + Name: "minio-location", + Value: "", + Usage: "Minio storage location to create bucket", + }, + cli.StringFlag{ + Name: "minio-base-path", + Value: "", + Usage: "Minio storage basepath on the bucket", + }, + cli.BoolFlag{ + Name: "minio-use-ssl", + Usage: "Enable SSL for minio", + }, + }, +} + +func migrateAttachments(dstStorage storage.ObjectStorage) error { + return models.IterateAttachment(func(attach *models.Attachment) error { + _, err := storage.Copy(dstStorage, attach.RelativePath(), storage.Attachments, attach.RelativePath()) + return err + }) +} + +func migrateLFS(dstStorage storage.ObjectStorage) error { + return models.IterateLFS(func(mo *models.LFSMetaObject) error { + _, err := storage.Copy(dstStorage, mo.RelativePath(), storage.LFS, mo.RelativePath()) + return err + }) +} + +func migrateAvatars(dstStorage storage.ObjectStorage) error { + return models.IterateUser(func(user *models.User) error { + _, err := storage.Copy(dstStorage, user.CustomAvatarRelativePath(), storage.Avatars, user.CustomAvatarRelativePath()) + return err + }) +} + +func migrateRepoAvatars(dstStorage storage.ObjectStorage) error { + return models.IterateRepository(func(repo *models.Repository) error { + _, err := storage.Copy(dstStorage, repo.CustomAvatarRelativePath(), storage.RepoAvatars, repo.CustomAvatarRelativePath()) + return err + }) +} + +func runMigrateStorage(ctx *cli.Context) error { + if err := initDB(); err != nil { + return err + } + + log.Trace("AppPath: %s", setting.AppPath) + log.Trace("AppWorkPath: %s", setting.AppWorkPath) + log.Trace("Custom path: %s", setting.CustomPath) + log.Trace("Log path: %s", setting.LogRootPath) + setting.InitDBConfig() + + if err := models.NewEngine(context.Background(), migrations.Migrate); err != nil { + log.Fatal("Failed to initialize ORM engine: %v", err) + return err + } + + goCtx := context.Background() + + if err := storage.Init(); err != nil { + return err + } + + var dstStorage storage.ObjectStorage + var err error + switch strings.ToLower(ctx.String("storage")) { + case "": + fallthrough + case string(storage.LocalStorageType): + p := ctx.String("path") + if p == "" { + log.Fatal("Path must be given when storage is loal") + return nil + } + dstStorage, err = storage.NewLocalStorage( + goCtx, + storage.LocalStorageConfig{ + Path: p, + }) + case string(storage.MinioStorageType): + dstStorage, err = storage.NewMinioStorage( + goCtx, + storage.MinioStorageConfig{ + Endpoint: ctx.String("minio-endpoint"), + AccessKeyID: ctx.String("minio-access-key-id"), + SecretAccessKey: ctx.String("minio-secret-access-key"), + Bucket: ctx.String("minio-bucket"), + Location: ctx.String("minio-location"), + BasePath: ctx.String("minio-base-path"), + UseSSL: ctx.Bool("minio-use-ssl"), + }) + default: + return fmt.Errorf("Unsupported storage type: %s", ctx.String("storage")) + } + if err != nil { + return err + } + + tp := strings.ToLower(ctx.String("type")) + switch tp { + case "attachments": + if err := migrateAttachments(dstStorage); err != nil { + return err + } + case "lfs": + if err := migrateLFS(dstStorage); err != nil { + return err + } + case "avatars": + if err := migrateAvatars(dstStorage); err != nil { + return err + } + case "repo-avatars": + if err := migrateRepoAvatars(dstStorage); err != nil { + return err + } + default: + return fmt.Errorf("Unsupported storage: %s", ctx.String("type")) + } + + log.Warn("All files have been copied to the new placement but old files are still on the orignial placement.") + + return nil +} diff --git a/cmd/restore_repo.go b/cmd/restore_repo.go new file mode 100644 index 0000000000000..541995879bf4c --- /dev/null +++ b/cmd/restore_repo.go @@ -0,0 +1,119 @@ +// Copyright 2020 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 cmd + +import ( + "context" + "strings" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/migrations" + "code.gitea.io/gitea/modules/migrations/base" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" + pull_service "code.gitea.io/gitea/services/pull" + + "github.com/urfave/cli" +) + +// CmdRestoreRepository represents the available restore a repository sub-command. +var CmdRestoreRepository = cli.Command{ + Name: "restore-repo", + Usage: "Restore the repository from disk", + Description: "This is a command for restoring the repository data.", + Action: runRestoreRepository, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "repo_dir, r", + Value: "./data", + Usage: "Repository dir path to restore from", + }, + cli.StringFlag{ + Name: "owner_name", + Value: "", + Usage: "Restore destination owner name", + }, + cli.StringFlag{ + Name: "repo_name", + Value: "", + Usage: "Restore destination repository name", + }, + cli.StringFlag{ + Name: "units", + Value: "", + Usage: `Which items will be restored, one or more units should be separated as comma. +wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`, + }, + }, +} + +func runRestoreRepository(ctx *cli.Context) error { + if err := initDB(); err != nil { + return err + } + + log.Trace("AppPath: %s", setting.AppPath) + log.Trace("AppWorkPath: %s", setting.AppWorkPath) + log.Trace("Custom path: %s", setting.CustomPath) + log.Trace("Log path: %s", setting.LogRootPath) + setting.InitDBConfig() + + if err := storage.Init(); err != nil { + return err + } + + if err := pull_service.Init(); err != nil { + return err + } + + var opts = base.MigrateOptions{ + RepoName: ctx.String("repo_name"), + } + + if len(ctx.String("units")) == 0 { + opts.Wiki = true + opts.Issues = true + opts.Milestones = true + opts.Labels = true + opts.Releases = true + opts.Comments = true + opts.PullRequests = true + opts.ReleaseAssets = true + } else { + units := strings.Split(ctx.String("units"), ",") + for _, unit := range units { + switch strings.ToLower(unit) { + case "wiki": + opts.Wiki = true + case "issues": + opts.Issues = true + case "milestones": + opts.Milestones = true + case "labels": + opts.Labels = true + case "releases": + opts.Releases = true + case "release_assets": + opts.ReleaseAssets = true + case "comments": + opts.Comments = true + case "pull_requests": + opts.PullRequests = true + } + } + } + + if err := migrations.RestoreRepository( + context.Background(), + ctx.String("repo_dir"), + ctx.String("owner_name"), + ctx.String("repo_name"), + ); err != nil { + log.Fatal("Failed to restore repository: %v", err) + return err + } + + return nil +} diff --git a/cmd/serv.go b/cmd/serv.go index 7c2be5157ad1f..1e66cb5111000 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -25,7 +25,7 @@ import ( "code.gitea.io/gitea/modules/setting" "github.com/dgrijalva/jwt-go" - "github.com/unknwon/com" + "github.com/kballard/go-shellquote" "github.com/urfave/cli" ) @@ -50,21 +50,16 @@ var CmdServ = cli.Command{ } func setup(logPath string, debug bool) { - if !debug { - _ = log.DelLogger("console") + _ = log.DelLogger("console") + if debug { + _ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`) + } else { + _ = log.NewLogger(1000, "console", "console", `{"level":"fatal","stacktracelevel":"NONE","stderr":true}`) } setting.NewContext() if debug { - setting.ProdMode = false - } -} - -func parseCmd(cmd string) (string, string) { - ss := strings.SplitN(cmd, " ", 2) - if len(ss) != 2 { - return "", "" + setting.RunMode = "dev" } - return ss[0], strings.Replace(ss[1], "'/", "'", 1) } var ( @@ -81,7 +76,7 @@ func fail(userMessage, logMessage string, args ...interface{}) { fmt.Fprintln(os.Stderr, "Gitea:", userMessage) if len(logMessage) > 0 { - if !setting.ProdMode { + if !setting.IsProd() { fmt.Fprintf(os.Stderr, logMessage+"\n", args...) } } @@ -109,7 +104,10 @@ func runServ(c *cli.Context) error { if len(keys) != 2 || keys[0] != "key" { fail("Key ID format error", "Invalid key argument: %s", c.Args()[0]) } - keyID := com.StrTo(keys[1]).MustInt64() + keyID, err := strconv.ParseInt(keys[1], 10, 64) + if err != nil { + fail("Key ID format error", "Invalid key argument: %s", c.Args()[1]) + } cmd := os.Getenv("SSH_ORIGINAL_COMMAND") if len(cmd) == 0 { @@ -117,16 +115,34 @@ func runServ(c *cli.Context) error { if err != nil { fail("Internal error", "Failed to check provided key: %v", err) } - if key.Type == models.KeyTypeDeploy { + switch key.Type { + case models.KeyTypeDeploy: println("Hi there! You've successfully authenticated with the deploy key named " + key.Name + ", but Gitea does not provide shell access.") - } else { + case models.KeyTypePrincipal: + println("Hi there! You've successfully authenticated with the principal " + key.Content + ", but Gitea does not provide shell access.") + default: println("Hi there, " + user.Name + "! You've successfully authenticated with the key named " + key.Name + ", but Gitea does not provide shell access.") } println("If this is unexpected, please log in with password and setup Gitea under another user.") return nil + } else if c.Bool("debug") { + log.Debug("SSH_ORIGINAL_COMMAND: %s", os.Getenv("SSH_ORIGINAL_COMMAND")) } - verb, args := parseCmd(cmd) + words, err := shellquote.Split(cmd) + if err != nil { + fail("Error parsing arguments", "Failed to parse arguments: %v", err) + } + + if len(words) < 2 { + fail("Too few arguments", "Too few arguments in cmd: %s", cmd) + } + + verb := words[0] + repoPath := words[1] + if repoPath[0] == '/' { + repoPath = repoPath[1:] + } var lfsVerb string if verb == lfsAuthenticateVerb { @@ -134,17 +150,17 @@ func runServ(c *cli.Context) error { fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled") } - argsSplit := strings.Split(args, " ") - if len(argsSplit) >= 2 { - args = strings.TrimSpace(argsSplit[0]) - lfsVerb = strings.TrimSpace(argsSplit[1]) + if len(words) > 2 { + lfsVerb = words[2] } } - repoPath := strings.ToLower(strings.Trim(args, "'")) + // LowerCase and trim the repoPath as that's how they are stored. + repoPath = strings.ToLower(strings.TrimSpace(repoPath)) + rr := strings.SplitN(repoPath, "/", 2) if len(rr) != 2 { - fail("Invalid repository path", "Invalid repository path: %v", args) + fail("Invalid repository path", "Invalid repository path: %v", repoPath) } username := strings.ToLower(rr[0]) @@ -203,11 +219,13 @@ func runServ(c *cli.Context) error { os.Setenv(models.EnvRepoName, results.RepoName) os.Setenv(models.EnvRepoUsername, results.OwnerName) os.Setenv(models.EnvPusherName, results.UserName) + os.Setenv(models.EnvPusherEmail, results.UserEmail) os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10)) - os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10)) - os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0)) + os.Setenv(models.EnvRepoID, strconv.FormatInt(results.RepoID, 10)) + os.Setenv(models.EnvPRID, fmt.Sprintf("%d", 0)) os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey)) os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID)) + os.Setenv(models.EnvAppURL, setting.AppURL) //LFS token authentication if verb == lfsAuthenticateVerb { diff --git a/cmd/web.go b/cmd/web.go index 243b9a4108a1d..063e41c94647b 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -7,6 +7,7 @@ package cmd import ( "context" "fmt" + "net" "net/http" _ "net/http/pprof" // Used for debugging if enabled and a web server is running "os" @@ -15,11 +16,11 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers/routes" context2 "github.com/gorilla/context" - "github.com/unknwon/com" "github.com/urfave/cli" "golang.org/x/crypto/acme/autocert" ini "gopkg.in/ini.v1" @@ -38,9 +39,14 @@ and it takes care of all the other things for you`, Value: "3000", Usage: "Temporary port number to prevent conflict", }, + cli.StringFlag{ + Name: "install-port", + Value: "3000", + Usage: "Temporary port number to run the install page on to prevent conflict", + }, cli.StringFlag{ Name: "pid, P", - Value: "/var/run/gitea.pid", + Value: setting.PIDFile, Usage: "Custom pid file path", }, }, @@ -92,7 +98,7 @@ func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) { // Remove the trailing slash at the end of setting.AppURL, the request // URI always contains a leading slash, which would result in a double // slash - target := strings.TrimRight(setting.AppURL, "/") + r.URL.RequestURI() + target := strings.TrimSuffix(setting.AppURL, "/") + r.URL.RequestURI() http.Redirect(w, r, target, http.StatusFound) } @@ -109,54 +115,110 @@ func runWeb(ctx *cli.Context) error { // Set pid file setting if ctx.IsSet("pid") { - setting.CustomPID = ctx.String("pid") + setting.PIDFile = ctx.String("pid") + setting.WritePIDFile = true } + // Perform pre-initialization + needsInstall := routers.PreInstallInit(graceful.GetManager().HammerContext()) + if needsInstall { + // Flag for port number in case first time run conflict + if ctx.IsSet("port") { + if err := setPort(ctx.String("port")); err != nil { + return err + } + } + if ctx.IsSet("install-port") { + if err := setPort(ctx.String("install-port")); err != nil { + return err + } + } + c := routes.NewChi() + routes.RegisterInstallRoute(c) + err := listen(c, false) + select { + case <-graceful.GetManager().IsShutdown(): + <-graceful.GetManager().Done() + log.Info("PID: %d Gitea Web Finished", os.Getpid()) + log.Close() + return err + default: + } + } else { + NoInstallListener() + } + + if setting.EnablePprof { + go func() { + log.Info("Starting pprof server on localhost:6060") + log.Info("%v", http.ListenAndServe("localhost:6060", nil)) + }() + } + + log.Info("Global init") // Perform global initialization routers.GlobalInit(graceful.GetManager().HammerContext()) - // Set up Macaron - m := routes.NewMacaron() - routes.RegisterRoutes(m) - - // Flag for port number in case first time run conflict. + // Override the provided port number within the configuration if ctx.IsSet("port") { - setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, ctx.String("port"), 1) - setting.HTTPPort = ctx.String("port") + if err := setPort(ctx.String("port")); err != nil { + return err + } + } + // Set up Chi routes + c := routes.NewChi() + c.Mount("/", routes.NormalRoutes()) + routes.DelegateToMacaron(c) - switch setting.Protocol { - case setting.UnixSocket: - case setting.FCGI: - case setting.FCGIUnix: - default: - // Save LOCAL_ROOT_URL if port changed - cfg := ini.Empty() - if com.IsFile(setting.CustomConf) { - // Keeps custom settings if there is already something. - if err := cfg.Append(setting.CustomConf); err != nil { - return fmt.Errorf("Failed to load custom conf '%s': %v", setting.CustomConf, err) - } - } + err := listen(c, true) + <-graceful.GetManager().Done() + log.Info("PID: %d Gitea Web Finished", os.Getpid()) + log.Close() + return err +} - defaultLocalURL := string(setting.Protocol) + "://" - if setting.HTTPAddr == "0.0.0.0" { - defaultLocalURL += "localhost" - } else { - defaultLocalURL += setting.HTTPAddr +func setPort(port string) error { + setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, port, 1) + setting.HTTPPort = port + + switch setting.Protocol { + case setting.UnixSocket: + case setting.FCGI: + case setting.FCGIUnix: + default: + // Save LOCAL_ROOT_URL if port changed + cfg := ini.Empty() + isFile, err := util.IsFile(setting.CustomConf) + if err != nil { + log.Fatal("Unable to check if %s is a file", err) + } + if isFile { + // Keeps custom settings if there is already something. + if err := cfg.Append(setting.CustomConf); err != nil { + return fmt.Errorf("Failed to load custom conf '%s': %v", setting.CustomConf, err) } - defaultLocalURL += ":" + setting.HTTPPort + "/" + } - cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL) + defaultLocalURL := string(setting.Protocol) + "://" + if setting.HTTPAddr == "0.0.0.0" { + defaultLocalURL += "localhost" + } else { + defaultLocalURL += setting.HTTPAddr + } + defaultLocalURL += ":" + setting.HTTPPort + "/" - if err := cfg.SaveTo(setting.CustomConf); err != nil { - return fmt.Errorf("Error saving generated JWT Secret to custom config: %v", err) - } + cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL) + if err := cfg.SaveTo(setting.CustomConf); err != nil { + return fmt.Errorf("Error saving generated JWT Secret to custom config: %v", err) } } + return nil +} +func listen(m http.Handler, handleRedirector bool) error { listenAddr := setting.HTTPAddr if setting.Protocol != setting.UnixSocket && setting.Protocol != setting.FCGIUnix { - listenAddr += ":" + setting.HTTPPort + listenAddr = net.JoinHostPort(listenAddr, setting.HTTPPort) } log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL) @@ -164,37 +226,40 @@ func runWeb(ctx *cli.Context) error { log.Info("LFS server enabled") } - if setting.EnablePprof { - go func() { - log.Info("Starting pprof server on localhost:6060") - log.Info("%v", http.ListenAndServe("localhost:6060", nil)) - }() - } - var err error switch setting.Protocol { case setting.HTTP: - NoHTTPRedirector() + if handleRedirector { + NoHTTPRedirector() + } err = runHTTP("tcp", listenAddr, context2.ClearHandler(m)) case setting.HTTPS: if setting.EnableLetsEncrypt { err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, context2.ClearHandler(m)) break } - if setting.RedirectOtherPort { - go runHTTPRedirector() - } else { - NoHTTPRedirector() + if handleRedirector { + if setting.RedirectOtherPort { + go runHTTPRedirector() + } else { + NoHTTPRedirector() + } } err = runHTTPS("tcp", listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m)) case setting.FCGI: - NoHTTPRedirector() + if handleRedirector { + NoHTTPRedirector() + } err = runFCGI("tcp", listenAddr, context2.ClearHandler(m)) case setting.UnixSocket: - NoHTTPRedirector() + if handleRedirector { + NoHTTPRedirector() + } err = runHTTP("unix", listenAddr, context2.ClearHandler(m)) case setting.FCGIUnix: - NoHTTPRedirector() + if handleRedirector { + NoHTTPRedirector() + } err = runFCGI("unix", listenAddr, context2.ClearHandler(m)) default: log.Fatal("Invalid protocol: %s", setting.Protocol) @@ -204,8 +269,5 @@ func runWeb(ctx *cli.Context) error { log.Critical("Failed to start server: %v", err) } log.Info("HTTP Listener: %s Closed", listenAddr) - <-graceful.GetManager().Done() - log.Info("PID: %d Gitea Web Finished", os.Getpid()) - log.Close() - return nil + return err } diff --git a/cmd/web_graceful.go b/cmd/web_graceful.go index f3c41766af490..9e039de699962 100644 --- a/cmd/web_graceful.go +++ b/cmd/web_graceful.go @@ -37,6 +37,12 @@ func NoMainListener() { graceful.GetManager().InformCleanup() } +// NoInstallListener tells our cleanup routine that we will not be using a possibly provided listener +// for our install HTTP/HTTPS service +func NoInstallListener() { + graceful.GetManager().InformCleanup() +} + func runFCGI(network, listenAddr string, m http.Handler) error { // This needs to handle stdin as fcgi point fcgiServer := graceful.NewServer(network, listenAddr) diff --git a/contrib/environment-to-ini/environment-to-ini.go b/contrib/environment-to-ini/environment-to-ini.go index e9dc383cb4c27..bfba2c3140908 100644 --- a/contrib/environment-to-ini/environment-to-ini.go +++ b/contrib/environment-to-ini/environment-to-ini.go @@ -12,8 +12,8 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" - "github.com/unknwon/com" "github.com/urfave/cli" ini "gopkg.in/ini.v1" ) @@ -97,7 +97,11 @@ func runEnvironmentToIni(c *cli.Context) error { setting.SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath) cfg := ini.Empty() - if com.IsFile(setting.CustomConf) { + isFile, err := util.IsFile(setting.CustomConf) + if err != nil { + log.Fatal("Unable to check if %s is a file. Error: %v", setting.CustomConf, err) + } + if isFile { if err := cfg.Append(setting.CustomConf); err != nil { log.Fatal("Failed to load custom conf '%s': %v", setting.CustomConf, err) } @@ -145,7 +149,7 @@ func runEnvironmentToIni(c *cli.Context) error { if len(destination) == 0 { destination = setting.CustomConf } - err := cfg.SaveTo(destination) + err = cfg.SaveTo(destination) if err != nil { return err } diff --git a/contrib/ide/vscode/launch.json b/contrib/ide/vscode/launch.json index 6e90aa0eaa5a5..10df14ef3788a 100644 --- a/contrib/ide/vscode/launch.json +++ b/contrib/ide/vscode/launch.json @@ -19,7 +19,7 @@ "type": "go", "request": "launch", "mode": "debug", - "buildFlags": "-tags=\"sqlite sqlite_unlock_notify\"", + "buildFlags": "-tags='sqlite sqlite_unlock_notify'", "port": 2345, "host": "127.0.0.1", "program": "${workspaceRoot}/main.go", diff --git a/contrib/ide/vscode/settings.json b/contrib/ide/vscode/settings.json new file mode 100644 index 0000000000000..e33bccf9028e9 --- /dev/null +++ b/contrib/ide/vscode/settings.json @@ -0,0 +1,4 @@ +{ + "go.buildTags": "'sqlite sqlite_unlock_notify'", + "go.testFlags": ["-v"] +} \ No newline at end of file diff --git a/contrib/ide/vscode/tasks.json b/contrib/ide/vscode/tasks.json index a9876f71013e9..e35ae303b27b0 100644 --- a/contrib/ide/vscode/tasks.json +++ b/contrib/ide/vscode/tasks.json @@ -12,15 +12,14 @@ "focus": false, "panel": "shared" }, - "args": ["build"], "linux": { - "args": [ "-o", "gitea", "${workspaceRoot}/main.go" ] + "args": ["build", "-o", "gitea", "${workspaceRoot}/main.go" ] }, "osx": { - "args": [ "-o", "gitea", "${workspaceRoot}/main.go" ] + "args": ["build", "-o", "gitea", "${workspaceRoot}/main.go" ] }, "windows": { - "args": [ "-o", "gitea.exe", "\"${workspaceRoot}\\main.go\""] + "args": ["build", "-o", "gitea.exe", "\"${workspaceRoot}\\main.go\""] }, "problemMatcher": ["$go"] }, @@ -35,15 +34,14 @@ "focus": false, "panel": "shared" }, - "args": ["build", "-tags=\"sqlite sqlite_unlock_notify\""], "linux": { - "args": ["-o", "gitea", "${workspaceRoot}/main.go"] + "args": ["build", "-tags=\"sqlite sqlite_unlock_notify\"", "-o", "gitea", "${workspaceRoot}/main.go"] }, "osx": { - "args": ["-o", "gitea", "${workspaceRoot}/main.go"] + "args": ["build", "-tags=\"sqlite sqlite_unlock_notify\"", "-o", "gitea", "${workspaceRoot}/main.go"] }, "windows": { - "args": ["-o", "gitea.exe", "\"${workspaceRoot}\\main.go\""] + "args": ["build", "-tags=\"sqlite sqlite_unlock_notify\"", "-o", "gitea.exe", "\"${workspaceRoot}\\main.go\""] }, "problemMatcher": ["$go"] } diff --git a/contrib/init/debian/gitea b/contrib/init/debian/gitea index b7911f106eac8..2246309440721 100644 --- a/contrib/init/debian/gitea +++ b/contrib/init/debian/gitea @@ -18,7 +18,7 @@ PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin DESC="Gitea - Git with a cup of tea" NAME=gitea SERVICEVERBOSE=yes -PIDFILE=/var/run/$NAME.pid +PIDFILE=/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME WORKINGDIR=/var/lib/$NAME DAEMON=/usr/local/bin/$NAME diff --git a/contrib/init/gentoo/gitea b/contrib/init/gentoo/gitea index c40fc93f5f6ad..e423eae54ddc6 100644 --- a/contrib/init/gentoo/gitea +++ b/contrib/init/gentoo/gitea @@ -7,7 +7,7 @@ start_stop_daemon_args="--user ${USER} --chdir ${DIR}" command="/usr/local/bin/gitea" command_args="web -c /etc/gitea/app.ini" command_background=yes -pidfile=/var/run/gitea.pid +pidfile=/run/gitea.pid depend() { diff --git a/contrib/init/suse/gitea b/contrib/init/suse/gitea index 23178583ffe99..6391bedaf8370 100644 --- a/contrib/init/suse/gitea +++ b/contrib/init/suse/gitea @@ -93,7 +93,7 @@ case "$1" in # Return value is slightly different for the status command: # 0 - service up and running - # 1 - service dead, but /var/run/ pid file exists + # 1 - service dead, but /run/ pid file exists # 2 - service dead, but /var/lock/ lock file exists # 3 - service not running (unused) # 4 - service status unknown :-( diff --git a/contrib/k8s/gitea.yml b/contrib/k8s/gitea.yml deleted file mode 100644 index c4aed869f7fe7..0000000000000 --- a/contrib/k8s/gitea.yml +++ /dev/null @@ -1,107 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: gitea ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: gitea - namespace: gitea - labels: - app: gitea -spec: - replicas: 1 - template: - metadata: - name: gitea - labels: - app: gitea - spec: - containers: - - name: gitea - image: gitea/gitea:latest - imagePullPolicy: Always - volumeMounts: - - mountPath: "/var/lib/gitea" - name: "root" - - mountPath: "/data" - name: "data" - ports: - - containerPort: 22 - name: ssh - protocol: TCP - - containerPort: 3000 - name: http - protocol: TCP - restartPolicy: Always - volumes: - # Set up a data directory for gitea - # For production usage, you should consider using PV/PVC instead(or simply using storage like NAS) - # For more details, please see https://kubernetes.io/docs/concepts/storage/volumes/ - - name: "root" - hostPath: - # directory location on host - path: "/var/lib/gitea" - # this field is optional - type: Directory - - name: "data" - hostPath: - path: "/data/gitea" - type: Directory - selector: - matchLabels: - app: gitea ---- -# Using cluster mode -apiVersion: v1 -kind: Service -metadata: - name: gitea-web - namespace: gitea - labels: - app: gitea-web -spec: - ports: - - port: 80 - targetPort: 3000 - name: http - selector: - app: gitea ---- -# Using node-port mode -# This mainly open a specific TCP port for SSH usage on each host, -# so you can use a proxy layer to handle it(e.g. slb, nginx) -apiVersion: v1 -kind: Service -metadata: - name: gitea-ssh - namespace: gitea - labels: - app: gitea-ssh -spec: - ports: - - port: 22 - targetPort: 22 - nodePort: 30022 - name: ssh - selector: - app: gitea - type: NodePort ---- -# Ingress is always suitable for HTTP usage, -# we suggest using an proxy layer such as slb to send traffic to different ports. -# Usually 80/443 for web and 22 directly for SSH. -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: gitea - namespace: gitea -spec: - rules: - - host: your-gitea-host.com - http: - paths: - - backend: - serviceName: gitea-web - servicePort: 80 diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index 5085f0a67a67b..9346577bd6970 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -29,6 +29,7 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/external" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers/routes" @@ -36,8 +37,6 @@ import ( "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing" context2 "github.com/gorilla/context" - "github.com/unknwon/com" - "gopkg.in/testfixtures.v2" "xorm.io/xorm" ) @@ -96,14 +95,12 @@ func runPR() { setting.Database.LogSQL = true //x, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared") - var helper testfixtures.Helper = &testfixtures.SQLite{} models.NewEngine(context.Background(), func(_ *xorm.Engine) error { return nil }) models.HasEngine = true //x.ShowSQL(true) err = models.InitFixtures( - helper, path.Join(curDir, "models/fixtures/"), ) if err != nil { @@ -111,16 +108,17 @@ func runPR() { os.Exit(1) } models.LoadFixtures() - os.RemoveAll(setting.RepoRootPath) - os.RemoveAll(models.LocalCopyPath()) - com.CopyDir(path.Join(curDir, "integrations/gitea-repositories-meta"), setting.RepoRootPath) + util.RemoveAll(setting.RepoRootPath) + util.RemoveAll(models.LocalCopyPath()) + util.CopyDir(path.Join(curDir, "integrations/gitea-repositories-meta"), setting.RepoRootPath) log.Printf("[PR] Setting up router\n") //routers.GlobalInit() external.RegisterParsers() markup.Init() - m := routes.NewMacaron() - routes.RegisterRoutes(m) + c := routes.NewChi() + c.Mount("/", routes.NormalRoutes()) + routes.DelegateToMacaron(c) log.Printf("[PR] Ready for testing !\n") log.Printf("[PR] Login with user1, user2, user3, ... with pass: password\n") @@ -140,24 +138,24 @@ func runPR() { */ //Start the server - http.ListenAndServe(":8080", context2.ClearHandler(m)) + http.ListenAndServe(":8080", context2.ClearHandler(c)) log.Printf("[PR] Cleaning up ...\n") /* - if err = os.RemoveAll(setting.Indexer.IssuePath); err != nil { - fmt.Printf("os.RemoveAll: %v\n", err) + if err = util.RemoveAll(setting.Indexer.IssuePath); err != nil { + fmt.Printf("util.RemoveAll: %v\n", err) os.Exit(1) } - if err = os.RemoveAll(setting.Indexer.RepoPath); err != nil { + if err = util.RemoveAll(setting.Indexer.RepoPath); err != nil { fmt.Printf("Unable to remove repo indexer: %v\n", err) os.Exit(1) } */ - if err = os.RemoveAll(setting.RepoRootPath); err != nil { - log.Fatalf("os.RemoveAll: %v\n", err) + if err = util.RemoveAll(setting.RepoRootPath); err != nil { + log.Fatalf("util.RemoveAll: %v\n", err) } - if err = os.RemoveAll(setting.AppDataPath); err != nil { - log.Fatalf("os.RemoveAll: %v\n", err) + if err = util.RemoveAll(setting.AppDataPath); err != nil { + log.Fatalf("util.RemoveAll: %v\n", err) } } @@ -201,7 +199,9 @@ func main() { } remoteUpstream := "origin" //Default for _, r := range remotes { - if r.Config().URLs[0] == "https://github.com/go-gitea/gitea" || r.Config().URLs[0] == "git@github.com:go-gitea/gitea.git" { //fetch at index 0 + if r.Config().URLs[0] == "https://github.com/go-gitea/gitea.git" || + r.Config().URLs[0] == "https://github.com/go-gitea/gitea" || + r.Config().URLs[0] == "git@github.com:go-gitea/gitea.git" { //fetch at index 0 remoteUpstream = r.Config().Name break } diff --git a/contrib/systemd/gitea.service b/contrib/systemd/gitea.service index 73e838c23bfc8..ac6a13ec573e7 100644 --- a/contrib/systemd/gitea.service +++ b/contrib/systemd/gitea.service @@ -57,6 +57,12 @@ WorkingDirectory=/var/lib/gitea/ ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini Restart=always Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea +# If you install Git to directory prefix other than default PATH (which happens +# for example if you install other versions of Git side-to-side with +# distribution version), uncomment below line and add that prefix to PATH +# Don't forget to place git-lfs binary on the PATH below if you want to enable +# Git LFS support +#Environment=PATH=/path/to/git/bin:/bin:/sbin:/usr/bin:/usr/sbin # If you want to bind Gitea to a port below 1024, uncomment # the two values below, or use socket activation to pass Gitea its ports as above ### diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini new file mode 100644 index 0000000000000..f2b65a0963db6 --- /dev/null +++ b/custom/conf/app.example.ini @@ -0,0 +1,1245 @@ +; This file lists the default values used by Gitea +; Copy required sections to your own app.ini (default is custom/conf/app.ini) +; and modify as needed. +; Do not copy the whole file as-is, as it contains some invalid sections for illustrative purposes. +; If you don't know what a setting is you should not set it. + +; see https://docs.gitea.io/en-us/config-cheat-sheet/ for additional documentation. + +; App name that shows in every page title +APP_NAME = Gitea: Git with a cup of tea +; Change it if you run locally +RUN_USER = git +; Application run mode, affects performance and debugging. Either "dev", "prod" or "test", default is "prod" +RUN_MODE = prod + +[project] +; Default templates for project boards +PROJECT_BOARD_BASIC_KANBAN_TYPE = To Do, In Progress, Done +PROJECT_BOARD_BUG_TRIAGE_TYPE = Needs Triage, High Priority, Low Priority, Closed + +[repository] +; Root path for storing all repository data. It must be an absolute path. By default it is stored in a sub-directory of `APP_DATA_PATH`. +ROOT = +; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. +SCRIPT_TYPE = bash +; DETECTED_CHARSETS_ORDER tie-break order for detected charsets. +; If the charsets have equal confidence, tie-breaking will be done by order in this list +; with charsets earlier in the list chosen in preference to those later. +; Adding "defaults" will place the unused charsets at that position. +DETECTED_CHARSETS_ORDER = UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE, ISO-8859, windows-1252, ISO-8859, windows-1250, ISO-8859, ISO-8859, ISO-8859, windows-1253, ISO-8859, windows-1255, ISO-8859, windows-1251, windows-1256, KOI8-R, ISO-8859, windows-1254, Shift_JIS, GB18030, EUC-JP, EUC-KR, Big5, ISO-2022, ISO-2022, ISO-2022, IBM424_rtl, IBM424_ltr, IBM420_rtl, IBM420_ltr +; Default ANSI charset to override non-UTF-8 charsets to +ANSI_CHARSET = +; Force every new repository to be private +FORCE_PRIVATE = false +; Default privacy setting when creating a new repository, allowed values: last, private, public. Default is last which means the last setting used. +DEFAULT_PRIVATE = last +; Default private when using push-to-create +DEFAULT_PUSH_CREATE_PRIVATE = true +; Global limit of repositories per user, applied at creation time. -1 means no limit +MAX_CREATION_LIMIT = -1 +; Mirror sync queue length, increase if mirror syncing starts hanging +MIRROR_QUEUE_LENGTH = 1000 +; Patch test queue length, increase if pull request patch testing starts hanging +PULL_REQUEST_QUEUE_LENGTH = 1000 +; Preferred Licenses to place at the top of the List +; The name here must match the filename in conf/license or custom/conf/license +PREFERRED_LICENSES = Apache License 2.0,MIT License +; Disable the ability to interact with repositories using the HTTP protocol +DISABLE_HTTP_GIT = false +; Value for Access-Control-Allow-Origin header, default is not to present +; WARNING: This maybe harmful to you website if you do not give it a right value. +ACCESS_CONTROL_ALLOW_ORIGIN = +; Force ssh:// clone url instead of scp-style uri when default SSH port is used +USE_COMPAT_SSH_URI = false +; Close issues as long as a commit on any branch marks it as fixed +DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH = false +; Allow users to push local repositories to Gitea and have them automatically created for a user or an org +ENABLE_PUSH_CREATE_USER = false +ENABLE_PUSH_CREATE_ORG = false +; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki +DISABLED_REPO_UNITS = +; Comma separated list of default repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects. +; Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility. +; External wiki and issue tracker can't be enabled by default as it requires additional settings. +; Disabled repo units will not be added to new repositories regardless if it is in the default list. +DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects +; Prefix archive files by placing them in a directory named after the repository +PREFIX_ARCHIVE_FILES = true +; Disable the creation of new mirrors. Pre-existing mirrors remain valid. +DISABLE_MIRRORS = false +; Disable migrating feature. +DISABLE_MIGRATIONS = false +; The default branch name of new repositories +DEFAULT_BRANCH = master +; Allow adoption of unadopted repositories +ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES = false +; Allow deletion of unadopted repositories +ALLOW_DELETION_OF_UNADOPTED_REPOSITORIES = false + +[repository.editor] +; List of file extensions for which lines should be wrapped in the Monaco editor +; Separate extensions with a comma. To line wrap files without an extension, just put a comma +LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd, +; Valid file modes that have a preview API associated with them, such as api/v1/markdown +; Separate the values by commas. The preview tab in edit mode won't be displayed if the file extension doesn't match +PREVIEWABLE_FILE_MODES = markdown + +[repository.local] +; Path for local repository copy. Defaults to `tmp/local-repo` +LOCAL_COPY_PATH = tmp/local-repo + +[repository.upload] +; Whether repository file uploads are enabled. Defaults to `true` +ENABLED = true +; Path for uploads. Defaults to `data/tmp/uploads` (tmp gets deleted on gitea restart) +TEMP_PATH = data/tmp/uploads +; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. +ALLOWED_TYPES = +; Max size of each file in megabytes. Defaults to 3MB +FILE_MAX_SIZE = 3 +; Max number of files per upload. Defaults to 5 +MAX_FILES = 5 + +[repository.pull-request] +; List of prefixes used in Pull Request title to mark them as Work In Progress +WORK_IN_PROGRESS_PREFIXES = WIP:,[WIP] +; List of keywords used in Pull Request comments to automatically close a related issue +CLOSE_KEYWORDS = close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved +; List of keywords used in Pull Request comments to automatically reopen a related issue +REOPEN_KEYWORDS = reopen,reopens,reopened +; In the default merge message for squash commits include at most this many commits +DEFAULT_MERGE_MESSAGE_COMMITS_LIMIT = 50 +; In the default merge message for squash commits limit the size of the commit messages to this +DEFAULT_MERGE_MESSAGE_SIZE = 5120 +; In the default merge message for squash commits walk all commits to include all authors in the Co-authored-by otherwise just use those in the limited list +DEFAULT_MERGE_MESSAGE_ALL_AUTHORS = false +; In default merge messages limit the number of approvers listed as Reviewed-by: to this many +DEFAULT_MERGE_MESSAGE_MAX_APPROVERS = 10 +; In default merge messages only include approvers who are official +DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY = true + +[repository.issue] +; List of reasons why a Pull Request or Issue can be locked +LOCK_REASONS = Too heated,Off-topic,Resolved,Spam + +[repository.release] +; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. +ALLOWED_TYPES = + +[repository.signing] +; GPG key to use to sign commits, Defaults to the default - that is the value of git config --get user.signingkey +; run in the context of the RUN_USER +; Switch to none to stop signing completely +SIGNING_KEY = default +; If a SIGNING_KEY ID is provided and is not set to default, use the provided Name and Email address as the signer. +; These should match a publicized name and email address for the key. (When SIGNING_KEY is default these are set to +; the results of git config --get user.name and git config --get user.email respectively and can only be overrided +; by setting the SIGNING_KEY ID to the correct ID.) +SIGNING_NAME = +SIGNING_EMAIL = +; Sets the default trust model for repositories. Options are: collaborator, committer, collaboratorcommitter +DEFAULT_TRUST_MODEL = collaborator +; Determines when gitea should sign the initial commit when creating a repository +; Either: +; - never +; - pubkey: only sign if the user has a pubkey +; - twofa: only sign if the user has logged in with twofa +; - always +; options other than none and always can be combined as comma separated list +INITIAL_COMMIT = always +; Determines when to sign for CRUD actions +; - as above +; - parentsigned: requires that the parent commit is signed. +CRUD_ACTIONS = pubkey, twofa, parentsigned +; Determines when to sign Wiki commits +; - as above +WIKI = never +; Determines when to sign on merges +; - basesigned: require that the parent of commit on the base repo is signed. +; - commitssigned: require that all the commits in the head branch are signed. +; - approved: only sign when merging an approved pr to a protected branch +MERGES = pubkey, twofa, basesigned, commitssigned + +[cors] +; More information about CORS can be found here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers +; enable cors headers (disabled by default) +ENABLED = false +; scheme of allowed requests +SCHEME = http +; list of requesting domains that are allowed +ALLOW_DOMAIN = * +; allow subdomains of headers listed above to request +ALLOW_SUBDOMAIN = false +; list of methods allowed to request +METHODS = GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS +; max time to cache response +MAX_AGE = 10m +; allow request with credentials +ALLOW_CREDENTIALS = false + +[ui] +; Number of repositories that are displayed on one explore page +EXPLORE_PAGING_NUM = 20 +; Number of issues that are displayed on one page +ISSUE_PAGING_NUM = 10 +; Number of maximum commits displayed in one activity feed +FEED_MAX_COMMIT_NUM = 5 +; Number of items that are displayed in home feed +FEED_PAGING_NUM = 20 +; Number of maximum commits displayed in commit graph. +GRAPH_MAX_COMMIT_NUM = 100 +; Number of line of codes shown for a code comment +CODE_COMMENT_LINES = 4 +; Value of `theme-color` meta tag, used by Android >= 5.0 +; An invalid color like "none" or "disable" will have the default style +; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android +THEME_COLOR_META_TAG = `#6cc644` +; Max size of files to be displayed (default is 8MiB) +MAX_DISPLAY_FILE_SIZE = 8388608 +; Whether the email of the user should be shown in the Explore Users page +SHOW_USER_EMAIL = true +; Set the default theme for the Gitea install +DEFAULT_THEME = gitea +; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`. +THEMES = gitea,arc-green +;All available reactions users can choose on issues/prs and comments. +;Values can be emoji alias (:smile:) or a unicode emoji. +;For custom reactions, add a tightly cropped square image to public/emoji/img/reaction_name.png +REACTIONS = +1, -1, laugh, hooray, confused, heart, rocket, eyes +; Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used. +DEFAULT_SHOW_FULL_NAME = false +; Whether to search within description at repository search on explore page. +SEARCH_REPO_DESCRIPTION = true +; Whether to enable a Service Worker to cache frontend assets +USE_SERVICE_WORKER = true + +[ui.admin] +; Number of users that are displayed on one page +USER_PAGING_NUM = 50 +; Number of repos that are displayed on one page +REPO_PAGING_NUM = 50 +; Number of notices that are displayed on one page +NOTICE_PAGING_NUM = 25 +; Number of organizations that are displayed on one page +ORG_PAGING_NUM = 50 + +[ui.user] +; Number of repos that are displayed on one page +REPO_PAGING_NUM = 15 + +[ui.meta] +AUTHOR = Gitea - Git with a cup of tea +DESCRIPTION = Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go +KEYWORDS = go,git,self-hosted,gitea + +[ui.notification] +; Control how often the notification endpoint is polled to update the notification +; The timeout will increase to MAX_TIMEOUT in TIMEOUT_STEPs if the notification count is unchanged +; Set MIN_TIMEOUT to 0 to turn off +MIN_TIMEOUT = 10s +MAX_TIMEOUT = 60s +TIMEOUT_STEP = 10s +; This setting determines how often the db is queried to get the latest notification counts. +; If the browser client supports EventSource and SharedWorker, a SharedWorker will be used in preference to polling notification. Set to -1 to disable the EventSource +EVENT_SOURCE_UPDATE_TIME = 10s + +[ui.svg] +; Whether to render SVG files as images. If SVG rendering is disabled, SVG files are displayed as text and cannot be embedded in markdown files as images. +ENABLE_RENDER = true + +[markdown] +; Render soft line breaks as hard line breaks, which means a single newline character between +; paragraphs will cause a line break and adding trailing whitespace to paragraphs is not +; necessary to force a line break. +; Render soft line breaks as hard line breaks for comments +ENABLE_HARD_LINE_BREAK_IN_COMMENTS = true +; Render soft line breaks as hard line breaks for markdown documents +ENABLE_HARD_LINE_BREAK_IN_DOCUMENTS = false +; Comma separated list of custom URL-Schemes that are allowed as links when rendering Markdown +; for example git,magnet,ftp (more at https://en.wikipedia.org/wiki/List_of_URI_schemes) +; URLs starting with http and https are always displayed, whatever is put in this entry. +CUSTOM_URL_SCHEMES = +; List of file extensions that should be rendered/edited as Markdown +; Separate the extensions with a comma. To render files without any extension as markdown, just put a comma +FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd + +[server] +; The protocol the server listens on. One of 'http', 'https', 'unix' or 'fcgi'. +PROTOCOL = http +DOMAIN = localhost +ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/ +; when STATIC_URL_PREFIX is empty it will follow ROOT_URL +STATIC_URL_PREFIX = +; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket. +HTTP_ADDR = 0.0.0.0 +; The port to listen on. Leave empty when using a unix socket. +HTTP_PORT = 3000 +; If REDIRECT_OTHER_PORT is true, and PROTOCOL is set to https an http server +; will be started on PORT_TO_REDIRECT and it will redirect plain, non-secure http requests to the main +; ROOT_URL. Defaults are false for REDIRECT_OTHER_PORT and 80 for +; PORT_TO_REDIRECT. +REDIRECT_OTHER_PORT = false +PORT_TO_REDIRECT = 80 +; Permission for unix socket +UNIX_SOCKET_PERMISSION = 666 +; Local (DMZ) URL for Gitea workers (such as SSH update) accessing web service. +; In most cases you do not need to change the default value. +; Alter it only if your SSH server node is not the same as HTTP node. +; Do not set this variable if PROTOCOL is set to 'unix'. +LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/ +; Disable SSH feature when not available +DISABLE_SSH = false +; Whether to use the builtin SSH server or not. +START_SSH_SERVER = false +; Username to use for the builtin SSH server. If blank, then it is the value of RUN_USER. +BUILTIN_SSH_SERVER_USER = +; Domain name to be exposed in clone URL +SSH_DOMAIN = %(DOMAIN)s +; The network interface the builtin SSH server should listen on +SSH_LISTEN_HOST = +; Port number to be exposed in clone URL +SSH_PORT = 22 +; The port number the builtin SSH server should listen on +SSH_LISTEN_PORT = %(SSH_PORT)s +; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. +SSH_ROOT_PATH = +; Gitea will create a authorized_keys file by default when it is not using the internal ssh server +; If you intend to use the AuthorizedKeysCommand functionality then you should turn this off. +SSH_CREATE_AUTHORIZED_KEYS_FILE = true +; Gitea will create a authorized_principals file by default when it is not using the internal ssh server +; If you intend to use the AuthorizedPrincipalsCommand functionality then you should turn this off. +SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE = true +; For the built-in SSH server, choose the ciphers to support for SSH connections, +; for system SSH this setting has no effect +SSH_SERVER_CIPHERS = aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128 +; For the built-in SSH server, choose the key exchange algorithms to support for SSH connections, +; for system SSH this setting has no effect +SSH_SERVER_KEY_EXCHANGES = diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, curve25519-sha256@libssh.org +; For the built-in SSH server, choose the MACs to support for SSH connections, +; for system SSH this setting has no effect +SSH_SERVER_MACS = hmac-sha2-256-etm@openssh.com, hmac-sha2-256, hmac-sha1, hmac-sha1-96 +; Directory to create temporary files in when testing public keys using ssh-keygen, +; default is the system temporary directory. +SSH_KEY_TEST_PATH = +; Path to ssh-keygen, default is 'ssh-keygen' which means the shell is responsible for finding out which one to call. +SSH_KEYGEN_PATH = ssh-keygen +; Enable SSH Authorized Key Backup when rewriting all keys, default is true +SSH_AUTHORIZED_KEYS_BACKUP = true +; Determines which principals to allow +; - empty: if SSH_TRUSTED_USER_CA_KEYS is empty this will default to off, otherwise will default to email, username. +; - off: Do not allow authorized principals +; - email: the principal must match the user's email +; - username: the principal must match the user's username +; - anything: there will be no checking on the content of the principal +SSH_AUTHORIZED_PRINCIPALS_ALLOW = email, username +; Enable SSH Authorized Principals Backup when rewriting all keys, default is true +SSH_AUTHORIZED_PRINCIPALS_BACKUP = true +; Specifies the public keys of certificate authorities that are trusted to sign user certificates for authentication. +; Multiple keys should be comma separated. +; E.g."ssh- ". or "ssh- , ssh- ". +; For more information see "TrustedUserCAKeys" in the sshd config manpages. +SSH_TRUSTED_USER_CA_KEYS = +; Absolute path of the `TrustedUserCaKeys` file gitea will manage. +; Default this `RUN_USER`/.ssh/gitea-trusted-user-ca-keys.pem +; If you're running your own ssh server and you want to use the gitea managed file you'll also need to modify your +; sshd_config to point to this file. The official docker image will automatically work without further configuration. +SSH_TRUSTED_USER_CA_KEYS_FILENAME = +; Enable exposure of SSH clone URL to anonymous visitors, default is false +SSH_EXPOSE_ANONYMOUS = false +; Indicate whether to check minimum key size with corresponding type +MINIMUM_KEY_SIZE_CHECK = false +; Disable CDN even in "prod" mode +OFFLINE_MODE = false +DISABLE_ROUTER_LOG = false +; Generate steps: +; $ ./gitea cert -ca=true -duration=8760h0m0s -host=myhost.example.com +; +; Or from a .pfx file exported from the Windows certificate store (do +; not forget to export the private key): +; $ openssl pkcs12 -in cert.pfx -out cert.pem -nokeys +; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes +; Paths are relative to CUSTOM_PATH +CERT_FILE = https/cert.pem +KEY_FILE = https/key.pem +; Root directory containing templates and static files. +; default is the path where Gitea is executed +STATIC_ROOT_PATH = +; Default path for App data +APP_DATA_PATH = data +; Enable gzip compression for runtime-generated content, static resources excluded +ENABLE_GZIP = false +; Application profiling (memory and cpu) +; For "web" command it listens on localhost:6060 +; For "serve" command it dumps to disk at PPROF_DATA_PATH as (cpuprofile|memprofile)__ +ENABLE_PPROF = false +; PPROF_DATA_PATH, use an absolute path when you start gitea as service +PPROF_DATA_PATH = data/tmp/pprof +; Landing page, can be "home", "explore", "organizations" or "login" +; The "login" choice is not a security measure but just a UI flow change, use REQUIRE_SIGNIN_VIEW to force users to log in. +LANDING_PAGE = home +; Enables git-lfs support. true or false, default is false. +LFS_START_SERVER = false +; Where your lfs files reside, default is data/lfs. +LFS_CONTENT_PATH = data/lfs +; LFS authentication secret, change this yourself +LFS_JWT_SECRET = +; LFS authentication validity period (in time.Duration), pushes taking longer than this may fail. +LFS_HTTP_AUTH_EXPIRY = 20m +; Maximum allowed LFS file size in bytes (Set to 0 for no limit). +LFS_MAX_FILE_SIZE = 0 +; Maximum number of locks returned per page +LFS_LOCKS_PAGING_NUM = 50 +; Allow graceful restarts using SIGHUP to fork +ALLOW_GRACEFUL_RESTARTS = true +; After a restart the parent will finish ongoing requests before +; shutting down. Force shutdown if this process takes longer than this delay. +; set to a negative value to disable +GRACEFUL_HAMMER_TIME = 60s +; Allows the setting of a startup timeout and waithint for Windows as SVC service +; 0 disables this. +STARTUP_TIMEOUT = 0 +; Static resources, includes resources on custom/, public/ and all uploaded avatars web browser cache time. Note that this cache is disabled when RUN_MODE is "dev". Default is 6h +STATIC_CACHE_TIME = 6h + +; Define allowed algorithms and their minimum key length (use -1 to disable a type) +[ssh.minimum_key_sizes] +ED25519 = 256 +ECDSA = 256 +RSA = 2048 +DSA = -1 ; set to 1024 to switch on + +[database] +; Database to use. Either "mysql", "postgres", "mssql" or "sqlite3". +DB_TYPE = mysql +HOST = 127.0.0.1:3306 +NAME = gitea +USER = root +; Use PASSWD = `your password` for quoting if you use special characters in the password. +PASSWD = +; For Postgres, schema to use if different from "public". The schema must exist beforehand, +; the user must have creation privileges on it, and the user search path must be set +; to the look into the schema first. e.g.:ALTER USER user SET SEARCH_PATH = schema_name,"$user",public; +SCHEMA = +; For Postgres, either "disable" (default), "require", or "verify-full" +; For MySQL, either "false" (default), "true", or "skip-verify" +SSL_MODE = disable +; For MySQL only, either "utf8" or "utf8mb4", default is "utf8mb4". +; NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this. +CHARSET = utf8mb4 +; For "sqlite3" and "tidb", use an absolute path when you start gitea as service +PATH = data/gitea.db +; For "sqlite3" only. Query timeout +SQLITE_TIMEOUT = 500 +; For iterate buffer, default is 50 +ITERATE_BUFFER_SIZE = 50 +; Show the database generated SQL +LOG_SQL = true +; Maximum number of DB Connect retries +DB_RETRIES = 10 +; Backoff time per DB retry (time.Duration) +DB_RETRY_BACKOFF = 3s +; Max idle database connections on connnection pool, default is 2 +MAX_IDLE_CONNS = 2 +; Database connection max life time, default is 0 or 3s mysql (See #6804 & #7071 for reasoning) +CONN_MAX_LIFETIME = 3s +; Database maximum number of open connections, default is 0 meaning no maximum +MAX_OPEN_CONNS = 0 + +[indexer] +; Issue indexer type, currently support: bleve, db or elasticsearch, default is bleve +ISSUE_INDEXER_TYPE = bleve +; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch +ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200 +; Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch +ISSUE_INDEXER_NAME = gitea_issues +; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve +ISSUE_INDEXER_PATH = indexers/issues.bleve +; Issue indexer queue, currently support: channel, levelqueue or redis, default is levelqueue +ISSUE_INDEXER_QUEUE_TYPE = levelqueue +; When ISSUE_INDEXER_QUEUE_TYPE is levelqueue, this will be the path where the queue will be saved. +; This can be overriden by `ISSUE_INDEXER_QUEUE_CONN_STR`. +; default is indexers/issues.queue +ISSUE_INDEXER_QUEUE_DIR = indexers/issues.queue +; When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string. +; When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this is a directory or additional options of +; the form `leveldb://path/to/db?option=value&....`, and overrides `ISSUE_INDEXER_QUEUE_DIR`. +ISSUE_INDEXER_QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0" +; Batch queue number, default is 20 +ISSUE_INDEXER_QUEUE_BATCH_NUMBER = 20 +; Timeout the indexer if it takes longer than this to start. +; Set to zero to disable timeout. +STARTUP_TIMEOUT = 30s + +; repo indexer by default disabled, since it uses a lot of disk space +REPO_INDEXER_ENABLED = false +; Code search engine type, could be `bleve` or `elasticsearch`. +REPO_INDEXER_TYPE = bleve +; Index file used for code search. +REPO_INDEXER_PATH = indexers/repos.bleve +; Code indexer connection string, available when `REPO_INDEXER_TYPE` is elasticsearch. i.e. http://elastic:changeme@localhost:9200 +REPO_INDEXER_CONN_STR = +; Code indexer name, available when `REPO_INDEXER_TYPE` is elasticsearch +REPO_INDEXER_NAME = gitea_codes + +UPDATE_BUFFER_LEN = 20 +MAX_FILE_SIZE = 1048576 +; A comma separated list of glob patterns (see https://github.com/gobwas/glob) to include +; in the index; default is empty +REPO_INDEXER_INCLUDE = +; A comma separated list of glob patterns to exclude from the index; ; default is empty +REPO_INDEXER_EXCLUDE = + +[queue] +; Specific queues can be individually configured with [queue.name]. [queue] provides defaults +; +; General queue queue type, currently support: persistable-channel, channel, level, redis, dummy +; default to persistable-channel +TYPE = persistable-channel +; data-dir for storing persistable queues and level queues, individual queues will be named by their type +DATADIR = queues/ +; Default queue length before a channel queue will block +LENGTH = 20 +; Batch size to send for batched queues +BATCH_LENGTH = 20 +; Connection string for redis queues this will store the redis connection string. +; When `TYPE` is `persistable-channel`, this provides a directory for the underlying leveldb +; or additional options of the form `leveldb://path/to/db?option=value&....`, and will override `DATADIR`. +CONN_STR = "addrs=127.0.0.1:6379 db=0" +; Provides the suffix of the default redis/disk queue name - specific queues can be overriden within in their [queue.name] sections. +QUEUE_NAME = "_queue" +; Provides the suffix of the default redis/disk unique queue set name - specific queues can be overriden within in their [queue.name] sections. +SET_NAME = "_unique" +; If the queue cannot be created at startup - level queues may need a timeout at startup - wrap the queue: +WRAP_IF_NECESSARY = true +; Attempt to create the wrapped queue at max +MAX_ATTEMPTS = 10 +; Timeout queue creation +TIMEOUT = 15m30s +; Create a pool with this many workers +WORKERS = 1 +; Dynamically scale the worker pool to at this many workers +MAX_WORKERS = 10 +; Add boost workers when the queue blocks for BLOCK_TIMEOUT +BLOCK_TIMEOUT = 1s +; Remove the boost workers after BOOST_TIMEOUT +BOOST_TIMEOUT = 5m +; During a boost add BOOST_WORKERS +BOOST_WORKERS = 5 + +[admin] +; Disallow regular (non-admin) users from creating organizations. +DISABLE_REGULAR_ORG_CREATION = false +; Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled +DEFAULT_EMAIL_NOTIFICATIONS = enabled + +[security] +; Whether the installer is disabled +INSTALL_LOCK = false +; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!! +SECRET_KEY = !#@FDEWREWR&*( +; How long to remember that a user is logged in before requiring relogin (in days) +LOGIN_REMEMBER_DAYS = 7 +COOKIE_USERNAME = gitea_awesome +COOKIE_REMEMBER_NAME = gitea_incredible +; Reverse proxy authentication header name of user name +REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER +REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL +; The minimum password length for new Users +MIN_PASSWORD_LENGTH = 6 +; Set to true to allow users to import local server paths +IMPORT_LOCAL_PATHS = false +; Set to false to allow users with git hook privileges to create custom git hooks. +; Custom git hooks can be used to perform arbitrary code execution on the host operating system. +; This enables the users to access and modify this config file and the Gitea database and interrupt the Gitea service. +; By modifying the Gitea database, users can gain Gitea administrator privileges. +; It also enables them to access other resources available to the user on the operating system that is running the Gitea instance and perform arbitrary actions in the name of the Gitea OS user. +; WARNING: This maybe harmful to you website or your operating system. +DISABLE_GIT_HOOKS = true +; Set to false to allow pushes to gitea repositories despite having an incomplete environment - NOT RECOMMENDED +ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET = true +;Comma separated list of character classes required to pass minimum complexity. +;If left empty or no valid values are specified, the default is off (no checking) +;Classes include "lower,upper,digit,spec" +PASSWORD_COMPLEXITY = off +; Password Hash algorithm, either "argon2", "pbkdf2", "scrypt" or "bcrypt" +PASSWORD_HASH_ALGO = argon2 +; Set false to allow JavaScript to read CSRF cookie +CSRF_COOKIE_HTTP_ONLY = true +; Validate against https://haveibeenpwned.com/Passwords to see if a password has been exposed +PASSWORD_CHECK_PWN = false + +[openid] +; +; OpenID is an open, standard and decentralized authentication protocol. +; Your identity is the address of a webpage you provide, which describes +; how to prove you are in control of that page. +; +; For more info: https://en.wikipedia.org/wiki/OpenID +; +; Current implementation supports OpenID-2.0 +; +; Tested to work providers at the time of writing: +; - Any GNUSocial node (your.hostname.tld/username) +; - Any SimpleID provider (http://simpleid.koinic.net) +; - http://openid.org.cn/ +; - openid.stackexchange.com +; - login.launchpad.net +; - .livejournal.com +; +; Whether to allow signin in via OpenID +ENABLE_OPENID_SIGNIN = true +; Whether to allow registering via OpenID +; Do not include to rely on rhw DISABLE_REGISTRATION setting +;ENABLE_OPENID_SIGNUP = true +; Allowed URI patterns (POSIX regexp). +; Space separated. +; Only these would be allowed if non-blank. +; Example value: trusted.domain.org trusted.domain.net +WHITELISTED_URIS = +; Forbidden URI patterns (POSIX regexp). +; Space separated. +; Only used if WHITELISTED_URIS is blank. +; Example value: loadaverage.org/badguy stackexchange.com/.*spammer +BLACKLISTED_URIS = + +[service] +; Time limit to confirm account/email registration +ACTIVE_CODE_LIVE_MINUTES = 180 +; Time limit to perform the reset of a forgotten password +RESET_PASSWD_CODE_LIVE_MINUTES = 180 +; Whether a new user needs to confirm their email when registering. +REGISTER_EMAIL_CONFIRM = false +; Whether a new user needs to be confirmed manually after registration. (Requires `REGISTER_EMAIL_CONFIRM` to be disabled.) +REGISTER_MANUAL_CONFIRM = false +; List of domain names that are allowed to be used to register on a Gitea instance +; gitea.io,example.com +EMAIL_DOMAIN_WHITELIST = +; Disallow registration, only allow admins to create accounts. +DISABLE_REGISTRATION = false +; Allow registration only using third-party services, it works only when DISABLE_REGISTRATION is false +ALLOW_ONLY_EXTERNAL_REGISTRATION = false +; User must sign in to view anything. +REQUIRE_SIGNIN_VIEW = false +; Mail notification +ENABLE_NOTIFY_MAIL = false +; This setting enables gitea to be signed in with HTTP BASIC Authentication using the user's password +; If you set this to false you will not be able to access the tokens endpoints on the API with your password +; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token +ENABLE_BASIC_AUTHENTICATION = true +; More detail: https://github.com/gogits/gogs/issues/165 +ENABLE_REVERSE_PROXY_AUTHENTICATION = false +ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false +ENABLE_REVERSE_PROXY_EMAIL = false +; Enable captcha validation for registration +ENABLE_CAPTCHA = false +; Type of captcha you want to use. Options: image, recaptcha, hcaptcha +CAPTCHA_TYPE = image +; Enable recaptcha to use Google's recaptcha service +; Go to https://www.google.com/recaptcha/admin to sign up for a key +RECAPTCHA_SECRET = +RECAPTCHA_SITEKEY = +; For hCaptcha, create an account at https://accounts.hcaptcha.com/login to get your keys +HCAPTCHA_SECRET = +HCAPTCHA_SITEKEY = +; Change this to use recaptcha.net or other recaptcha service +RECAPTCHA_URL = https://www.google.com/recaptcha/ +; Default value for KeepEmailPrivate +; Each new user will get the value of this setting copied into their profile +DEFAULT_KEEP_EMAIL_PRIVATE = false +; Default value for AllowCreateOrganization +; Every new user will have rights set to create organizations depending on this setting +DEFAULT_ALLOW_CREATE_ORGANIZATION = true +; Either "public", "limited" or "private", default is "public" +; Limited is for signed user only +; Private is only for member of the organization +; Public is for everyone +DEFAULT_ORG_VISIBILITY = public +; Default value for DefaultOrgMemberVisible +; True will make the membership of the users visible when added to the organisation +DEFAULT_ORG_MEMBER_VISIBLE = false +; Default value for EnableDependencies +; Repositories will use dependencies by default depending on this setting +DEFAULT_ENABLE_DEPENDENCIES = true +; Dependencies can be added from any repository where the user is granted access or only from the current repository depending on this setting. +ALLOW_CROSS_REPOSITORY_DEPENDENCIES = true +; Enable heatmap on users profiles. +ENABLE_USER_HEATMAP = true +; Enable Timetracking +ENABLE_TIMETRACKING = true +; Default value for EnableTimetracking +; Repositories will use timetracking by default depending on this setting +DEFAULT_ENABLE_TIMETRACKING = true +; Default value for AllowOnlyContributorsToTrackTime +; Only users with write permissions can track time if this is true +DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME = true +; Default value for the domain part of the user's email address in the git log +; if he has set KeepEmailPrivate to true. The user's email will be replaced with a +; concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS. +NO_REPLY_ADDRESS = noreply.%(DOMAIN)s +; Show Registration button +SHOW_REGISTRATION_BUTTON = true +; Show milestones dashboard page - a view of all the user's milestones +SHOW_MILESTONES_DASHBOARD_PAGE = true +; Default value for AutoWatchNewRepos +; When adding a repo to a team or creating a new repo all team members will watch the +; repo automatically if enabled +AUTO_WATCH_NEW_REPOS = true +; Default value for AutoWatchOnChanges +; Make the user watch a repository When they commit for the first time +AUTO_WATCH_ON_CHANGES = false +; Minimum amount of time a user must exist before comments are kept when the user is deleted. +USER_DELETE_WITH_COMMENTS_MAX_TIME = 0 + +[webhook] +; Hook task queue length, increase if webhook shooting starts hanging +QUEUE_LENGTH = 1000 +; Deliver timeout in seconds +DELIVER_TIMEOUT = 5 +; Allow insecure certification +SKIP_TLS_VERIFY = false +; Number of history information in each page +PAGING_NUM = 10 +; Proxy server URL, support http://, https//, socks://, blank will follow environment http_proxy/https_proxy +PROXY_URL = +; Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts. +PROXY_HOSTS = + +[mailer] +ENABLED = false +; Buffer length of channel, keep it as it is if you don't know what it is. +SEND_BUFFER_LEN = 100 +; Prefix displayed before subject in mail +SUBJECT_PREFIX = +; Mail server +; Gmail: smtp.gmail.com:587 +; QQ: smtp.qq.com:465 +; Using STARTTLS on port 587 is recommended per RFC 6409. +; Note, if the port ends with "465", SMTPS will 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. +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 +; 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 +; Mail from address, RFC 5322. This can be just an email address, or the `"Name" ` format +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`. +USER = +; Use PASSWD = `your password` for quoting if you use special characters in the password. +PASSWD = +; Send mails as plain text +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 +; Specify any extra sendmail arguments +SENDMAIL_ARGS = +; Timeout for Sendmail +SENDMAIL_TIMEOUT = 5m + +[cache] +; if the cache enabled +ENABLED = true +; Either "memory", "redis", or "memcache", default is "memory" +ADAPTER = memory +; For "memory" only, GC interval in seconds, default is 60 +INTERVAL = 60 +; For "redis" and "memcache", connection host address +; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180 +; memcache: `127.0.0.1:11211` +HOST = +; Time to keep items in cache if not used, default is 16 hours. +; Setting it to 0 disables caching +ITEM_TTL = 16h + +; Last commit cache +[cache.last_commit] +; if the cache enabled +ENABLED = true +; Time to keep items in cache if not used, default is 8760 hours. +; Setting it to 0 disables caching +ITEM_TTL = 8760h +; Only enable the cache when repository's commits count great than +COMMITS_COUNT = 1000 + +[session] +; Either "memory", "file", or "redis", default is "memory" +PROVIDER = memory +; Provider config options +; memory: doesn't have any config yet +; file: session file path, e.g. `data/sessions` +; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180 +; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table` +PROVIDER_CONFIG = data/sessions +; Session cookie name +COOKIE_NAME = i_like_gitea +; If you use session in https only, default is false +COOKIE_SECURE = false +; Session GC time interval in seconds, default is 86400 (1 day) +GC_INTERVAL_TIME = 86400 +; Session life time in seconds, default is 86400 (1 day) +SESSION_LIFE_TIME = 86400 + +[picture] +AVATAR_UPLOAD_PATH = data/avatars +REPOSITORY_AVATAR_UPLOAD_PATH = data/repo-avatars +; How Gitea deals with missing repository avatars +; none = no avatar will be displayed; random = random avatar will be displayed; image = default image will be used +REPOSITORY_AVATAR_FALLBACK = none +REPOSITORY_AVATAR_FALLBACK_IMAGE = /img/repo_default.png +; Max Width and Height of uploaded avatars. +; This is to limit the amount of RAM used when resizing the image. +AVATAR_MAX_WIDTH = 4096 +AVATAR_MAX_HEIGHT = 3072 +; Maximum alloved file size for uploaded avatars. +; This is to limit the amount of RAM used when resizing the image. +AVATAR_MAX_FILE_SIZE = 1048576 +; Chinese users can choose "duoshuo" +; or a custom avatar source, like: http://cn.gravatar.com/avatar/ +GRAVATAR_SOURCE = gravatar +; This value will always be true in offline mode. +DISABLE_GRAVATAR = false +; Federated avatar lookup uses DNS to discover avatar associated +; with emails, see https://www.libravatar.org +; This value will always be false in offline mode or when Gravatar is disabled. +ENABLE_FEDERATED_AVATAR = false + +[attachment] +; Whether issue and pull request attachments are enabled. Defaults to `true` +ENABLED = true +; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. +ALLOWED_TYPES = .docx,.gif,.gz,.jpeg,.jpg,.log,.pdf,.png,.pptx,.txt,.xlsx,.zip +; Max size of each file. Defaults to 4MB +MAX_SIZE = 4 +; Max number of files per upload. Defaults to 5 +MAX_FILES = 5 +; Storage type for attachments, `local` for local disk or `minio` for s3 compatible +; object storage service, default is `local`. +STORAGE_TYPE = local +; Allows the storage driver to redirect to authenticated URLs to serve files directly +; Currently, only `minio` is supported. +SERVE_DIRECT = false +; Path for attachments. Defaults to `data/attachments` only available when STORAGE_TYPE is `local` +PATH = data/attachments +; Minio endpoint to connect only available when STORAGE_TYPE is `minio` +MINIO_ENDPOINT = localhost:9000 +; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio` +MINIO_ACCESS_KEY_ID = +; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` +MINIO_SECRET_ACCESS_KEY = +; Minio bucket to store the attachments only available when STORAGE_TYPE is `minio` +MINIO_BUCKET = gitea +; Minio location to create bucket only available when STORAGE_TYPE is `minio` +MINIO_LOCATION = us-east-1 +; Minio base path on the bucket only available when STORAGE_TYPE is `minio` +MINIO_BASE_PATH = attachments/ +; Minio enabled ssl only available when STORAGE_TYPE is `minio` +MINIO_USE_SSL = false + +[time] +; Specifies the format for fully outputted dates. Defaults to RFC1123 +; Special supported values are ANSIC, UnixDate, RubyDate, RFC822, RFC822Z, RFC850, RFC1123, RFC1123Z, RFC3339, RFC3339Nano, Kitchen, Stamp, StampMilli, StampMicro and StampNano +; For more information about the format see http://golang.org/pkg/time/#pkg-constants +FORMAT = +; Location the UI time display i.e. Asia/Shanghai +; Empty means server's location setting +DEFAULT_UI_LOCATION = + +[log] +ROOT_PATH = +; Either "console", "file", "conn", "smtp" or "database", default is "console" +; Use comma to separate multiple modes, e.g. "console, file" +MODE = console +; Buffer length of the channel, keep it as it is if you don't know what it is. +BUFFER_LEN = 10000 +REDIRECT_MACARON_LOG = false +MACARON = file +; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Info" +ROUTER_LOG_LEVEL = Info +ROUTER = console +ENABLE_ACCESS_LOG = false +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}}" +ACCESS = file +; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace" +LEVEL = Info +; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "None" +STACKTRACE_LEVEL = None + +; Generic log modes +[log.x] +FLAGS = stdflags +EXPRESSION = +PREFIX = +COLORIZE = false + +; For "console" mode only +[log.console] +LEVEL = +STDERR = false + +; For "file" mode only +[log.file] +LEVEL = +; Set the file_name for the logger. If this is a relative path this +; will be relative to ROOT_PATH +FILE_NAME = +; This enables automated log rotate(switch of following options), default is true +LOG_ROTATE = true +; Max size shift of a single file, default is 28 means 1 << 28, 256MB +MAX_SIZE_SHIFT = 28 +; Segment log daily, default is true +DAILY_ROTATE = true +; delete the log file after n days, default is 7 +MAX_DAYS = 7 +; compress logs with gzip +COMPRESS = true +; compression level see godoc for compress/gzip +COMPRESSION_LEVEL = -1 + +; For "conn" mode only +[log.conn] +LEVEL = +; Reconnect host for every single message, default is false +RECONNECT_ON_MSG = false +; Try to reconnect when connection is lost, default is false +RECONNECT = false +; Either "tcp", "unix" or "udp", default is "tcp" +PROTOCOL = tcp +; Host address +ADDR = + +; For "smtp" mode only +[log.smtp] +LEVEL = +; Name displayed in mail title, default is "Diagnostic message from server" +SUBJECT = Diagnostic message from server +; Mail server +HOST = +; Mailer user name and password +USER = +; Use PASSWD = `your password` for quoting if you use special characters in the password. +PASSWD = +; Receivers, can be one or more, e.g. 1@example.com,2@example.com +RECEIVERS = + +[cron] +; Enable running all cron tasks periodically with default settings. +ENABLED = false +; Run cron tasks when Gitea starts. +RUN_AT_START = false + +; Basic cron tasks - enabled by default + +; Clean up old repository archives +[cron.archive_cleanup] +; Whether to enable the job +ENABLED = true +; Whether to always run at least once at start up time (if ENABLED) +RUN_AT_START = true +; Notice if not success +NO_SUCCESS_NOTICE = false +; Time interval for job to run +SCHEDULE = @every 24h +; Archives created more than OLDER_THAN ago are subject to deletion +OLDER_THAN = 24h + +; Update mirrors +[cron.update_mirrors] +SCHEDULE = @every 10m +; Enable running Update mirrors task periodically. +ENABLED = true +; Run Update mirrors task when Gitea starts. +RUN_AT_START = false +; Notice if not success +NO_SUCCESS_NOTICE = true + +; Repository health check +[cron.repo_health_check] +SCHEDULE = @every 24h +; Enable running Repository health check task periodically. +ENABLED = true +; Run Repository health check task when Gitea starts. +RUN_AT_START = false +; Notice if not success +NO_SUCCESS_NOTICE = false +TIMEOUT = 60s +; Arguments for command 'git fsck', e.g. "--unreachable --tags" +; see more on http://git-scm.com/docs/git-fsck +ARGS = + +; Check repository statistics +[cron.check_repo_stats] +; Enable running check repository statistics task periodically. +ENABLED = true +; Run check repository statistics task when Gitea starts. +RUN_AT_START = true +; Notice if not success +NO_SUCCESS_NOTICE = false +SCHEDULE = @every 24h + +[cron.update_migration_poster_id] +; Update migrated repositories' issues and comments' posterid, it will always attempt synchronization when the instance starts. +ENABLED = true +; Update migrated repositories' issues and comments' posterid when starting server (default true) +RUN_AT_START = true +; Notice if not success +NO_SUCCESS_NOTICE = false +; Interval as a duration between each synchronization. (default every 24h) +SCHEDULE = @every 24h + +; Synchronize external user data (only LDAP user synchronization is supported) +[cron.sync_external_users] +ENABLED = true +; Synchronize external user data when starting server (default false) +RUN_AT_START = false +; Notice if not success +NO_SUCCESS_NOTICE = false +; Interval as a duration between each synchronization (default every 24h) +SCHEDULE = @every 24h +; Create new users, update existing user data and disable users that are not in external source anymore (default) +; or only create new users if UPDATE_EXISTING is set to false +UPDATE_EXISTING = true + +; Clean-up deleted branches +[cron.deleted_branches_cleanup] +ENABLED = true +; Clean-up deleted branches when starting server (default true) +RUN_AT_START = true +; Notice if not success +NO_SUCCESS_NOTICE = false +; Interval as a duration between each synchronization (default every 24h) +SCHEDULE = @every 24h +; deleted branches than OLDER_THAN ago are subject to deletion +OLDER_THAN = 24h + +; Extended cron task - not enabled by default + +; Delete all unactivated accounts +[cron.delete_inactive_accounts] +ENABLED = false +RUN_AT_START = false +NO_SUCCESS_NOTICE = false +SCHEDULE = @annually +OLDER_THAN = 168h + +; Delete all repository archives +[cron.delete_repo_archives] +ENABLED = false +RUN_AT_START = false +NO_SUCCESS_NOTICE = false +SCHEDULE = @annually + +; Garbage collect all repositories +[cron.git_gc_repos] +ENABLED = false +RUN_AT_START = false +NO_SUCCESS_NOTICE = false +SCHEDULE = @every 72h +TIMEOUT = 60s +; Arguments for command 'git gc' +; The default value is same with [git] -> GC_ARGS +ARGS = + +; Update the '.ssh/authorized_keys' file with Gitea SSH keys +[cron.resync_all_sshkeys] +ENABLED = false +RUN_AT_START = false +NO_SUCCESS_NOTICE = false +SCHEDULE = @every 72h + +; Resynchronize pre-receive, update and post-receive hooks of all repositories. +[cron.resync_all_hooks] +ENABLED = false +RUN_AT_START = false +NO_SUCCESS_NOTICE = false +SCHEDULE = @every 72h + +; Reinitialize all missing Git repositories for which records exist +[cron.reinit_missing_repos] +ENABLED = false +RUN_AT_START = false +NO_SUCCESS_NOTICE = false +SCHEDULE = @every 72h + +; Delete all repositories missing their Git files +[cron.delete_missing_repos] +ENABLED = false +RUN_AT_START = false +NO_SUCCESS_NOTICE = false +SCHEDULE = @every 72h + +; Delete generated repository avatars +[cron.delete_generated_repository_avatars] +ENABLED = false +RUN_AT_START = false +NO_SUCCESS_NOTICE = false +SCHEDULE = @every 72h + +[git] +; The path of git executable. If empty, Gitea searches through the PATH environment. +PATH = +; Disables highlight of added and removed changes +DISABLE_DIFF_HIGHLIGHT = false +; Max number of lines allowed in a single file in diff view +MAX_GIT_DIFF_LINES = 1000 +; Max number of allowed characters in a line in diff view +MAX_GIT_DIFF_LINE_CHARACTERS = 5000 +; Max number of files shown in diff view +MAX_GIT_DIFF_FILES = 100 +; Set the default commits range size +COMMITS_RANGE_SIZE = 50 +; Set the default branches range size +BRANCHES_RANGE_SIZE = 20 +; Arguments for command 'git gc', e.g. "--aggressive --auto" +; see more on http://git-scm.com/docs/git-gc/ +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 +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) +PULL_REQUEST_PUSH_MESSAGE = true + +; Operation timeout in seconds +[git.timeout] +DEFAULT = 360 +MIGRATE = 600 +MIRROR = 300 +CLONE = 300 +PULL = 300 +GC = 60 + +[mirror] +; Default interval as a duration between each check +DEFAULT_INTERVAL = 8h +; Min interval as a duration must be > 1m +MIN_INTERVAL = 10m + +[api] +; Enables Swagger. True or false; default is true. +ENABLE_SWAGGER = true +; Max number of items in a page +MAX_RESPONSE_ITEMS = 50 +; Default paging number of api +DEFAULT_PAGING_NUM = 30 +; Default and maximum number of items per page for git trees api +DEFAULT_GIT_TREES_PER_PAGE = 1000 +; Default size of a blob returned by the blobs API (default is 10MiB) +DEFAULT_MAX_BLOB_SIZE = 10485760 + +[oauth2] +; Enables OAuth2 provider +ENABLE = true +; Lifetime of an OAuth2 access token in seconds +ACCESS_TOKEN_EXPIRATION_TIME = 3600 +; Lifetime of an OAuth2 refresh token in hours +REFRESH_TOKEN_EXPIRATION_TIME = 730 +; Check if refresh token got already used +INVALIDATE_REFRESH_TOKENS = false +; OAuth2 authentication secret for access and refresh tokens, change this yourself to a unique string. CLI generate option is helpful in this case. https://docs.gitea.io/en-us/command-line/#generate +JWT_SECRET = +; Maximum length of oauth2 token/cookie stored on server +MAX_TOKEN_LENGTH = 32767 + +[i18n] +LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR +NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,Українська,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어 + +[U2F] +; NOTE: THE DEFAULT VALUES HERE WILL NEED TO BE CHANGED +; Two Factor authentication with security keys +; https://developers.yubico.com/U2F/App_ID.html +;APP_ID = http://localhost:3000/ +; Comma separated list of trusted facets +;TRUSTED_FACETS = http://localhost:3000/ + +; Extension mapping to highlight class +; e.g. .toml=ini +[highlight.mapping] + +[other] +SHOW_FOOTER_BRANDING = false +; Show version information about Gitea and Go in the footer +SHOW_FOOTER_VERSION = true +; Show template execution time in the footer +SHOW_FOOTER_TEMPLATE_LOAD_TIME = true + +[markup.sanitizer.1] +; The following keys can appear once to define a sanitation policy rule. +; This section can appear multiple times by adding a unique alphanumeric suffix to define multiple rules. +; e.g., [markup.sanitizer.1] -> [markup.sanitizer.2] -> [markup.sanitizer.TeX] +;ELEMENT = span +;ALLOW_ATTR = class +;REGEXP = ^(info|warning|error)$ + +[markup.asciidoc] +ENABLED = false +; List of file extensions that should be rendered by an external command +FILE_EXTENSIONS = .adoc,.asciidoc +; External command to render all matching extensions +RENDER_COMMAND = "asciidoc --out-file=- -" +; Don't pass the file on STDIN, pass the filename as argument instead. +IS_INPUT_FILE = false + +[metrics] +; Enables metrics endpoint. True or false; default is false. +ENABLED = false +; If you want to add authorization, specify a token here +TOKEN = + +[task] +; Task queue type, could be `channel` or `redis`. +QUEUE_TYPE = channel +; Task queue length, available only when `QUEUE_TYPE` is `channel`. +QUEUE_LENGTH = 1000 +; Task queue connection string, available only when `QUEUE_TYPE` is `redis`. +; If there is a password of redis, use `addrs=127.0.0.1:6379 password=123 db=0`. +QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0" + +[migrations] +; Max attempts per http/https request on migrations. +MAX_ATTEMPTS = 3 +; Backoff time per http/https request retry (seconds) +RETRY_BACKOFF = 3 +; Allowed domains for migrating, default is blank. Blank means everything will be allowed. +; Multiple domains could be separated by commas. +ALLOWED_DOMAINS = +; Blocklist for migrating, default is blank. Multiple domains could be separated by commas. +; When ALLOWED_DOMAINS is not blank, this option will be ignored. +BLOCKED_DOMAINS = +; Allow private addresses defined by RFC 1918, RFC 1122, RFC 4632 and RFC 4291 (false by default) +ALLOW_LOCALNETWORKS = false + +; default storage for attachments, lfs and avatars +[storage] +; storage type +STORAGE_TYPE = local + +; lfs storage will override storage +[lfs] +STORAGE_TYPE = local + +; customize storage +;[storage.my_minio] +;STORAGE_TYPE = minio +; Minio endpoint to connect only available when STORAGE_TYPE is `minio` +;MINIO_ENDPOINT = localhost:9000 +; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio` +;MINIO_ACCESS_KEY_ID = +; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` +;MINIO_SECRET_ACCESS_KEY = +; Minio bucket to store the attachments only available when STORAGE_TYPE is `minio` +;MINIO_BUCKET = gitea +; Minio location to create bucket only available when STORAGE_TYPE is `minio` +;MINIO_LOCATION = us-east-1 +; Minio enabled ssl only available when STORAGE_TYPE is `minio` +;MINIO_USE_SSL = false diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample deleted file mode 100644 index fee5f0b063a17..0000000000000 --- a/custom/conf/app.ini.sample +++ /dev/null @@ -1,1034 +0,0 @@ -; This file lists the default values used by Gitea -; Copy required sections to your own app.ini (default is custom/conf/app.ini) -; and modify as needed. - -; see https://docs.gitea.io/en-us/config-cheat-sheet/ for additional documentation. - -; App name that shows in every page title -APP_NAME = Gitea: Git with a cup of tea -; Change it if you run locally -RUN_USER = git -; Either "dev", "prod" or "test", default is "dev" -RUN_MODE = dev - -[repository] -ROOT = -SCRIPT_TYPE = bash -; DETECTED_CHARSETS_ORDER tie-break order for detected charsets. -; If the charsets have equal confidence, tie-breaking will be done by order in this list -; with charsets earlier in the list chosen in preference to those later. -; Adding "defaults" will place the unused charsets at that position. -DETECTED_CHARSETS_ORDER=UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE, ISO-8859, windows-1252, ISO-8859, windows-1250, ISO-8859, ISO-8859, ISO-8859, windows-1253, ISO-8859, windows-1255, ISO-8859, windows-1251, windows-1256, KOI8-R, ISO-8859, windows-1254, Shift_JIS, GB18030, EUC-JP, EUC-KR, Big5, ISO-2022, ISO-2022, ISO-2022, IBM424_rtl, IBM424_ltr, IBM420_rtl, IBM420_ltr -; Default ANSI charset to override non-UTF-8 charsets to -ANSI_CHARSET = -; Force every new repository to be private -FORCE_PRIVATE = false -; Default privacy setting when creating a new repository, allowed values: last, private, public. Default is last which means the last setting used. -DEFAULT_PRIVATE = last -; Global limit of repositories per user, applied at creation time. -1 means no limit -MAX_CREATION_LIMIT = -1 -; Mirror sync queue length, increase if mirror syncing starts hanging -MIRROR_QUEUE_LENGTH = 1000 -; Patch test queue length, increase if pull request patch testing starts hanging -PULL_REQUEST_QUEUE_LENGTH = 1000 -; Preferred Licenses to place at the top of the List -; The name here must match the filename in conf/license or custom/conf/license -PREFERRED_LICENSES = Apache License 2.0,MIT License -; Disable the ability to interact with repositories using the HTTP protocol -DISABLE_HTTP_GIT = false -; Value for Access-Control-Allow-Origin header, default is not to present -; WARNING: This maybe harmful to you website if you do not give it a right value. -ACCESS_CONTROL_ALLOW_ORIGIN = -; Force ssh:// clone url instead of scp-style uri when default SSH port is used -USE_COMPAT_SSH_URI = false -; Close issues as long as a commit on any branch marks it as fixed -DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH = false -; Allow users to push local repositories to Gitea and have them automatically created for a user or an org -ENABLE_PUSH_CREATE_USER = false -ENABLE_PUSH_CREATE_ORG = false -; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki -DISABLED_REPO_UNITS = -; Comma separated list of default repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki. -; Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility. -; External wiki and issue tracker can't be enabled by default as it requires additional settings. -; Disabled repo units will not be added to new repositories regardless if it is in the default list. -DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki -; Prefix archive files by placing them in a directory named after the repository -PREFIX_ARCHIVE_FILES = true -; Disable the creation of new mirrors. Pre-existing mirrors remain valid. -DISABLE_MIRRORS = false - -[repository.editor] -; List of file extensions for which lines should be wrapped in the Monaco editor -; Separate extensions with a comma. To line wrap files without an extension, just put a comma -LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd, -; Valid file modes that have a preview API associated with them, such as api/v1/markdown -; Separate the values by commas. The preview tab in edit mode won't be displayed if the file extension doesn't match -PREVIEWABLE_FILE_MODES = markdown - -[repository.local] -; Path for local repository copy. Defaults to `tmp/local-repo` -LOCAL_COPY_PATH = tmp/local-repo -; Path for local wiki copy. Defaults to `tmp/local-wiki` -LOCAL_WIKI_PATH = tmp/local-wiki - -[repository.upload] -; Whether repository file uploads are enabled. Defaults to `true` -ENABLED = true -; Path for uploads. Defaults to `data/tmp/uploads` (tmp gets deleted on gitea restart) -TEMP_PATH = data/tmp/uploads -; One or more allowed types, e.g. image/jpeg|image/png. Nothing means any file type -ALLOWED_TYPES = -; Max size of each file in megabytes. Defaults to 3MB -FILE_MAX_SIZE = 3 -; Max number of files per upload. Defaults to 5 -MAX_FILES = 5 - -[repository.pull-request] -; List of prefixes used in Pull Request title to mark them as Work In Progress -WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP] -; List of keywords used in Pull Request comments to automatically close a related issue -CLOSE_KEYWORDS=close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved -; List of keywords used in Pull Request comments to automatically reopen a related issue -REOPEN_KEYWORDS=reopen,reopens,reopened -; In the default merge message for squash commits include at most this many commits -DEFAULT_MERGE_MESSAGE_COMMITS_LIMIT=50 -; In the default merge message for squash commits limit the size of the commit messages to this -DEFAULT_MERGE_MESSAGE_SIZE=5120 -; In the default merge message for squash commits walk all commits to include all authors in the Co-authored-by otherwise just use those in the limited list -DEFAULT_MERGE_MESSAGE_ALL_AUTHORS=false -; In default merge messages limit the number of approvers listed as Reviewed-by: to this many -DEFAULT_MERGE_MESSAGE_MAX_APPROVERS=10 -; In default merge messages only include approvers who are official -DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY=true - -[repository.issue] -; List of reasons why a Pull Request or Issue can be locked -LOCK_REASONS=Too heated,Off-topic,Resolved,Spam - -[repository.signing] -; GPG key to use to sign commits, Defaults to the default - that is the value of git config --get user.signingkey -; run in the context of the RUN_USER -; Switch to none to stop signing completely -SIGNING_KEY = default -; If a SIGNING_KEY ID is provided and is not set to default, use the provided Name and Email address as the signer. -; These should match a publicized name and email address for the key. (When SIGNING_KEY is default these are set to -; the results of git config --get user.name and git config --get user.email respectively and can only be overrided -; by setting the SIGNING_KEY ID to the correct ID.) -SIGNING_NAME = -SIGNING_EMAIL = -; Determines when gitea should sign the initial commit when creating a repository -; Either: -; - never -; - pubkey: only sign if the user has a pubkey -; - twofa: only sign if the user has logged in with twofa -; - always -; options other than none and always can be combined as comma separated list -INITIAL_COMMIT = always -; Determines when to sign for CRUD actions -; - as above -; - parentsigned: requires that the parent commit is signed. -CRUD_ACTIONS = pubkey, twofa, parentsigned -; Determines when to sign Wiki commits -; - as above -WIKI = never -; Determines when to sign on merges -; - basesigned: require that the parent of commit on the base repo is signed. -; - commitssigned: require that all the commits in the head branch are signed. -; - approved: only sign when merging an approved pr to a protected branch -MERGES = pubkey, twofa, basesigned, commitssigned - -[cors] -; More information about CORS can be found here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers -; enable cors headers (disabled by default) -ENABLED=false -; scheme of allowed requests -SCHEME=http -; list of requesting domains that are allowed -ALLOW_DOMAIN=* -; allow subdomains of headers listed above to request -ALLOW_SUBDOMAIN=false -; list of methods allowed to request -METHODS=GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS -; max time to cache response -MAX_AGE=10m -; allow request with credentials -ALLOW_CREDENTIALS=false - -[ui] -; Number of repositories that are displayed on one explore page -EXPLORE_PAGING_NUM = 20 -; Number of issues that are displayed on one page -ISSUE_PAGING_NUM = 10 -; Number of maximum commits displayed in one activity feed -FEED_MAX_COMMIT_NUM = 5 -; Number of maximum commits displayed in commit graph. -GRAPH_MAX_COMMIT_NUM = 100 -; Number of line of codes shown for a code comment -CODE_COMMENT_LINES = 4 -; Value of `theme-color` meta tag, used by Android >= 5.0 -; An invalid color like "none" or "disable" will have the default style -; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android -THEME_COLOR_META_TAG = `#6cc644` -; Max size of files to be displayed (default is 8MiB) -MAX_DISPLAY_FILE_SIZE = 8388608 -; Whether the email of the user should be shown in the Explore Users page -SHOW_USER_EMAIL = true -; Set the default theme for the Gitea install -DEFAULT_THEME = gitea -; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`. -THEMES = gitea,arc-green -;All available reactions users can choose on issues/prs and comments. -;Values can be emoji alias (:smile:) or a unicode emoji. -;For custom reactions, add a tightly cropped square image to public/emoji/img/reaction_name.png -REACTIONS = +1, -1, laugh, hooray, confused, heart, rocket, eyes -; Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used. -DEFAULT_SHOW_FULL_NAME = false -; Whether to search within description at repository search on explore page. -SEARCH_REPO_DESCRIPTION = true -; Whether to enable a Service Worker to cache frontend assets -USE_SERVICE_WORKER = true - -[ui.admin] -; Number of users that are displayed on one page -USER_PAGING_NUM = 50 -; Number of repos that are displayed on one page -REPO_PAGING_NUM = 50 -; Number of notices that are displayed on one page -NOTICE_PAGING_NUM = 25 -; Number of organizations that are displayed on one page -ORG_PAGING_NUM = 50 - -[ui.user] -; Number of repos that are displayed on one page -REPO_PAGING_NUM = 15 - -[ui.meta] -AUTHOR = Gitea - Git with a cup of tea -DESCRIPTION = Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go -KEYWORDS = go,git,self-hosted,gitea - -[ui.notification] -; Control how often the notification endpoint is polled to update the notification -; The timeout will increase to MAX_TIMEOUT in TIMEOUT_STEPs if the notification count is unchanged -; Set MIN_TIMEOUT to 0 to turn off -MIN_TIMEOUT = 10s -MAX_TIMEOUT = 60s -TIMEOUT_STEP = 10s -; This setting determines how often the db is queried to get the latest notification counts. -; If the browser client supports EventSource, it will be used in preference to polling notification. -EVENT_SOURCE_UPDATE_TIME = 10s - -[markdown] -; Render soft line breaks as hard line breaks, which means a single newline character between -; paragraphs will cause a line break and adding trailing whitespace to paragraphs is not -; necessary to force a line break. -; Render soft line breaks as hard line breaks for comments -ENABLE_HARD_LINE_BREAK_IN_COMMENTS = true -; Render soft line breaks as hard line breaks for markdown documents -ENABLE_HARD_LINE_BREAK_IN_DOCUMENTS = false -; Comma separated list of custom URL-Schemes that are allowed as links when rendering Markdown -; for example git,magnet,ftp (more at https://en.wikipedia.org/wiki/List_of_URI_schemes) -; URLs starting with http and https are always displayed, whatever is put in this entry. -CUSTOM_URL_SCHEMES = -; List of file extensions that should be rendered/edited as Markdown -; Separate the extensions with a comma. To render files without any extension as markdown, just put a comma -FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd - -[server] -; The protocol the server listens on. One of 'http', 'https', 'unix' or 'fcgi'. -PROTOCOL = http -DOMAIN = localhost -ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/ -; when STATIC_URL_PREFIX is empty it will follow ROOT_URL -STATIC_URL_PREFIX = -; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket. -HTTP_ADDR = 0.0.0.0 -; The port to listen on. Leave empty when using a unix socket. -HTTP_PORT = 3000 -; If REDIRECT_OTHER_PORT is true, and PROTOCOL is set to https an http server -; will be started on PORT_TO_REDIRECT and it will redirect plain, non-secure http requests to the main -; ROOT_URL. Defaults are false for REDIRECT_OTHER_PORT and 80 for -; PORT_TO_REDIRECT. -REDIRECT_OTHER_PORT = false -PORT_TO_REDIRECT = 80 -; Permission for unix socket -UNIX_SOCKET_PERMISSION = 666 -; Local (DMZ) URL for Gitea workers (such as SSH update) accessing web service. -; In most cases you do not need to change the default value. -; Alter it only if your SSH server node is not the same as HTTP node. -; Do not set this variable if PROTOCOL is set to 'unix'. -LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/ -; Disable SSH feature when not available -DISABLE_SSH = false -; Whether to use the builtin SSH server or not. -START_SSH_SERVER = false -; Username to use for the builtin SSH server. If blank, then it is the value of RUN_USER. -BUILTIN_SSH_SERVER_USER = -; Domain name to be exposed in clone URL -SSH_DOMAIN = %(DOMAIN)s -; The network interface the builtin SSH server should listen on -SSH_LISTEN_HOST = -; Port number to be exposed in clone URL -SSH_PORT = 22 -; The port number the builtin SSH server should listen on -SSH_LISTEN_PORT = %(SSH_PORT)s -; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. -SSH_ROOT_PATH = -; Gitea will create a authorized_keys file by default when it is not using the internal ssh server -; If you intend to use the AuthorizedKeysCommand functionality then you should turn this off. -SSH_CREATE_AUTHORIZED_KEYS_FILE = true -; For the built-in SSH server, choose the ciphers to support for SSH connections, -; for system SSH this setting has no effect -SSH_SERVER_CIPHERS = aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128 -; For the built-in SSH server, choose the key exchange algorithms to support for SSH connections, -; for system SSH this setting has no effect -SSH_SERVER_KEY_EXCHANGES = diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, curve25519-sha256@libssh.org -; For the built-in SSH server, choose the MACs to support for SSH connections, -; for system SSH this setting has no effect -SSH_SERVER_MACS = hmac-sha2-256-etm@openssh.com, hmac-sha2-256, hmac-sha1, hmac-sha1-96 -; Directory to create temporary files in when testing public keys using ssh-keygen, -; default is the system temporary directory. -SSH_KEY_TEST_PATH = -; Path to ssh-keygen, default is 'ssh-keygen' which means the shell is responsible for finding out which one to call. -SSH_KEYGEN_PATH = ssh-keygen -; Enable SSH Authorized Key Backup when rewriting all keys, default is true -SSH_BACKUP_AUTHORIZED_KEYS = true -; Enable exposure of SSH clone URL to anonymous visitors, default is false -SSH_EXPOSE_ANONYMOUS = false -; Indicate whether to check minimum key size with corresponding type -MINIMUM_KEY_SIZE_CHECK = false -; Disable CDN even in "prod" mode -OFFLINE_MODE = false -DISABLE_ROUTER_LOG = false -; Generate steps: -; $ ./gitea cert -ca=true -duration=8760h0m0s -host=myhost.example.com -; -; Or from a .pfx file exported from the Windows certificate store (do -; not forget to export the private key): -; $ openssl pkcs12 -in cert.pfx -out cert.pem -nokeys -; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes -; Paths are relative to CUSTOM_PATH -CERT_FILE = https/cert.pem -KEY_FILE = https/key.pem -; Root directory containing templates and static files. -; default is the path where Gitea is executed -STATIC_ROOT_PATH = -; Default path for App data -APP_DATA_PATH = data -; Application level GZIP support -ENABLE_GZIP = false -; Application profiling (memory and cpu) -; For "web" command it listens on localhost:6060 -; For "serve" command it dumps to disk at PPROF_DATA_PATH as (cpuprofile|memprofile)__ -ENABLE_PPROF = false -; PPROF_DATA_PATH, use an absolute path when you start gitea as service -PPROF_DATA_PATH = data/tmp/pprof -; Landing page, can be "home", "explore", "organizations" or "login" -; The "login" choice is not a security measure but just a UI flow change, use REQUIRE_SIGNIN_VIEW to force users to log in. -LANDING_PAGE = home -; Enables git-lfs support. true or false, default is false. -LFS_START_SERVER = false -; Where your lfs files reside, default is data/lfs. -LFS_CONTENT_PATH = data/lfs -; LFS authentication secret, change this yourself -LFS_JWT_SECRET = -; LFS authentication validity period (in time.Duration), pushes taking longer than this may fail. -LFS_HTTP_AUTH_EXPIRY = 20m -; Maximum allowed LFS file size in bytes (Set to 0 for no limit). -LFS_MAX_FILE_SIZE = 0 -; Maximum number of locks returned per page -LFS_LOCKS_PAGING_NUM = 50 -; Allow graceful restarts using SIGHUP to fork -ALLOW_GRACEFUL_RESTARTS = true -; After a restart the parent will finish ongoing requests before -; shutting down. Force shutdown if this process takes longer than this delay. -; set to a negative value to disable -GRACEFUL_HAMMER_TIME = 60s -; Allows the setting of a startup timeout and waithint for Windows as SVC service -; 0 disables this. -STARTUP_TIMEOUT = 0 -; Static resources, includes resources on custom/, public/ and all uploaded avatars web browser cache time, default is 6h -STATIC_CACHE_TIME = 6h - -; Define allowed algorithms and their minimum key length (use -1 to disable a type) -[ssh.minimum_key_sizes] -ED25519 = 256 -ECDSA = 256 -RSA = 2048 -DSA = 1024 - -[database] -; Database to use. Either "mysql", "postgres", "mssql" or "sqlite3". -DB_TYPE = mysql -HOST = 127.0.0.1:3306 -NAME = gitea -USER = root -; Use PASSWD = `your password` for quoting if you use special characters in the password. -PASSWD = -; For Postgres, schema to use if different from "public". The schema must exist beforehand, -; the user must have creation privileges on it, and the user search path must be set -; to the look into the schema first. e.g.:ALTER USER user SET SEARCH_PATH = schema_name,"$user",public; -SCHEMA = -; For Postgres, either "disable" (default), "require", or "verify-full" -; For MySQL, either "false" (default), "true", or "skip-verify" -SSL_MODE = disable -; For MySQL only, either "utf8" or "utf8mb4", default is "utf8". -; NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this. -CHARSET = utf8 -; For "sqlite3" and "tidb", use an absolute path when you start gitea as service -PATH = data/gitea.db -; For "sqlite3" only. Query timeout -SQLITE_TIMEOUT = 500 -; For iterate buffer, default is 50 -ITERATE_BUFFER_SIZE = 50 -; Show the database generated SQL -LOG_SQL = true -; Maximum number of DB Connect retries -DB_RETRIES = 10 -; Backoff time per DB retry (time.Duration) -DB_RETRY_BACKOFF = 3s -; Max idle database connections on connnection pool, default is 2 -MAX_IDLE_CONNS = 2 -; Database connection max life time, default is 0 or 3s mysql (See #6804 & #7071 for reasoning) -CONN_MAX_LIFETIME = 3s -; Database maximum number of open connections, default is 0 meaning no maximum -MAX_OPEN_CONNS = 0 - -[indexer] -; Issue indexer type, currently support: bleve, db or elasticsearch, default is bleve -ISSUE_INDEXER_TYPE = bleve -; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch -ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200 -; Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch -ISSUE_INDEXER_NAME = gitea_issues -; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve -ISSUE_INDEXER_PATH = indexers/issues.bleve -; Issue indexer queue, currently support: channel, levelqueue or redis, default is levelqueue -ISSUE_INDEXER_QUEUE_TYPE = levelqueue -; When ISSUE_INDEXER_QUEUE_TYPE is levelqueue, this will be the queue will be saved path, -; default is indexers/issues.queue -ISSUE_INDEXER_QUEUE_DIR = indexers/issues.queue -; When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string. -ISSUE_INDEXER_QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0" -; Batch queue number, default is 20 -ISSUE_INDEXER_QUEUE_BATCH_NUMBER = 20 -; Timeout the indexer if it takes longer than this to start. -; Set to zero to disable timeout. -STARTUP_TIMEOUT=30s - -; repo indexer by default disabled, since it uses a lot of disk space -REPO_INDEXER_ENABLED = false -REPO_INDEXER_PATH = indexers/repos.bleve -UPDATE_BUFFER_LEN = 20 -MAX_FILE_SIZE = 1048576 -; A comma separated list of glob patterns (see https://github.com/gobwas/glob) to include -; in the index; default is empty -REPO_INDEXER_INCLUDE = -; A comma separated list of glob patterns to exclude from the index; ; default is empty -REPO_INDEXER_EXCLUDE = - -[queue] -; Specific queues can be individually configured with [queue.name]. [queue] provides defaults -; -; General queue queue type, currently support: persistable-channel, channel, level, redis, dummy -; default to persistable-channel -TYPE = persistable-channel -; data-dir for storing persistable queues and level queues, individual queues will be named by their type -DATADIR = queues/ -; Default queue length before a channel queue will block -LENGTH = 20 -; Batch size to send for batched queues -BATCH_LENGTH = 20 -; Connection string for redis queues this will store the redis connection string. -CONN_STR = "addrs=127.0.0.1:6379 db=0" -; Provide the suffix of the default redis queue name - specific queues can be overriden within in their [queue.name] sections. -QUEUE_NAME = "_queue" -; If the queue cannot be created at startup - level queues may need a timeout at startup - wrap the queue: -WRAP_IF_NECESSARY = true -; Attempt to create the wrapped queue at max -MAX_ATTEMPTS = 10 -; Timeout queue creation -TIMEOUT = 15m30s -; Create a pool with this many workers -WORKERS = 1 -; Dynamically scale the worker pool to at this many workers -MAX_WORKERS = 10 -; Add boost workers when the queue blocks for BLOCK_TIMEOUT -BLOCK_TIMEOUT = 1s -; Remove the boost workers after BOOST_TIMEOUT -BOOST_TIMEOUT = 5m -; During a boost add BOOST_WORKERS -BOOST_WORKERS = 5 - -[admin] -; Disallow regular (non-admin) users from creating organizations. -DISABLE_REGULAR_ORG_CREATION = false -; Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled -DEFAULT_EMAIL_NOTIFICATIONS = enabled - -[security] -; Whether the installer is disabled -INSTALL_LOCK = false -; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!! -SECRET_KEY = !#@FDEWREWR&*( -; How long to remember that a user is logged in before requiring relogin (in days) -LOGIN_REMEMBER_DAYS = 7 -COOKIE_USERNAME = gitea_awesome -COOKIE_REMEMBER_NAME = gitea_incredible -; Reverse proxy authentication header name of user name -REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER -REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL -; The minimum password length for new Users -MIN_PASSWORD_LENGTH = 6 -; Set to true to allow users to import local server paths -IMPORT_LOCAL_PATHS = false -; Set to true to prevent all users (including admin) from creating custom git hooks -DISABLE_GIT_HOOKS = false -; Set to false to allow pushes to gitea repositories despite having an incomplete environment - NOT RECOMMENDED -ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET = true -;Comma separated list of character classes required to pass minimum complexity. -;If left empty or no valid values are specified, the default values ("lower,upper,digit,spec") will be used. -;Use "off" to disable checking. -PASSWORD_COMPLEXITY = lower,upper,digit,spec -; Password Hash algorithm, either "pbkdf2", "argon2", "scrypt" or "bcrypt" -PASSWORD_HASH_ALGO = pbkdf2 -; Set false to allow JavaScript to read CSRF cookie -CSRF_COOKIE_HTTP_ONLY = true - -[openid] -; -; OpenID is an open, standard and decentralized authentication protocol. -; Your identity is the address of a webpage you provide, which describes -; how to prove you are in control of that page. -; -; For more info: https://en.wikipedia.org/wiki/OpenID -; -; Current implementation supports OpenID-2.0 -; -; Tested to work providers at the time of writing: -; - Any GNUSocial node (your.hostname.tld/username) -; - Any SimpleID provider (http://simpleid.koinic.net) -; - http://openid.org.cn/ -; - openid.stackexchange.com -; - login.launchpad.net -; - .livejournal.com -; -; Whether to allow signin in via OpenID -ENABLE_OPENID_SIGNIN = true -; Whether to allow registering via OpenID -; Do not include to rely on rhw DISABLE_REGISTRATION setting -;ENABLE_OPENID_SIGNUP = true -; Allowed URI patterns (POSIX regexp). -; Space separated. -; Only these would be allowed if non-blank. -; Example value: trusted.domain.org trusted.domain.net -WHITELISTED_URIS = -; Forbidden URI patterns (POSIX regexp). -; Space separated. -; Only used if WHITELISTED_URIS is blank. -; Example value: loadaverage.org/badguy stackexchange.com/.*spammer -BLACKLISTED_URIS = - -[service] -; Time limit to confirm account/email registration -ACTIVE_CODE_LIVE_MINUTES = 180 -; Time limit to perform the reset of a forgotten password -RESET_PASSWD_CODE_LIVE_MINUTES = 180 -; Whether a new user needs to confirm their email when registering. -REGISTER_EMAIL_CONFIRM = false -; List of domain names that are allowed to be used to register on a Gitea instance -; gitea.io,example.com -EMAIL_DOMAIN_WHITELIST= -; Disallow registration, only allow admins to create accounts. -DISABLE_REGISTRATION = false -; Allow registration only using third-party services, it works only when DISABLE_REGISTRATION is false -ALLOW_ONLY_EXTERNAL_REGISTRATION = false -; User must sign in to view anything. -REQUIRE_SIGNIN_VIEW = false -; Mail notification -ENABLE_NOTIFY_MAIL = false -; This setting enables gitea to be signed in with HTTP BASIC Authentication using the user's password -; If you set this to false you will not be able to access the tokens endpoints on the API with your password -; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token -ENABLE_BASIC_AUTHENTICATION = true -; More detail: https://github.com/gogits/gogs/issues/165 -ENABLE_REVERSE_PROXY_AUTHENTICATION = false -ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false -ENABLE_REVERSE_PROXY_EMAIL = false -; Enable captcha validation for registration -ENABLE_CAPTCHA = false -; Type of captcha you want to use. Options: image, recaptcha -CAPTCHA_TYPE = image -; Enable recaptcha to use Google's recaptcha service -; Go to https://www.google.com/recaptcha/admin to sign up for a key -RECAPTCHA_SECRET = -RECAPTCHA_SITEKEY = -; Change this to use recaptcha.net or other recaptcha service -RECAPTCHA_URL = https://www.google.com/recaptcha/ -; Default value for KeepEmailPrivate -; Each new user will get the value of this setting copied into their profile -DEFAULT_KEEP_EMAIL_PRIVATE = false -; Default value for AllowCreateOrganization -; Every new user will have rights set to create organizations depending on this setting -DEFAULT_ALLOW_CREATE_ORGANIZATION = true -; Either "public", "limited" or "private", default is "public" -; Limited is for signed user only -; Private is only for member of the organization -; Public is for everyone -DEFAULT_ORG_VISIBILITY = public -; Default value for DefaultOrgMemberVisible -; True will make the membership of the users visible when added to the organisation -DEFAULT_ORG_MEMBER_VISIBLE = false -; Default value for EnableDependencies -; Repositories will use dependencies by default depending on this setting -DEFAULT_ENABLE_DEPENDENCIES = true -; Dependencies can be added from any repository where the user is granted access or only from the current repository depending on this setting. -ALLOW_CROSS_REPOSITORY_DEPENDENCIES = true -; Enable heatmap on users profiles. -ENABLE_USER_HEATMAP = true -; Enable Timetracking -ENABLE_TIMETRACKING = true -; Default value for EnableTimetracking -; Repositories will use timetracking by default depending on this setting -DEFAULT_ENABLE_TIMETRACKING = true -; Default value for AllowOnlyContributorsToTrackTime -; Only users with write permissions can track time if this is true -DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME = true -; Default value for the domain part of the user's email address in the git log -; if he has set KeepEmailPrivate to true. The user's email will be replaced with a -; concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS. -NO_REPLY_ADDRESS = noreply.%(DOMAIN)s -; Show Registration button -SHOW_REGISTRATION_BUTTON = true -; Show milestones dashboard page - a view of all the user's milestones -SHOW_MILESTONES_DASHBOARD_PAGE = true -; Default value for AutoWatchNewRepos -; When adding a repo to a team or creating a new repo all team members will watch the -; repo automatically if enabled -AUTO_WATCH_NEW_REPOS = true -; Default value for AutoWatchOnChanges -; Make the user watch a repository When they commit for the first time -AUTO_WATCH_ON_CHANGES = false - -[webhook] -; Hook task queue length, increase if webhook shooting starts hanging -QUEUE_LENGTH = 1000 -; Deliver timeout in seconds -DELIVER_TIMEOUT = 5 -; Allow insecure certification -SKIP_TLS_VERIFY = false -; Number of history information in each page -PAGING_NUM = 10 -; Proxy server URL, support http://, https//, socks://, blank will follow environment http_proxy/https_proxy -PROXY_URL = -; Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts. -PROXY_HOSTS = - -[mailer] -ENABLED = false -; Buffer length of channel, keep it as it is if you don't know what it is. -SEND_BUFFER_LEN = 100 -; Prefix displayed before subject in mail -SUBJECT_PREFIX = -; Mail server -; Gmail: smtp.gmail.com:587 -; QQ: smtp.qq.com:465 -; Using STARTTLS on port 587 is recommended per RFC 6409. -; Note, if the port ends with "465", SMTPS will 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. -HELO_HOSTNAME = -; Do not verify the certificate of the server. Only use this for self-signed certificates -SKIP_VERIFY = -; Use client certificate -USE_CERTIFICATE = false -CERT_FILE = custom/mailer/cert.pem -KEY_FILE = custom/mailer/key.pem -; 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 -; Mail from address, RFC 5322. This can be just an email address, or the `"Name" ` format -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`. -USER = -; Use PASSWD = `your password` for quoting if you use special characters in the password. -PASSWD = -; Send mails as plain text -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 -; Specify any extra sendmail arguments -SENDMAIL_ARGS = -; Timeout for Sendmail -SENDMAIL_TIMEOUT = 5m - -[cache] -; if the cache enabled -ENABLED = true -; Either "memory", "redis", or "memcache", default is "memory" -ADAPTER = memory -; For "memory" only, GC interval in seconds, default is 60 -INTERVAL = 60 -; For "redis" and "memcache", connection host address -; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180 -; memcache: `127.0.0.1:11211` -HOST = -; Time to keep items in cache if not used, default is 16 hours. -; Setting it to 0 disables caching -ITEM_TTL = 16h - -; Last commit cache -[cache.last_commit] -; if the cache enabled -ENABLED = true -; Time to keep items in cache if not used, default is 8760 hours. -; Setting it to 0 disables caching -ITEM_TTL = 8760h -; Only enable the cache when repository's commits count great than -COMMITS_COUNT = 1000 - -[session] -; Either "memory", "file", or "redis", default is "memory" -PROVIDER = memory -; Provider config options -; memory: doesn't have any config yet -; file: session file path, e.g. `data/sessions` -; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180 -; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table` -PROVIDER_CONFIG = data/sessions -; Session cookie name -COOKIE_NAME = i_like_gitea -; If you use session in https only, default is false -COOKIE_SECURE = false -; Enable set cookie, default is true -ENABLE_SET_COOKIE = true -; Session GC time interval in seconds, default is 86400 (1 day) -GC_INTERVAL_TIME = 86400 -; Session life time in seconds, default is 86400 (1 day) -SESSION_LIFE_TIME = 86400 - -[picture] -AVATAR_UPLOAD_PATH = data/avatars -REPOSITORY_AVATAR_UPLOAD_PATH = data/repo-avatars -; How Gitea deals with missing repository avatars -; none = no avatar will be displayed; random = random avatar will be displayed; image = default image will be used -REPOSITORY_AVATAR_FALLBACK = none -REPOSITORY_AVATAR_FALLBACK_IMAGE = /img/repo_default.png -; Max Width and Height of uploaded avatars. -; This is to limit the amount of RAM used when resizing the image. -AVATAR_MAX_WIDTH = 4096 -AVATAR_MAX_HEIGHT = 3072 -; Maximum alloved file size for uploaded avatars. -; This is to limit the amount of RAM used when resizing the image. -AVATAR_MAX_FILE_SIZE = 1048576 -; Chinese users can choose "duoshuo" -; or a custom avatar source, like: http://cn.gravatar.com/avatar/ -GRAVATAR_SOURCE = gravatar -; This value will always be true in offline mode. -DISABLE_GRAVATAR = false -; Federated avatar lookup uses DNS to discover avatar associated -; with emails, see https://www.libravatar.org -; This value will always be false in offline mode or when Gravatar is disabled. -ENABLE_FEDERATED_AVATAR = false - -[attachment] -; Whether attachments are enabled. Defaults to `true` -ENABLED = true -; Path for attachments. Defaults to `data/attachments` -PATH = data/attachments -; One or more allowed types, e.g. "image/jpeg|image/png". Use "*/*" for all types. -ALLOWED_TYPES = image/jpeg|image/png|application/zip|application/gzip -; Max size of each file. Defaults to 4MB -MAX_SIZE = 4 -; Max number of files per upload. Defaults to 5 -MAX_FILES = 5 - -[time] -; Specifies the format for fully outputted dates. Defaults to RFC1123 -; Special supported values are ANSIC, UnixDate, RubyDate, RFC822, RFC822Z, RFC850, RFC1123, RFC1123Z, RFC3339, RFC3339Nano, Kitchen, Stamp, StampMilli, StampMicro and StampNano -; For more information about the format see http://golang.org/pkg/time/#pkg-constants -FORMAT = -; Location the UI time display i.e. Asia/Shanghai -; Empty means server's location setting -DEFAULT_UI_LOCATION = - -[log] -ROOT_PATH = -; Either "console", "file", "conn", "smtp" or "database", default is "console" -; Use comma to separate multiple modes, e.g. "console, file" -MODE = console -; Buffer length of the channel, keep it as it is if you don't know what it is. -BUFFER_LEN = 10000 -REDIRECT_MACARON_LOG = false -MACARON = file -; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Info" -ROUTER_LOG_LEVEL = Info -ROUTER = console -ENABLE_ACCESS_LOG = false -ACCESS_LOG_TEMPLATE = {{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}" -ACCESS = file -; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace" -LEVEL = Info -; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "None" -STACKTRACE_LEVEL = None - -; Generic log modes -[log.x] -FLAGS = stdflags -EXPRESSION = -PREFIX = -COLORIZE = false - -; For "console" mode only -[log.console] -LEVEL = -STDERR = false - -; For "file" mode only -[log.file] -LEVEL = -; Set the file_name for the logger. If this is a relative path this -; will be relative to ROOT_PATH -FILE_NAME = -; This enables automated log rotate(switch of following options), default is true -LOG_ROTATE = true -; Max number of lines in a single file, default is 1000000 -MAX_LINES = 1000000 -; Max size shift of a single file, default is 28 means 1 << 28, 256MB -MAX_SIZE_SHIFT = 28 -; Segment log daily, default is true -DAILY_ROTATE = true -; delete the log file after n days, default is 7 -MAX_DAYS = 7 -; compress logs with gzip -COMPRESS = true -; compression level see godoc for compress/gzip -COMPRESSION_LEVEL = -1 - -; For "conn" mode only -[log.conn] -LEVEL = -; Reconnect host for every single message, default is false -RECONNECT_ON_MSG = false -; Try to reconnect when connection is lost, default is false -RECONNECT = false -; Either "tcp", "unix" or "udp", default is "tcp" -PROTOCOL = tcp -; Host address -ADDR = - -; For "smtp" mode only -[log.smtp] -LEVEL = -; Name displayed in mail title, default is "Diagnostic message from server" -SUBJECT = Diagnostic message from server -; Mail server -HOST = -; Mailer user name and password -USER = -; Use PASSWD = `your password` for quoting if you use special characters in the password. -PASSWD = -; Receivers, can be one or more, e.g. 1@example.com,2@example.com -RECEIVERS = - -[cron] -; Enable running cron tasks periodically. -ENABLED = true -; Run cron tasks when Gitea starts. -RUN_AT_START = false - -; Update mirrors -[cron.update_mirrors] -SCHEDULE = @every 10m - -; Repository health check -[cron.repo_health_check] -SCHEDULE = @every 24h -TIMEOUT = 60s -; Arguments for command 'git fsck', e.g. "--unreachable --tags" -; see more on http://git-scm.com/docs/git-fsck -ARGS = - -; Check repository statistics -[cron.check_repo_stats] -RUN_AT_START = true -SCHEDULE = @every 24h - -; Clean up old repository archives -[cron.archive_cleanup] -; Whether to enable the job -ENABLED = true -; Whether to always run at least once at start up time (if ENABLED) -RUN_AT_START = true -; Time interval for job to run -SCHEDULE = @every 24h -; Archives created more than OLDER_THAN ago are subject to deletion -OLDER_THAN = 24h - -; Synchronize external user data (only LDAP user synchronization is supported) -[cron.sync_external_users] -; Synchronize external user data when starting server (default false) -RUN_AT_START = false -; Interval as a duration between each synchronization (default every 24h) -SCHEDULE = @every 24h -; Create new users, update existing user data and disable users that are not in external source anymore (default) -; or only create new users if UPDATE_EXISTING is set to false -UPDATE_EXISTING = true - -; Update migrated repositories' issues and comments' posterid, it will always attempt synchronization when the instance starts. -[cron.update_migration_poster_id] -; Interval as a duration between each synchronization. (default every 24h) -SCHEDULE = @every 24h - -[git] -; The path of git executable. If empty, Gitea searches through the PATH environment. -PATH = -; Disables highlight of added and removed changes -DISABLE_DIFF_HIGHLIGHT = false -; Max number of lines allowed in a single file in diff view -MAX_GIT_DIFF_LINES = 1000 -; Max number of allowed characters in a line in diff view -MAX_GIT_DIFF_LINE_CHARACTERS = 5000 -; Max number of files shown in diff view -MAX_GIT_DIFF_FILES = 100 -; Arguments for command 'git gc', e.g. "--aggressive --auto" -; see more on http://git-scm.com/docs/git-gc/ -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 -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) -PULL_REQUEST_PUSH_MESSAGE = true - -; Operation timeout in seconds -[git.timeout] -DEFAULT = 360 -MIGRATE = 600 -MIRROR = 300 -CLONE = 300 -PULL = 300 -GC = 60 - -[mirror] -; Default interval as a duration between each check -DEFAULT_INTERVAL = 8h -; Min interval as a duration must be > 1m -MIN_INTERVAL = 10m - -[api] -; Enables Swagger. True or false; default is true. -ENABLE_SWAGGER = true -; Max number of items in a page -MAX_RESPONSE_ITEMS = 50 -; Default paging number of api -DEFAULT_PAGING_NUM = 30 -; Default and maximum number of items per page for git trees api -DEFAULT_GIT_TREES_PER_PAGE = 1000 -; Default size of a blob returned by the blobs API (default is 10MiB) -DEFAULT_MAX_BLOB_SIZE = 10485760 - -[oauth2] -; Enables OAuth2 provider -ENABLE = true -; Lifetime of an OAuth2 access token in seconds -ACCESS_TOKEN_EXPIRATION_TIME=3600 -; Lifetime of an OAuth2 access token in hours -REFRESH_TOKEN_EXPIRATION_TIME=730 -; Check if refresh token got already used -INVALIDATE_REFRESH_TOKENS=false -; OAuth2 authentication secret for access and refresh tokens, change this to a unique string. -JWT_SECRET=Bk0yK7Y9g_p56v86KaHqjSbxvNvu3SbKoOdOt2ZcXvU -; Maximum length of oauth2 token/cookie stored on server -MAX_TOKEN_LENGTH=32767 - -[i18n] -LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR -NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,Українська,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어 - -; Used for datetimepicker -[i18n.datelang] -en-US = en -zh-CN = zh -zh-HK = zh-HK -zh-TW = zh-TW -de-DE = de -fr-FR = fr -nl-NL = nl -lv-LV = lv -ru-RU = ru -uk-UA = uk -ja-JP = ja -es-ES = es -pt-BR = pt-BR -pt-PT = pt -pl-PL = pl -bg-BG = bg -it-IT = it -fi-FI = fi -tr-TR = tr -cs-CZ = cs-CZ -sr-SP = sr -sv-SE = sv -ko-KR = ko - -[U2F] -; NOTE: THE DEFAULT VALUES HERE WILL NEED TO BE CHANGED -; Two Factor authentication with security keys -; https://developers.yubico.com/U2F/App_ID.html -;APP_ID = http://localhost:3000/ -; Comma seperated list of trusted facets -;TRUSTED_FACETS = http://localhost:3000/ - -; Extension mapping to highlight class -; e.g. .toml=ini -[highlight.mapping] - -[other] -SHOW_FOOTER_BRANDING = false -; Show version information about Gitea and Go in the footer -SHOW_FOOTER_VERSION = true -; Show template execution time in the footer -SHOW_FOOTER_TEMPLATE_LOAD_TIME = true - -[markup.sanitizer.1] -; The following keys can appear once to define a sanitation policy rule. -; This section can appear multiple times by adding a unique alphanumeric suffix to define multiple rules. -; e.g., [markup.sanitizer.1] -> [markup.sanitizer.2] -> [markup.sanitizer.TeX] -;ELEMENT = span -;ALLOW_ATTR = class -;REGEXP = ^(info|warning|error)$ - -[markup.asciidoc] -ENABLED = false -; List of file extensions that should be rendered by an external command -FILE_EXTENSIONS = .adoc,.asciidoc -; External command to render all matching extensions -RENDER_COMMAND = "asciidoc --out-file=- -" -; Don't pass the file on STDIN, pass the filename as argument instead. -IS_INPUT_FILE = false - -[metrics] -; Enables metrics endpoint. True or false; default is false. -ENABLED = false -; If you want to add authorization, specify a token here -TOKEN = - -[task] -; Task queue type, could be `channel` or `redis`. -QUEUE_TYPE = channel -; Task queue length, available only when `QUEUE_TYPE` is `channel`. -QUEUE_LENGTH = 1000 -; Task queue connection string, available only when `QUEUE_TYPE` is `redis`. -; If there is a password of redis, use `addrs=127.0.0.1:6379 password=123 db=0`. -QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0" - -[migrations] -; Max attempts per http/https request on migrations. -MAX_ATTEMPTS = 3 -; Backoff time per http/https request retry (seconds) -RETRY_BACKOFF = 3 diff --git a/docker/Makefile b/docker/Makefile deleted file mode 100644 index bd4cb176bdbdb..0000000000000 --- a/docker/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -#Makefile related to docker - -DOCKER_IMAGE ?= gitea/gitea -DOCKER_TAG ?= latest -DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG) - -.PHONY: docker -docker: - docker build --disable-content-trust=false -t $(DOCKER_REF) . -# support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" . - -.PHONY: docker-build -docker-build: - docker run -ti --rm -v $(CURDIR):/srv/app/src/code.gitea.io/gitea -w /srv/app/src/code.gitea.io/gitea -e TAGS="bindata $(TAGS)" LDFLAGS="$(LDFLAGS)" CGO_EXTRA_CFLAGS="$(CGO_EXTRA_CFLAGS)" webhippie/golang:edge make clean build diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000000000..ef05032ee6f37 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,7 @@ +# Gitea - Docker + +Dockerfile is found in root of repository. + +Docker image can be found on [docker hub](https://hub.docker.com/r/gitea/gitea) + +Documentation on using docker image can be found on [Gitea Docs site](https://docs.gitea.io/en-us/install-with-docker/) diff --git a/docker/manifest.rootless.tmpl b/docker/manifest.rootless.tmpl new file mode 100644 index 0000000000000..aed36caa4e877 --- /dev/null +++ b/docker/manifest.rootless.tmpl @@ -0,0 +1,19 @@ +image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}-rootless +{{#if build.tags}} +tags: +{{#each build.tags}} + - {{this}}-rootless +{{/each}} +{{/if}} +manifests: + - + image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64-rootless + platform: + architecture: amd64 + os: linux + - + image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64-rootless + platform: + architecture: arm64 + os: linux + variant: v8 diff --git a/docker/root/etc/s6/gitea/run b/docker/root/etc/s6/gitea/run index da5fd6b535ef6..b6150c10d5fa3 100755 --- a/docker/root/etc/s6/gitea/run +++ b/docker/root/etc/s6/gitea/run @@ -1,6 +1,6 @@ #!/bin/bash [[ -f ./setup ]] && source ./setup -pushd /app/gitea > /dev/null - exec su-exec $USER /app/gitea/gitea web +pushd /app/gitea >/dev/null +exec su-exec $USER /app/gitea/gitea web popd diff --git a/docker/root/etc/s6/gitea/setup b/docker/root/etc/s6/gitea/setup index 892fa7fd2bd17..4449420b99ce7 100755 --- a/docker/root/etc/s6/gitea/setup +++ b/docker/root/etc/s6/gitea/setup @@ -25,7 +25,7 @@ if [ ! -f ${GITEA_CUSTOM}/conf/app.ini ]; then # Substitude the environment variables in the template APP_NAME=${APP_NAME:-"Gitea: Git with a cup of tea"} \ - RUN_MODE=${RUN_MODE:-"dev"} \ + RUN_MODE=${RUN_MODE:-"prod"} \ DOMAIN=${DOMAIN:-"localhost"} \ SSH_DOMAIN=${SSH_DOMAIN:-"localhost"} \ HTTP_PORT=${HTTP_PORT:-"3000"} \ diff --git a/docker/root/etc/s6/openssh/run b/docker/root/etc/s6/openssh/run index 63950248250fc..a40b5b113f407 100755 --- a/docker/root/etc/s6/openssh/run +++ b/docker/root/etc/s6/openssh/run @@ -1,6 +1,6 @@ #!/bin/bash [[ -f ./setup ]] && source ./setup -pushd /root > /dev/null - exec su-exec root /usr/sbin/sshd -D -e 2>&1 +pushd /root >/dev/null +exec su-exec root /usr/sbin/sshd -D -e 2>&1 popd diff --git a/docker/root/etc/templates/app.ini b/docker/root/etc/templates/app.ini index 9b23c1270d4da..1a831a6d10eed 100644 --- a/docker/root/etc/templates/app.ini +++ b/docker/root/etc/templates/app.ini @@ -29,6 +29,7 @@ HOST = $DB_HOST NAME = $DB_NAME USER = $DB_USER PASSWD = $DB_PASSWD +LOG_SQL = false [indexer] ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve @@ -44,6 +45,11 @@ REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars PATH = /data/gitea/attachments [log] +MODE = console +LEVEL = info +REDIRECT_MACARON_LOG = true +MACARON = console +ROUTER = console ROOT_PATH = /data/gitea/log [security] diff --git a/docker/root/etc/templates/sshd_config b/docker/root/etc/templates/sshd_config index 20e0b36012c91..26e26feb4127a 100644 --- a/docker/root/etc/templates/sshd_config +++ b/docker/root/etc/templates/sshd_config @@ -8,11 +8,18 @@ ListenAddress :: LogLevel INFO HostKey /data/ssh/ssh_host_ed25519_key +HostCertificate /data/ssh/ssh_host_ed25519_cert HostKey /data/ssh/ssh_host_rsa_key -HostKey /data/ssh/ssh_host_dsa_key +HostCertificate /data/ssh/ssh_host_rsa_cert HostKey /data/ssh/ssh_host_ecdsa_key +HostCertificate /data/ssh/ssh_host_ecdsa_cert +HostKey /data/ssh/ssh_host_dsa_key +HostCertificate /data/ssh/ssh_host_dsa_cert AuthorizedKeysFile .ssh/authorized_keys +AuthorizedPrincipalsFile .ssh/authorized_principals +TrustedUserCAKeys /data/git/.ssh/gitea-trusted-user-ca-keys.pem +CASignatureAlgorithms ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ecdsa-sha2-nistp256@openssh.com,ssh-ed25519,sk-ssh-ed25519@openssh.com,rsa-sha2-512,rsa-sha2-256,ssh-rsa UseDNS no AllowAgentForwarding no diff --git a/docker/rootless/etc/templates/app.ini b/docker/rootless/etc/templates/app.ini new file mode 100644 index 0000000000000..92755575b989e --- /dev/null +++ b/docker/rootless/etc/templates/app.ini @@ -0,0 +1,55 @@ +APP_NAME = $APP_NAME +RUN_USER = $RUN_USER +RUN_MODE = $RUN_MODE + +[repository] +ROOT = $GITEA_WORK_DIR/git/repositories + +[repository.local] +LOCAL_COPY_PATH = $GITEA_TEMP/local-repo + +[repository.upload] +TEMP_PATH = $GITEA_TEMP/uploads + +[server] +APP_DATA_PATH = $GITEA_WORK_DIR +SSH_DOMAIN = $SSH_DOMAIN +HTTP_PORT = $HTTP_PORT +ROOT_URL = $ROOT_URL +DISABLE_SSH = $DISABLE_SSH +; In rootless gitea container only internal ssh server is supported +START_SSH_SERVER = true +SSH_PORT = $SSH_PORT +SSH_LISTEN_PORT = $SSH_LISTEN_PORT +BUILTIN_SSH_SERVER_USER = $RUN_USER +LFS_START_SERVER = $LFS_START_SERVER +LFS_CONTENT_PATH = $GITEA_WORK_DIR/git/lfs + +[database] +PATH = $GITEA_WORK_DIR/data/gitea.db +DB_TYPE = $DB_TYPE +HOST = $DB_HOST +NAME = $DB_NAME +USER = $DB_USER +PASSWD = $DB_PASSWD + +[session] +PROVIDER_CONFIG = $GITEA_WORK_DIR/data/sessions + +[picture] +AVATAR_UPLOAD_PATH = $GITEA_WORK_DIR/data/avatars +REPOSITORY_AVATAR_UPLOAD_PATH = $GITEA_WORK_DIR/data/gitea/repo-avatars + +[attachment] +PATH = $GITEA_WORK_DIR/data/attachments + +[log] +ROOT_PATH = $GITEA_WORK_DIR/data/log + +[security] +INSTALL_LOCK = $INSTALL_LOCK +SECRET_KEY = $SECRET_KEY + +[service] +DISABLE_REGISTRATION = $DISABLE_REGISTRATION +REQUIRE_SIGNIN_VIEW = $REQUIRE_SIGNIN_VIEW diff --git a/docker/rootless/usr/local/bin/docker-entrypoint.sh b/docker/rootless/usr/local/bin/docker-entrypoint.sh new file mode 100755 index 0000000000000..d05777adc5645 --- /dev/null +++ b/docker/rootless/usr/local/bin/docker-entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ -x /usr/local/bin/docker-setup.sh ]; then + /usr/local/bin/docker-setup.sh || { echo 'docker setup failed' ; exit 1; } +fi + +if [ $# -gt 0 ]; then + exec "$@" +else + exec /usr/local/bin/gitea -c ${GITEA_APP_INI} web +fi diff --git a/docker/rootless/usr/local/bin/docker-setup.sh b/docker/rootless/usr/local/bin/docker-setup.sh new file mode 100755 index 0000000000000..9764ff3c59729 --- /dev/null +++ b/docker/rootless/usr/local/bin/docker-setup.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# Prepare git folder +mkdir -p ${HOME} && chmod 0700 ${HOME} +if [ ! -w ${HOME} ]; then echo "${HOME} is not writable"; exit 1; fi + +# Prepare custom folder +mkdir -p ${GITEA_CUSTOM} && chmod 0500 ${GITEA_CUSTOM} + +# Prepare temp folder +mkdir -p ${GITEA_TEMP} && chmod 0700 ${GITEA_TEMP} +if [ ! -w ${GITEA_TEMP} ]; then echo "${GITEA_TEMP} is not writable"; exit 1; fi + +#Prepare config file +if [ ! -f ${GITEA_APP_INI} ]; then + + #Prepare config file folder + GITEA_APP_INI_DIR=$(dirname ${GITEA_APP_INI}) + mkdir -p ${GITEA_APP_INI_DIR} && chmod 0700 ${GITEA_APP_INI_DIR} + if [ ! -w ${GITEA_APP_INI_DIR} ]; then echo "${GITEA_APP_INI_DIR} is not writable"; exit 1; fi + + # Set INSTALL_LOCK to true only if SECRET_KEY is not empty and + # INSTALL_LOCK is empty + if [ -n "$SECRET_KEY" ] && [ -z "$INSTALL_LOCK" ]; then + INSTALL_LOCK=true + fi + + # Substitude the environment variables in the template + APP_NAME=${APP_NAME:-"Gitea: Git with a cup of tea"} \ + RUN_MODE=${RUN_MODE:-"prod"} \ + RUN_USER=${USER:-"git"} \ + SSH_DOMAIN=${SSH_DOMAIN:-"localhost"} \ + HTTP_PORT=${HTTP_PORT:-"3000"} \ + ROOT_URL=${ROOT_URL:-""} \ + DISABLE_SSH=${DISABLE_SSH:-"false"} \ + SSH_PORT=${SSH_PORT:-"2222"} \ + SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-$SSH_PORT} \ + DB_TYPE=${DB_TYPE:-"sqlite3"} \ + DB_HOST=${DB_HOST:-"localhost:3306"} \ + DB_NAME=${DB_NAME:-"gitea"} \ + DB_USER=${DB_USER:-"root"} \ + DB_PASSWD=${DB_PASSWD:-""} \ + INSTALL_LOCK=${INSTALL_LOCK:-"false"} \ + DISABLE_REGISTRATION=${DISABLE_REGISTRATION:-"false"} \ + REQUIRE_SIGNIN_VIEW=${REQUIRE_SIGNIN_VIEW:-"false"} \ + SECRET_KEY=${SECRET_KEY:-""} \ + envsubst < /etc/templates/app.ini > ${GITEA_APP_INI} +fi diff --git a/docs/.editorconfig b/docs/.editorconfig deleted file mode 100644 index 17581eef54622..0000000000000 --- a/docs/.editorconfig +++ /dev/null @@ -1,34 +0,0 @@ -# http://editorconfig.org - -root = true - -[*] -charset = utf-8 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.go] -indent_style = tab -indent_size = 8 - -[*.{tmpl,html}] -indent_style = tab -indent_size = 4 - -[*.{less}] -indent_style = space -indent_size = 4 - -[*.{yml}] -indent_style = space -indent_size = 2 - -[*.js] -indent_style = space -indent_size = 4 - -[Makefile] -indent_style = tab - -[*.md] -trim_trailing_whitespace = false diff --git a/docs/Makefile b/docs/Makefile index 78de2d396f9ea..487e16cf6fc27 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -21,6 +21,10 @@ server: $(THEME) build: $(THEME) hugo --cleanDestinationDir +.PHONY: build-offline +build-offline: $(THEME) + hugo --baseURL="/" --cleanDestinationDir + .PHONY: update update: $(THEME) diff --git a/docs/config.yaml b/docs/config.yaml index 9f83a0a2d0f9c..d8282bb93571e 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -18,9 +18,9 @@ params: description: Git with a cup of tea author: The Gitea Authors website: https://docs.gitea.io - version: 1.11.6 - minGoVersion: 1.12 - goVersion: 1.14 + version: 1.13.1 + minGoVersion: 1.13 + goVersion: 1.15 minNodeVersion: 10.13 outputs: @@ -48,10 +48,10 @@ menu: url: https://blog.gitea.io/ weight: 30 pre: rss - - name: Code - url: https://code.gitea.io/ + - name: Shop + url: https://shop.gitea.io/ weight: 40 - pre: code + pre: shopping-cart - name: Translation url: https://crowdin.com/project/gitea weight: 41 @@ -359,3 +359,50 @@ languages: url: https://discourse.gitea.io/ weight: 80 pre: group + + de-de: + weight: 7 + languageName: Deutsch + menu: + page: + - name: Webseite + url: https://gitea.io/en-us/ + weight: 10 + pre: home + post: active + - name: Dokumentation + url: /de-de/ + weight: 20 + pre: question + - name: API + url: https://try.gitea.io/api/swagger + weight: 45 + pre: plug + - name: Blog + url: https://blog.gitea.io/ + weight: 30 + pre: rss + - name: Code + url: https://code.gitea.io/ + weight: 40 + pre: code + - name: Übersetzung + url: https://crowdin.com/project/gitea + weight: 41 + pre: language + - name: Downloads + url: https://dl.gitea.io/ + weight: 50 + pre: download + - name: GitHub + url: https://github.com/go-gitea/ + weight: 60 + pre: github + - name: Discord Chat + url: https://discord.gg/Gitea + weight: 70 + pre: comment + - name: Forum + url: https://discourse.gitea.io/ + weight: 80 + pre: group diff --git a/docs/content/doc/advanced/ci-cd.en-us.md b/docs/content/doc/advanced/ci-cd.en-us.md deleted file mode 100644 index 7b69d851bd399..0000000000000 --- a/docs/content/doc/advanced/ci-cd.en-us.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -date: "2019-08-27:00:00+02:00" -title: "CI/CD Usage" -slug: "ci-cd" -weight: 40 -toc: true -draft: false -menu: - sidebar: - parent: "advanced" - name: "CI/CD Usage" - weight: 40 - identifier: "ci-cd" ---- - -# Gitea and CI/CD -**NOTE:** These tools are not endorsed by Gitea. They are listed here for convenience only. - -## Hey! This page may be out of date or even removed in the future! :scream: -Instead, check out [awesome-gitea](https://gitea.com/gitea/awesome-gitea/src/branch/master/README.md#user-content-devops)! - -## Listing - -CI/CD solutions that have integration with Gitea. Following list is not complete, -the purpose is to give a starting point to integrate a CI/CD process with your Gitea instance. - - - [Drone](https://drone.io) with [Gitea documentation](https://docs.drone.io/installation/providers/gitea/) - - [Jenkins](https://jenkins.io/) with [Gitea plugin](https://plugins.jenkins.io/gitea) - - [Agola](https://agola.io) - - [Buildkite](https://buildkite.com) with [Gitea connector](https://github.com/techknowlogick/gitea-buildkite-connector) - - [AppVeyor](https://www.appveyor.com) with [built-in Gitea support](https://www.appveyor.com/blog/2019/09/05/gitea-receives-first-class-support-in-appveyor/) - - [Buildbot](https://www.buildbot.net/) with [Gitea plugin](https://github.com/lab132/buildbot-gitea) - - -Others CI/CD solutions that can partially be integrated with Gitea: - - - [Concourse](https://www.concourse-ci.org), see more information at [Concourse community forum](https://discuss.concourse-ci.org/t/concourse-ci-and-gitea-oauth/1475) diff --git a/docs/content/doc/advanced/cmd-embedded.en-us.md b/docs/content/doc/advanced/cmd-embedded.en-us.md index 7144aed4d63d1..3bd80d13483c4 100644 --- a/docs/content/doc/advanced/cmd-embedded.en-us.md +++ b/docs/content/doc/advanced/cmd-embedded.en-us.md @@ -3,7 +3,7 @@ date: "2020-01-25T21:00:00-03:00" title: "Embedded data extraction tool" slug: "cmd-embedded" weight: 40 -toc: true +toc: false draft: false menu: sidebar: @@ -15,6 +15,10 @@ menu: # Embedded data extraction tool +**Table of Contents** + +{{< toc >}} + Gitea's executable contains all the resources required to run: templates, images, style-sheets and translations. Any of them can be overridden by placing a replacement in a matching path inside the `custom` directory (see [Customizing Gitea]({{< relref "doc/advanced/customizing-gitea.en-us.md" >}})). @@ -28,7 +32,7 @@ can be used from the OS shell interface. To list resources embedded in Gitea's executable, use the following syntax: -``` +```sh gitea embedded list [--include-vendored] [patterns...] ``` @@ -48,11 +52,11 @@ a special meaning for your command shell. If no pattern is provided, all files are listed. -#### Example +### Example Listing all embedded files with `openid` in their path: -``` +```sh $ gitea embedded list '**openid**' public/img/auth/openid_connect.svg public/img/openid-16x16.png @@ -68,7 +72,7 @@ templates/user/settings/security_openid.tmpl To extract resources embedded in Gitea's executable, use the following syntax: -``` +```sh gitea [--config {file}] embedded extract [--destination {dir}|--custom] [--overwrite|--rename] [--include-vendored] {patterns...} ``` @@ -91,7 +95,7 @@ as `filename.bak`. Previous `.bak` files are overwritten. At least one file search pattern must be provided; see `list` subcomand above for pattern syntax and examples. -#### Important notice +### Important notice Make sure to **only extract those files that require customization**. Files that are present in the `custom` directory are not upgraded by Gitea's upgrade process. @@ -99,11 +103,11 @@ When Gitea is upgraded to a new version (by replacing the executable), many of t embedded files will suffer changes. Gitea will honor and use any files found in the `custom` directory, even if they are old and incompatible. -#### Example +### Example Extracting mail templates to a temporary directory: -``` +```sh $ mkdir tempdir $ gitea embedded extract --destination tempdir 'templates/mail/**.tmpl' Extracting to tempdir: 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 a7ac5a4cc6961..5d2670151cb55 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -23,7 +23,7 @@ or any corresponding location. When installing from a distribution, this will typically be found at `/etc/gitea/conf/app.ini`. The defaults provided here are best-effort (not built automatically). They are -accurately recorded in [app.ini.sample](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.ini.sample) +accurately recorded in [app.example.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini) (s/master/\). Any string in the format `%(X)s` is a feature powered by [ini](https://github.com/go-ini/ini/#recursive-values), for reading values recursively. @@ -31,19 +31,19 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. **Note:** A full restart is required for Gitea configuration changes to take effect. +{{< toc >}} + ## Overall (`DEFAULT`) - `APP_NAME`: **Gitea: Git with a cup of tea**: Application name, used in the page title. - `RUN_USER`: **git**: The user Gitea will run as. This should be a dedicated system (non-user) account. Setting this incorrectly will cause Gitea to not start. -- `RUN_MODE`: **dev**: For performance and other purposes, change this to `prod` when - deployed to a production environment. The installation process will set this to `prod` - automatically. \[prod, dev, test\] +- `RUN_MODE`: **prod**: Application run mode, affects performance and debugging. Either "dev", "prod" or "test". ## Repository (`repository`) -- `ROOT`: **~/gitea-repositories/**: Root path for storing all repository data. It must be - an absolute path. +- `ROOT`: **data/gitea-repositories/**: Root path for storing all repository data. It must be + an absolute path. By default it is stored in a sub-directory of `APP_DATA_PATH`. - `SCRIPT_TYPE`: **bash**: The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. - `DETECTED_CHARSETS_ORDER`: **UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE, ISO-8859, windows-1252, ISO-8859, windows-1250, ISO-8859, ISO-8859, ISO-8859, windows-1253, ISO-8859, windows-1255, ISO-8859, windows-1251, windows-1256, KOI8-R, ISO-8859, windows-1254, Shift_JIS, GB18030, EUC-JP, EUC-KR, Big5, ISO-2022, ISO-2022, ISO-2022, IBM424_rtl, IBM424_ltr, IBM420_rtl, IBM420_ltr**: Tie-break order of detected charsets - if the detected charsets have equal confidence, charsets earlier in the list will be chosen in preference to those later. Adding `defaults` will place the unnamed charsets at that point. @@ -51,6 +51,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `FORCE_PRIVATE`: **false**: Force every new repository to be private. - `DEFAULT_PRIVATE`: **last**: Default private when creating a new repository. \[last, private, public\] +- `DEFAULT_PUSH_CREATE_PRIVATE`: **true**: Default private when creating a new repository with push-to-create. - `MAX_CREATION_LIMIT`: **-1**: Global maximum creation limit of repositories per user, `-1` means no limit. - `PULL_REQUEST_QUEUE_LENGTH`: **1000**: Length of pull request patch test queue, make it @@ -69,8 +70,19 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH`: **false**: Close an issue if a commit on a non default branch marks it as closed. - `ENABLE_PUSH_CREATE_USER`: **false**: Allow users to push local repositories to Gitea and have them automatically created for a user. - `ENABLE_PUSH_CREATE_ORG`: **false**: Allow users to push local repositories to Gitea and have them automatically created for an org. +- `DISABLED_REPO_UNITS`: **_empty_**: Comma separated list of globally disabled repo units. Allowed values: \[repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects\] +- `DEFAULT_REPO_UNITS`: **repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects**: Comma separated list of default repo units. Allowed values: \[repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects\]. Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility. External wiki and issue tracker can't be enabled by default as it requires additional settings. Disabled repo units will not be added to new repositories regardless if it is in the default list. - `PREFIX_ARCHIVE_FILES`: **true**: Prefix archive files by placing them in a directory named after the repository. - `DISABLE_MIRRORS`: **false**: Disable the creation of **new** mirrors. Pre-existing mirrors remain valid. +- `DISABLE_MIGRATIONS`: **false**: Disable migrating feature. +- `DEFAULT_BRANCH`: **master**: 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 + +### Repository - Editor (`repository.editor`) + +- `LINE_WRAP_EXTENSIONS`: **.txt,.md,.markdown,.mdown,.mkd,**: List of file extensions for which lines should be wrapped in the Monaco editor. Separate extensions with a comma. To line wrap files without an extension, just put a comma +- `PREVIEWABLE_FILE_MODES`: **markdown**: Valid file modes that have a preview API associated with them, such as `api/v1/markdown`. Separate the values by commas. The preview tab in edit mode won't be displayed if the file extension doesn't match. ### Repository - Pull Request (`repository.pull-request`) @@ -90,6 +102,18 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `LOCK_REASONS`: **Too heated,Off-topic,Resolved,Spam**: A list of reasons why a Pull Request or Issue can be locked +### Repository - Upload (`repository.upload`) + +- `ENABLED`: **true**: Whether repository file uploads are enabled +- `TEMP_PATH`: **data/tmp/uploads**: Path for uploads (tmp gets deleted on gitea restart) +- `ALLOWED_TYPES`: **\**: Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. +- `FILE_MAX_SIZE`: **3**: Max size of each file in megabytes. +- `MAX_FILES`: **5**: Max number of files per upload + +### Repository - Release (`repository.release`) + +- `ALLOWED_TYPES`: **\**: Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. + ### Repository - Signing (`repository.signing`) - `SIGNING_KEY`: **default**: \[none, KEYID, default \]: Key to sign with. @@ -100,6 +124,10 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `twofa`: Only sign if the user is logged in with twofa - `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 commmitter). + - `collaboratorcommitter`: Trust signatures signed by keys of collaborators which match the commiter. - `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: @@ -110,6 +138,10 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `headsigned`: Only sign if the head commit in the head branch is signed. - `commitssigned`: Only sign if all the commits in the head branch to the merge point are signed. +## Repository - Local (`repository.local`) + +- `LOCAL_COPY_PATH`: **tmp/local-repo**: Path for temporary local repository copies. Defaults to `tmp/local-repo` + ## CORS (`cors`) - `ENABLED`: **false**: enable cors headers (disabled by default) @@ -126,10 +158,15 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `ISSUE_PAGING_NUM`: **10**: Number of issues that are shown in one page (for all pages that list issues). - `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. - `GRAPH_MAX_COMMIT_NUM`: **100**: Number of maximum commits shown in the commit graph. +- `CODE_COMMENT_LINES`: **4**: Number of line of codes shown for a code comment. - `DEFAULT_THEME`: **gitea**: \[gitea, arc-green\]: Set the default theme for the Gitea install. -- `THEMES`: **gitea,arc-green**: All available themes. Allow users select personalized themes +- `SHOW_USER_EMAIL`: **true**: Whether the email of the user should be shown in the Explore Users page. +- `THEMES`: **gitea,arc-green**: All available themes. Allow users select personalized themes. regardless of the value of `DEFAULT_THEME`. +- `THEME_COLOR_META_TAG`: **#6cc644**: Value of `theme-color` meta tag, used by Android >= 5.0. An invalid color like "none" or "disable" will have the default style. More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android +- `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB) - `REACTIONS`: All available reactions users can choose on issues/prs and comments Values can be emoji alias (:smile:) or a unicode emoji. For custom reactions, add a tightly cropped square image to public/emoji/img/reaction_name.png @@ -144,13 +181,22 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `NOTICE_PAGING_NUM`: **25**: Number of notices that are shown in one page. - `ORG_PAGING_NUM`: **50**: Number of organizations that are shown in one page. +### UI - Metadata (`ui.meta`) + +- `AUTHOR`: **Gitea - Git with a cup of tea**: Author meta tag of the homepage. +- `DESCRIPTION`: **Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go**: Description meta tag of the homepage. +- `KEYWORDS`: **go,git,self-hosted,gitea**: Keywords meta tag of the homepage. + ### UI - Notification (`ui.notification`) - `MIN_TIMEOUT`: **10s**: These options control how often notification endpoint is polled to update the notification count. On page load the notification count will be checked after `MIN_TIMEOUT`. The timeout will increase to `MAX_TIMEOUT` by `TIMEOUT_STEP` if the notification count is unchanged. Set MIN_TIMEOUT to 0 to turn off. - `MAX_TIMEOUT`: **60s**. - `TIMEOUT_STEP`: **10s**. -- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource`, it will be used in preference to polling notification endpoint. +- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource` and `SharedWorker`, a `SharedWorker` will be used in preference to polling notification endpoint. Set to **-1** to disable the `EventSource`. + +### UI - SVG Images (`ui.svg`) +- `ENABLE_RENDER`: **true**: Whether to render SVG files as images. If SVG rendering is disabled, SVG files are displayed as text and cannot be embedded in markdown files as images. ## Markdown (`markdown`) @@ -191,26 +237,49 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. most cases you do not need to change the default value. Alter it only if your SSH server node is not the same as HTTP node. Do not set this variable if `PROTOCOL` is set to `unix`. + - `DISABLE_SSH`: **false**: Disable SSH feature when it's not available. - `START_SSH_SERVER`: **false**: When enabled, use the built-in SSH server. +- `BUILTIN_SSH_SERVER_USER`: **%(RUN_USER)s**: Username to use for the built-in SSH Server. - `SSH_DOMAIN`: **%(DOMAIN)s**: Domain name of this server, used for displayed clone URL. - `SSH_PORT`: **22**: SSH port displayed in clone URL. - `SSH_LISTEN_HOST`: **0.0.0.0**: Listen address for the built-in SSH server. - `SSH_LISTEN_PORT`: **%(SSH\_PORT)s**: Port for the built-in SSH server. +- `SSH_ROOT_PATH`: **~/.ssh**: Root path of SSH directory. +- `SSH_CREATE_AUTHORIZED_KEYS_FILE`: **true**: Gitea will create a authorized_keys file by default when it is not using the internal ssh server. If you intend to use the AuthorizedKeysCommand functionality then you should turn this off. +- `SSH_AUTHORIZED_KEYS_BACKUP`: **true**: Enable SSH Authorized Key Backup when rewriting all keys, default is true. +- `SSH_TRUSTED_USER_CA_KEYS`: **\**: Specifies the public keys of certificate authorities that are trusted to sign user certificates for authentication. Multiple keys should be comma separated. E.g.`ssh- ` or `ssh- , ssh- `. For more information see `TrustedUserCAKeys` in the sshd config man pages. When empty no file will be created and `SSH_AUTHORIZED_PRINCIPALS_ALLOW` will default to `off`. +- `SSH_TRUSTED_USER_CA_KEYS_FILENAME`: **`RUN_USER`/.ssh/gitea-trusted-user-ca-keys.pem**: Absolute path of the `TrustedUserCaKeys` file gitea will manage. If you're running your own ssh server and you want to use the gitea managed file you'll also need to modify your sshd_config to point to this file. The official docker image will automatically work without further configuration. +- `SSH_AUTHORIZED_PRINCIPALS_ALLOW`: **off** or **username, email**: \[off, username, email, anything\]: Specify the principals values that users are allowed to use as principal. When set to `anything` no checks are done on the principal string. When set to `off` authorized principal are not allowed to be set. +- `SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE`: **false/true**: Gitea will create a authorized_principals file by default when it is not using the internal ssh server and `SSH_AUTHORIZED_PRINCIPALS_ALLOW` is not `off`. +- `SSH_AUTHORIZED_PRINCIPALS_BACKUP`: **false/true**: Enable SSH Authorized Principals Backup when rewriting all keys, default is true if `SSH_AUTHORIZED_PRINCIPALS_ALLOW` is not `off`. +- `SSH_SERVER_CIPHERS`: **aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128**: For the built-in SSH server, choose the ciphers to support for SSH connections, for system SSH this setting has no effect. +- `SSH_SERVER_KEY_EXCHANGES`: **diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, curve25519-sha256@libssh.org**: For the built-in SSH server, choose the key exchange algorithms to support for SSH connections, for system SSH this setting has no effect. +- `SSH_SERVER_MACS`: **hmac-sha2-256-etm@openssh.com, hmac-sha2-256, hmac-sha1, hmac-sha1-96**: For the built-in SSH server, choose the MACs to support for SSH connections, for system SSH this setting has no effect +- `SSH_KEY_TEST_PATH`: **/tmp**: Directory to create temporary files in when testing public keys using ssh-keygen, default is the system temporary directory. +- `SSH_KEYGEN_PATH`: **ssh-keygen**: Path to ssh-keygen, default is 'ssh-keygen' which means the shell is responsible for finding out which one to call. +- `SSH_EXPOSE_ANONYMOUS`: **false**: Enable exposure of SSH clone URL to anonymous visitors, default is false. +- `MINIMUM_KEY_SIZE_CHECK`: **true**: Indicate whether to check minimum key size with corresponding type. + - `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures. - `DISABLE_ROUTER_LOG`: **false**: Mute printing of the router log. -- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. From 1.11 paths are relative to `CUSTOM_PATH`. +- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). From 1.11 paths are relative to `CUSTOM_PATH`. - `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. From 1.11 paths are relative to `CUSTOM_PATH`. - `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path. -- `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. -- `ENABLE_GZIP`: **false**: Enables application-level GZIP support. +- `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)__` +- `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\]. + - `LFS_START_SERVER`: **false**: Enables git-lfs support. -- `LFS_CONTENT_PATH`: **./data/lfs**: Where to store LFS files. +- `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)/lfs**: Default LFS content path. (if it is on local storage.) - `LFS_JWT_SECRET`: **\**: LFS authentication secret, change this a unique string. - `LFS_HTTP_AUTH_EXPIRY`: **20m**: LFS authentication validity period in time.Duration, pushes taking longer than this may fail. - `LFS_MAX_FILE_SIZE`: **0**: Maximum allowed LFS file size in bytes (Set to 0 for no limit). -- `LFS_LOCK_PAGING_NUM`: **50**: Maximum number of LFS Locks returned per page. +- `LFS_LOCKS_PAGING_NUM`: **50**: Maximum number of LFS Locks returned per page. + - `REDIRECT_OTHER_PORT`: **false**: If true and `PROTOCOL` is https, allows redirecting http requests on `PORT_TO_REDIRECT` to the https port Gitea listens on. - `PORT_TO_REDIRECT`: **80**: Port for the http redirection service to listen on. Used when `REDIRECT_OTHER_PORT` is true. - `ENABLE_LETSENCRYPT`: **false**: If enabled you must set `DOMAIN` to valid internet facing domain (ensure DNS is set and port 80 is accessible by letsencrypt validation server). @@ -228,9 +297,9 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `HOST`: **127.0.0.1:3306**: Database host address and port or absolute path for unix socket \[mysql, postgres\] (ex: /var/run/mysqld/mysqld.sock). - `NAME`: **gitea**: Database name. - `USER`: **root**: Database username. -- `PASSWD`: **\**: Database user password. Use \`your password\` for quoting if you use special characters in the password. +- `PASSWD`: **\**: Database user password. Use \`your password\` or """your password""" for quoting if you use special characters in the password. - `SCHEMA`: **\**: For PostgreSQL only, schema to use if different from "public". The schema must exist beforehand, - the user must have creation privileges on it, and the user search path must be set to the look into the schema first + the user must have creation privileges on it, and the user search path must be set to the look into the schema first (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: @@ -244,7 +313,9 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `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. -- `CHARSET`: **utf8**: For MySQL only, either "utf8" or "utf8mb4", default is "utf8". NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this. +- `SQLITE_TIMEOUT`: **500**: Query timeout for sqlite3 only. +- `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. - `LOG_SQL`: **true**: Log the executed SQL. - `DB_RETRIES`: **10**: How many ORM init / DB connect attempts allowed. @@ -252,7 +323,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `MAX_OPEN_CONNS` **0**: Database maximum open connections - default is 0, meaning there is no limit. - `MAX_IDLE_CONNS` **2**: Max idle database connections on connnection pool, default is 2 - this will be capped to `MAX_OPEN_CONNS`. - `CONN_MAX_LIFETIME` **0 or 3s**: Sets the maximum amount of time a DB connection may be reused - default is 0, meaning there is no limit (except on MySQL where it is 3s - see #6804 & #7071). - + Please see #8540 & #8273 for further discussion of the appropriate values for `MAX_OPEN_CONNS`, `MAX_IDLE_CONNS` & `CONN_MAX_LIFETIME` and their relation to port exhaustion. @@ -264,12 +335,16 @@ relation to port exhaustion. - `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search; available when ISSUE_INDEXER_TYPE is bleve and elasticsearch. - The next 4 configuration values are deprecated and should be set in `queue.issue_indexer` however are kept for backwards compatibility: - `ISSUE_INDEXER_QUEUE_TYPE`: **levelqueue**: Issue indexer queue, currently supports:`channel`, `levelqueue`, `redis`. -- `ISSUE_INDEXER_QUEUE_DIR`: **indexers/issues.queue**: When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this will be the queue will be saved path. -- `ISSUE_INDEXER_QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string. +- `ISSUE_INDEXER_QUEUE_DIR`: **indexers/issues.queue**: When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this will be the path where the queue will be saved. +- `ISSUE_INDEXER_QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string. When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this is a directory or additional options of the form `leveldb://path/to/db?option=value&....`, and overrides `ISSUE_INDEXER_QUEUE_DIR`. - `ISSUE_INDEXER_QUEUE_BATCH_NUMBER`: **20**: Batch queue number. - `REPO_INDEXER_ENABLED`: **false**: Enables code search (uses a lot of disk space, about 6 times more than the repository size). +- `REPO_INDEXER_TYPE`: **bleve**: Code search engine type, could be `bleve` or `elasticsearch`. - `REPO_INDEXER_PATH`: **indexers/repos.bleve**: Index file used for code search. +- `REPO_INDEXER_CONN_STR`: ****: Code indexer connection string, available when `REPO_INDEXER_TYPE` is elasticsearch. i.e. http://elastic:changeme@localhost:9200 +- `REPO_INDEXER_NAME`: **gitea_codes**: Code indexer name, available when `REPO_INDEXER_TYPE` is elasticsearch + - `REPO_INDEXER_INCLUDE`: **empty**: A comma separated list of glob patterns (see https://github.com/gobwas/glob) to **include** in the index. Use `**.txt` to match any files with .txt extension. An empty list means include all files. - `REPO_INDEXER_EXCLUDE`: **empty**: A comma separated list of glob patterns (see https://github.com/gobwas/glob) to **exclude** from the index. Files that match this list will not be indexed, even if they match in `REPO_INDEXER_INCLUDE`. - `REPO_INDEXER_EXCLUDE_VENDORED`: **true**: Exclude vendored files from index. @@ -279,16 +354,14 @@ relation to port exhaustion. ## Queue (`queue` and `queue.*`) -- `TYPE`: **persistable-channel**: General queue type, currently support: `persistable-channel`, `channel`, `level`, `redis`, `dummy` -- `DATADIR`: **queues/**: Base DataDir for storing persistent and level queues. `DATADIR` for inidividual queues can be set in `queue.name` sections but will default to `DATADIR/`**`name`**. +- `TYPE`: **persistable-channel**: General queue type, currently support: `persistable-channel` (uses a LevelDB internally), `channel`, `level`, `redis`, `dummy` +- `DATADIR`: **queues/**: Base DataDir for storing persistent and level queues. `DATADIR` for individual queues can be set in `queue.name` sections but will default to `DATADIR/`**`name`**. - `LENGTH`: **20**: Maximal queue size before channel queues block - `BATCH_LENGTH`: **20**: Batch data before passing to the handler -- `CONN_STR`: **addrs=127.0.0.1:6379 db=0**: Connection string for the redis queue type. -- `QUEUE_NAME`: **_queue**: The suffix for default redis queue name. Individual queues will default to **`name`**`QUEUE_NAME` but can be overriden in the specific `queue.name` section. -- `SET_NAME`: **_unique**: The suffix that will added to the default redis -set name for unique queues. Individual queues will default to -**`name`**`QUEUE_NAME`_`SET_NAME`_ but can be overridden in the specific -`queue.name` section. +- `CONN_STR`: **redis://127.0.0.1:6379/0**: Connection string for the redis queue type. Options can be set using query params. Similarly LevelDB options can also be set using: **leveldb://relative/path?option=value** or **leveldb:///absolute/path?option=value**, and will override `DATADIR` +- `QUEUE_NAME`: **_queue**: The suffix for default redis and disk queue name. Individual queues will default to **`name`**`QUEUE_NAME` but can be overriden in the specific `queue.name` section. +- `SET_NAME`: **_unique**: The suffix that will be added to the default redis and disk queue `set` name for unique queues. Individual queues will default to + **`name`**`QUEUE_NAME`_`SET_NAME`_ but can be overridden in the specific `queue.name` section. - `WRAP_IF_NECESSARY`: **true**: Will wrap queues with a timeoutable queue if the selected queue is not ready to be created - (Only relevant for the level queue.) - `MAX_ATTEMPTS`: **10**: Maximum number of attempts to create the wrapped queue - `TIMEOUT`: **GRACEFUL_HAMMER_TIME + 30s**: Timeout the creation of the wrapped queue if it takes longer than this to create. @@ -300,7 +373,9 @@ set name for unique queues. Individual queues will default to - `BOOST_WORKERS`: **5**: This many workers will be added to the worker pool if there is a boost. ## Admin (`admin`) + - `DEFAULT_EMAIL_NOTIFICATIONS`: **enabled**: Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled +- `DISABLE_REGULAR_ORG_CREATION`: **false**: Disallow regular (non-admin) users from creating organizations. ## Security (`security`) @@ -314,20 +389,27 @@ set name for unique queues. Individual queues will default to authentication. - `REVERSE_PROXY_AUTHENTICATION_EMAIL`: **X-WEBAUTH-EMAIL**: Header name for reverse proxy authentication provided email. -- `DISABLE_GIT_HOOKS`: **false**: Set to `true` to prevent all users (including admin) from creating custom - git hooks. +- `DISABLE_GIT_HOOKS`: **true**: Set to `false` to enable users with git hook privilege to create custom git hooks. + WARNING: Custom git hooks can be used to perform arbitrary code execution on the host operating system. + This enables the users to access and modify this config file and the Gitea database and interrupt the Gitea service. + By modifying the Gitea database, users can gain Gitea administrator privileges. + It also enables them to access other resources available to the user on the operating system that is running the + Gitea instance and perform arbitrary actions in the name of the Gitea OS user. + This maybe harmful to you website or your operating system. - `ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET`: **true**: Set to `false` to allow local users to push to gitea-repositories without setting up the Gitea environment. This is not recommended and if you want local users to push to gitea repositories you should set the environment appropriately. - `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server. - `INTERNAL_TOKEN`: **\**: Secret used to validate communication within Gitea binary. - `INTERNAL_TOKEN_URI`: ****: Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: `file:/etc/gitea/internal_token`) -- `PASSWORD_HASH_ALGO`: **pbkdf2**: The hash algorithm to use \[pbkdf2, argon2, scrypt, bcrypt\]. +- `PASSWORD_HASH_ALGO`: **argon2**: The hash algorithm to use \[argon2, pbkdf2, scrypt, bcrypt\]. - `CSRF_COOKIE_HTTP_ONLY`: **true**: Set false to allow JavaScript to read CSRF cookie. -- `PASSWORD_COMPLEXITY`: **lower,upper,digit,spec**: Comma separated list of character classes required to pass minimum complexity. If left empty or no valid values are specified, the default values will be used. Possible values are: +- `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 +- `PASSWORD_CHECK_PWN`: **false**: Check [HaveIBeenPwned](https://haveibeenpwned.com/Passwords) to see if a password has been exposed. ## OpenID (`openid`) @@ -345,6 +427,8 @@ set name for unique queues. Individual queues will default to process. - `REGISTER_EMAIL_CONFIRM`: **false**: Enable this to ask for mail confirmation of registration. Requires `Mailer` to be enabled. +- `REGISTER_MANUAL_CONFIRM`: **false**: Enable this to manually confirm new registrations. + Requires `REGISTER_EMAIL_CONFIRM` to be disabled. - `DISABLE_REGISTRATION`: **false**: Disable registration, after which only admin can create accounts for users. - `REQUIRE_EXTERNAL_REGISTRATION_PASSWORD`: **false**: Enable this to force externally created @@ -365,13 +449,20 @@ set name for unique queues. Individual queues will default to - `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration. - `REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA`: **false**: Enable this to force captcha validation even for External Accounts (i.e. GitHub, OpenID Connect, etc). You must `ENABLE_CAPTCHA` also. -- `CAPTCHA_TYPE`: **image**: \[image, recaptcha\] +- `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha\] - `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha. - `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha. - `RECAPTCHA_URL`: **https://www.google.com/recaptcha/**: Set the recaptcha url - allows the use of recaptcha net. +- `HCAPTCHA_SECRET`: **""**: Sign up at https://www.hcaptcha.com/ to get a secret for hcaptcha. +- `HCAPTCHA_SITEKEY`: **""**: Sign up at https://www.hcaptcha.com/ to get a sitekey for hcaptcha. +- `DEFAULT_KEEP_EMAIL_PRIVATE`: **false**: By default set users to keep their email address private. +- `DEFAULT_ALLOW_CREATE_ORGANIZATION`: **true**: Allow new users to create organizations by default. - `DEFAULT_ENABLE_DEPENDENCIES`: **true**: Enable this to have dependencies enabled by default. - `ALLOW_CROSS_REPOSITORY_DEPENDENCIES` : **true** Enable this to allow dependencies on issues from any repository where the user is granted access. - `ENABLE_USER_HEATMAP`: **true**: Enable this to display the heatmap on users profiles. +- `ENABLE_TIMETRACKING`: **true**: Enable Timetracking feature. +- `DEFAULT_ENABLE_TIMETRACKING`: **true**: Allow repositories to use timetracking by deault. +- `DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME`: **true**: Only allow users with write permissions to track time. - `EMAIL_DOMAIN_WHITELIST`: **\**: If non-empty, list of domain names that can only be used to register on this instance. - `SHOW_REGISTRATION_BUTTON`: **! DISABLE\_REGISTRATION**: Show Registration Button @@ -381,8 +472,18 @@ set name for unique queues. Individual queues will default to - `DEFAULT_ORG_VISIBILITY`: **public**: Set default visibility mode for organisations, either "public", "limited" or "private". - `DEFAULT_ORG_MEMBER_VISIBLE`: **false** True will make the membership of the users visible when added to the organisation. - `ALLOW_ONLY_EXTERNAL_REGISTRATION`: **false** Set to true to force registration only using third-party services. -- `NO_REPLY_ADDRESS`: **DOMAIN** Default value for the domain part of the user's email address in the git log if he has set KeepEmailPrivate to true. +- `NO_REPLY_ADDRESS`: **DOMAIN** Default value for the domain part of the user's email address in the git log if he has set KeepEmailPrivate to true. The user's email will be replaced with a concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS. +- `USER_DELETE_WITH_COMMENTS_MAX_TIME`: **0** Minimum amount of time a user must exist before comments are kept when the user is deleted. + +## SSH Minimum Key Sizes (`ssh.minimum_key_sizes`) + +Define allowed algorithms and their minimum key length (use -1 to disable a type): + +- `ED25519`: **256** +- `ECDSA`: **256** +- `RSA`: **2048** +- `DSA`: **-1**: DSA is now disabled by default. Set to **1024** to re-enable but ensure you may need to reconfigure your SSHD provider ## Webhook (`webhook`) @@ -400,7 +501,7 @@ set name for unique queues. Individual queues will default to - `HELO_HOSTNAME`: **\**: Custom hostname for HELO operation. - `HOST`: **\**: SMTP mail host address and port (example: smtp.gitea.io:587). - Using opportunistic TLS via STARTTLS on port 587 is recommended per RFC 6409. -- `IS_TLS_ENABLED` : **false** : Forcibly use TLS to connect even if not on a default SMTPS port. +- `IS_TLS_ENABLED` : **false** : Forcibly use TLS to connect even if not on a default SMTPS port. - Note, if the port ends with `465` 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 @@ -408,8 +509,13 @@ set name for unique queues. Individual queues will default to - `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. -- `SKIP_VERIFY`: **\**: Do not verify the self-signed certificates. +- `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** - `SUBJECT_PREFIX`: **\**: Prefix to be placed before e-mail subject lines. - `MAILER_TYPE`: **smtp**: \[smtp, sendmail, dummy\] - **smtp** Use SMTP to send mail @@ -421,7 +527,9 @@ set name for unique queues. Individual queues will default to - 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. - `SENDMAIL_TIMEOUT`: **5m**: default timeout for sending email through sendmail +- `SEND_BUFFER_LEN`: **100**: Buffer length of mailing queue. ## Cache (`cache`) @@ -429,7 +537,7 @@ set name for unique queues. Individual queues will default to - `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, or `memcache`. - `INTERVAL`: **60**: Garbage Collection interval (sec), for memory cache only. - `HOST`: **\**: Connection string for `redis` and `memcache`. - - Redis: `network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180` + - 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` - `ITEM_TTL`: **16h**: Time to keep items in cache if not used, Setting it to 0 disables caching. @@ -446,6 +554,7 @@ set name for unique queues. Individual queues will default to - `COOKIE_SECURE`: **false**: Enable this to force using HTTPS for all session access. - `COOKIE_NAME`: **i\_like\_gitea**: The name of the cookie used for the session ID. - `GC_INTERVAL_TIME`: **86400**: GC interval in seconds. +- `SESSION_LIFE_TIME`: **86400**: Session life time in seconds, default is 86400 (1 day) ## Picture (`picture`) @@ -454,25 +563,45 @@ set name for unique queues. Individual queues will default to - `DISABLE_GRAVATAR`: **false**: Enable this to use local avatars only. - `ENABLE_FEDERATED_AVATAR`: **false**: Enable support for federated avatars (see [http://www.libravatar.org](http://www.libravatar.org)). + +- `AVATAR_STORAGE_TYPE`: **default**: Storage type defined in `[storage.xxx]`. Default is `default` which will read `[storage]` if no section `[storage]` will be a type `local`. - `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store user avatar image files. +- `AVATAR_MAX_WIDTH`: **4096**: Maximum avatar image width in pixels. +- `AVATAR_MAX_HEIGHT`: **3072**: Maximum avatar image height in pixels. +- `AVATAR_MAX_FILE_SIZE`: **1048576** (1Mb): Maximum avatar image file size in bytes. + +- `REPOSITORY_AVATAR_STORAGE_TYPE`: **default**: Storage type defined in `[storage.xxx]`. Default is `default` which will read `[storage]` if no section `[storage]` will be a type `local`. - `REPOSITORY_AVATAR_UPLOAD_PATH`: **data/repo-avatars**: Path to store repository avatar image files. - `REPOSITORY_AVATAR_FALLBACK`: **none**: How Gitea deals with missing repository avatars - none = no avatar will be displayed - random = random avatar will be generated - - image = default image will be used (which is set in `REPOSITORY_AVATAR_DEFAULT_IMAGE`) + - 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) -- `AVATAR_MAX_WIDTH`: **4096**: Maximum avatar image width in pixels. -- `AVATAR_MAX_HEIGHT`: **3072**: Maximum avatar image height in pixels. -- `AVATAR_MAX_FILE_SIZE`: **1048576** (1Mb): Maximum avatar image file size in bytes. -## Attachment (`attachment`) -- `ENABLED`: **true**: Enable this to allow uploading attachments. -- `PATH`: **data/attachments**: Path to store attachments. -- `ALLOWED_TYPES`: **see app.ini.sample**: Allowed MIME types, e.g. `image/jpeg|image/png`. - Use `*/*` for all types. +## Project (`project`) + +Default templates for project boards: + +- `PROJECT_BOARD_BASIC_KANBAN_TYPE`: **To Do, In Progress, Done** +- `PROJECT_BOARD_BUG_TRIAGE_TYPE`: **Needs Triage, High Priority, Low Priority, Closed** + +## Issue and pull request attachments (`attachment`) + +- `ENABLED`: **true**: Whether issue and pull request attachments are enabled. +- `ALLOWED_TYPES`: **.docx,.gif,.gz,.jpeg,.jpg,.log,.pdf,.png,.pptx,.txt,.xlsx,.zip**: Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. - `MAX_SIZE`: **4**: Maximum size (MB). - `MAX_FILES`: **5**: Maximum number of attachments that can be uploaded at once. +- `STORAGE_TYPE`: **local**: Storage type for attachments, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]` +- `SERVE_DIRECT`: **false**: Allows the storage driver to redirect to authenticated URLs to serve files directly. Currently, only Minio/S3 is supported via signed URLs, local does nothing. +- `PATH`: **data/attachments**: Path to store attachments only available when STORAGE_TYPE is `local` +- `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when STORAGE_TYPE is `minio` +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when STORAGE_TYPE is `minio` +- `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` +- `MINIO_BUCKET`: **gitea**: Minio bucket to store the attachments only available when STORAGE_TYPE is `minio` +- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when STORAGE_TYPE is `minio` +- `MINIO_BASE_PATH`: **attachments/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio` +- `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when STORAGE_TYPE is `minio` ## Log (`log`) @@ -538,41 +667,93 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` ## Cron (`cron`) -- `ENABLED`: **true**: Run cron tasks periodically. +- `ENABLED`: **false**: Enable to run all cron tasks periodically with default settings. - `RUN_AT_START`: **false**: Run cron tasks at application start-up. +- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices. + +### Basic cron tasks - enabled by default -### Cron - Cleanup old repository archives (`cron.archive_cleanup`) +#### Cron - Cleanup old repository archives (`cron.archive_cleanup`) - `ENABLED`: **true**: Enable service. - `RUN_AT_START`: **true**: Run tasks at start up time (if ENABLED). - `SCHEDULE`: **@every 24h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`. - `OLDER_THAN`: **24h**: Archives created more than `OLDER_THAN` ago are subject to deletion, e.g. `12h`. -### Cron - Update Mirrors (`cron.update_mirrors`) +#### Cron - Update Mirrors (`cron.update_mirrors`) - `SCHEDULE`: **@every 10m**: Cron syntax for scheduling update mirrors, e.g. `@every 3h`. +- `NO_SUCCESS_NOTICE`: **true**: The cron task for update mirrors success report is not very useful - as it just means that the mirrors have been queued. Therefore this is turned off by default. -### Cron - Repository Health Check (`cron.repo_health_check`) +#### Cron - Repository Health Check (`cron.repo_health_check`) - `SCHEDULE`: **@every 24h**: Cron syntax for scheduling repository health check. - `TIMEOUT`: **60s**: Time duration syntax for health check execution timeout. - `ARGS`: **\**: Arguments for command `git fsck`, e.g. `--unreachable --tags`. See more on http://git-scm.com/docs/git-fsck -### Cron - Repository Statistics Check (`cron.check_repo_stats`) +#### Cron - Repository Statistics Check (`cron.check_repo_stats`) - `RUN_AT_START`: **true**: Run repository statistics check at start time. - `SCHEDULE`: **@every 24h**: Cron syntax for scheduling repository statistics check. -### Cron - Update Migration Poster ID (`cron.update_migration_poster_id`) +#### Cron - Update Migration Poster ID (`cron.update_migration_poster_id`) + +- `SCHEDULE`: **@every 24h** : Interval as a duration between each synchronization, it will always attempt synchronization when the instance starts. + +#### Cron - Sync External Users (`cron.sync_external_users`) - `SCHEDULE`: **@every 24h** : Interval as a duration between each synchronization, it will always attempt synchronization when the instance starts. +- `UPDATE_EXISTING`: **true**: Create new users, update existing user data and disable users that are not in external source anymore (default) or only create new users if UPDATE_EXISTING is set to false. + +### 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`. +- `TIMEOUT`: **60s**: Time duration syntax for garbage collection execution timeout. +- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices. +- `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). +- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off 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). +- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off 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). +- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off 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). +- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off 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). +- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices. +- `SCHEDULE`: **@every 72h**: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`. ## Git (`git`) - `PATH`: **""**: The path of git executable. If empty, Gitea searches through the PATH environment. +- `DISABLE_DIFF_HIGHLIGHT`: **false**: Disables highlight of added and removed changes. - `MAX_GIT_DIFF_LINES`: **100**: 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. - `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view. +- `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 - `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) @@ -604,8 +785,8 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` - `ENABLE`: **true**: Enables OAuth2 provider. - `ACCESS_TOKEN_EXPIRATION_TIME`: **3600**: Lifetime of an OAuth2 access token in seconds -- `REFRESH_TOKEN_EXPIRATION_TIME`: **730**: Lifetime of an OAuth2 access token in hours -- `INVALIDATE_REFRESH_TOKEN`: **false**: Check if refresh token got already used +- `REFRESH_TOKEN_EXPIRATION_TIME`: **730**: Lifetime of an OAuth2 refresh token in hours +- `INVALIDATE_REFRESH_TOKENS`: **false**: Check if refresh token has already been used - `JWT_SECRET`: **\**: OAuth2 authentication secret for access and refresh tokens, change this a unique string. - `MAX_TOKEN_LENGTH`: **32767**: Maximum length of token/cookie to accept from OAuth2 provider @@ -614,32 +795,6 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` - `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR**: List of locales shown in language selector - `NAMES`: **English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어**: Visible names corresponding to the locales -### i18n - Datepicker Language (`i18n.datelang`) -Maps locales to the languages used by the datepicker plugin - -- `en-US`: **en** -- `zh-CN`: **zh** -- `zh-HK`: **zh-HK** -- `zh-TW`: **zh-TW** -- `de-DE`: **de** -- `fr-FR`: **fr** -- `nl-NL`: **nl** -- `lv-LV`: **lv** -- `ru-RU`: **ru** -- `ja-JP`: **ja** -- `es-ES`: **es** -- `pt-BR`: **pt-BR** -- `pt-PT`: **pt** -- `pl-PL`: **pl** -- `bg-BG`: **bg** -- `it-IT`: **it** -- `fi-FI`: **fi** -- `tr-TR`: **tr** -- `cs-CZ`: **cs-CZ** -- `sr-SP`: **sr** -- `sv-SE`: **sv** -- `ko-KR`: **ko** - ## U2F (`U2F`) - `APP_ID`: **`ROOT_URL`**: Declares the facet of the application. Requires HTTPS. - `TRUSTED_FACETS`: List of additional facets which are trusted. This is not support by all browsers. @@ -695,15 +850,73 @@ Task queue configuration has been moved to `queue.task`. However, the below conf - `QUEUE_TYPE`: **channel**: Task queue type, could be `channel` or `redis`. - `QUEUE_LENGTH`: **1000**: Task queue length, available only when `QUEUE_TYPE` is `channel`. -- `QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: Task queue connection string, available only when `QUEUE_TYPE` is `redis`. If redis needs a password, use `addrs=127.0.0.1:6379 password=123 db=0`. +- `QUEUE_CONN_STR`: **redis://127.0.0.1:6379/0**: Task queue connection string, available only when `QUEUE_TYPE` is `redis`. If redis needs a password, use `redis://123@127.0.0.1:6379/0`. ## Migrations (`migrations`) - `MAX_ATTEMPTS`: **3**: Max attempts per http/https request on migrations. - `RETRY_BACKOFF`: **3**: Backoff time per http/https request retry (seconds) +- `ALLOWED_DOMAINS`: **\**: Domains allowlist for migrating repositories, default is blank. It means everything will be allowed. Multiple domains could be separated by commas. +- `BLOCKED_DOMAINS`: **\**: Domains blocklist for migrating repositories, default is blank. Multiple domains could be separated by commas. When `ALLOWED_DOMAINS` is not blank, this option will be ignored. +- `ALLOW_LOCALNETWORKS`: **false**: Allow private addresses defined by RFC 1918, RFC 1122, RFC 4632 and RFC 4291 + +## Mirror (`mirror`) + +- `DEFAULT_INTERVAL`: **8h**: Default interval between each check +- `MIN_INTERVAL`: **10m**: Minimum interval for checking. (Must be >1m). + +## LFS (`lfs`) + +Storage configuration for lfs data. It will be derived from default `[storage]` or +`[storage.xxx]` when set `STORAGE_TYPE` to `xxx`. When derived, the default of `PATH` +is `data/lfs` and the default of `MINIO_BASE_PATH` is `lfs/`. + +- `STORAGE_TYPE`: **local**: Storage type for lfs, `local` for local disk or `minio` for s3 compatible object storage service or other name defined with `[storage.xxx]` +- `SERVE_DIRECT`: **false**: Allows the storage driver to redirect to authenticated URLs to serve files directly. Currently, only Minio/S3 is supported via signed URLs, local does nothing. +- `CONTENT_PATH`: **./data/lfs**: Where to store LFS files, only available when `STORAGE_TYPE` is `local`. +- `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when `STORAGE_TYPE` is `minio` +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when `STORAGE_TYPE` is `minio` +- `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey to connect only available when `STORAGE_TYPE is` `minio` +- `MINIO_BUCKET`: **gitea**: Minio bucket to store the lfs only available when `STORAGE_TYPE` is `minio` +- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when `STORAGE_TYPE` is `minio` +- `MINIO_BASE_PATH`: **lfs/**: Minio base path on the bucket only available when `STORAGE_TYPE` is `minio` +- `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when `STORAGE_TYPE` is `minio` + +## Storage (`storage`) + +Default storage configuration for attachments, lfs, avatars and etc. + +- `SERVE_DIRECT`: **false**: Allows the storage driver to redirect to authenticated URLs to serve files directly. Currently, only Minio/S3 is supported via signed URLs, local does nothing. +- `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when `STORAGE_TYPE` is `minio` +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when `STORAGE_TYPE` is `minio` +- `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey to connect only available when `STORAGE_TYPE is` `minio` +- `MINIO_BUCKET`: **gitea**: Minio bucket to store the data only available when `STORAGE_TYPE` is `minio` +- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when `STORAGE_TYPE` is `minio` +- `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when `STORAGE_TYPE` is `minio` + +And you can also define a customize storage like below: + +```ini +[storage.my_minio] +STORAGE_TYPE = minio +; Minio endpoint to connect only available when STORAGE_TYPE is `minio` +MINIO_ENDPOINT = localhost:9000 +; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio` +MINIO_ACCESS_KEY_ID = +; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` +MINIO_SECRET_ACCESS_KEY = +; Minio bucket to store the attachments only available when STORAGE_TYPE is `minio` +MINIO_BUCKET = gitea +; Minio location to create bucket only available when STORAGE_TYPE is `minio` +MINIO_LOCATION = us-east-1 +; Minio enabled ssl only available when STORAGE_TYPE is `minio` +MINIO_USE_SSL = false +``` + +And used by `[attachment]`, `[lfs]` and etc. as `STORAGE_TYPE`. ## Other (`other`) - `SHOW_FOOTER_BRANDING`: **false**: Show Gitea branding in the footer. -- `SHOW_FOOTER_VERSION`: **true**: Show Gitea version information in the footer. +- `SHOW_FOOTER_VERSION`: **true**: Show Gitea and Go version information in the footer. - `SHOW_FOOTER_TEMPLATE_LOAD_TIME`: **true**: Show time of template execution in the footer. 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 082944c8a4a22..da2d02c11dcca 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -15,7 +15,9 @@ menu: # 配置说明 -这是针对Gitea配置文件的说明,你可以了解Gitea的强大配置。需要说明的是,你的所有改变请修改 `custom/conf/app.ini` 文件而不是源文件。所有默认值可以通过 [app.ini.sample](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.ini.sample) 查看到。如果你发现 `%(X)s` 这样的内容,请查看 [ini](https://github.com/go-ini/ini/#recursive-values) 这里的说明。标注了 :exclamation: 的配置项表明除非你真的理解这个配置项的意义,否则最好使用默认值。 +这是针对Gitea配置文件的说明,你可以了解Gitea的强大配置。需要说明的是,你的所有改变请修改 `custom/conf/app.ini` 文件而不是源文件。所有默认值可以通过 [app.example.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini) 查看到。如果你发现 `%(X)s` 这样的内容,请查看 [ini](https://github.com/go-ini/ini/#recursive-values) 这里的说明。标注了 :exclamation: 的配置项表明除非你真的理解这个配置项的意义,否则最好使用默认值。 + +{{< toc >}} ## Overall (`DEFAULT`) @@ -30,6 +32,7 @@ menu: - `ANSI_CHARSET`: 默认字符编码。 - `FORCE_PRIVATE`: 强制所有git工程必须私有。 - `DEFAULT_PRIVATE`: 默认创建的git工程为私有。 可以是`last`, `private` 或 `public`。默认值是 `last`表示用户最后创建的Repo的选择。 +- `DEFAULT_PUSH_CREATE_PRIVATE`: **true**: 通过 ``push-to-create`` 方式创建的仓库是否默认为私有仓库. - `MAX_CREATION_LIMIT`: 全局最大每个用户创建的git工程数目, `-1` 表示没限制。 - `PULL_REQUEST_QUEUE_LENGTH`: 小心:合并请求测试队列的长度,尽量放大。 @@ -67,10 +70,10 @@ menu: - `KEY_FILE`: 启用HTTPS的密钥文件。 - `STATIC_ROOT_PATH`: 存放模板和静态文件的根目录,默认是 Gitea 的根目录。 - `STATIC_CACHE_TIME`: **6h**: 静态资源文件,包括 `custom/`, `public/` 和所有上传的头像的浏览器缓存时间。 -- `ENABLE_GZIP`: 启用应用级别的 GZIP 压缩。 +- `ENABLE_GZIP`: 启用实时生成的数据启用 GZIP 压缩,不包括静态资源。 - `LANDING_PAGE`: 未登录用户的默认页面,可选 `home` 或 `explore`。 + - `LFS_START_SERVER`: 是否启用 git-lfs 支持. 可以为 `true` 或 `false`, 默认是 `false`。 -- `LFS_CONTENT_PATH`: 存放 lfs 命令上传的文件的地方,默认是 `data/lfs`。 - `LFS_JWT_SECRET`: LFS 认证密钥,改成自己的。 ## Database (`database`) @@ -81,7 +84,7 @@ menu: - `USER`: 数据库用户名。 - `PASSWD`: 数据库用户密码。 - `SSL_MODE`: MySQL 或 PostgreSQL数据库是否启用SSL模式。 -- `CHARSET`: **utf8**: 仅当数据库为 MySQL 时有效, 可以为 "utf8" 或 "utf8mb4"。注意:如果使用 "utf8mb4",你的 MySQL InnoDB 版本必须在 5.6 以上。 +- `CHARSET`: **utf8mb4**: 仅当数据库为 MySQL 时有效, 可以为 "utf8" 或 "utf8mb4"。注意:如果使用 "utf8mb4",你的 MySQL InnoDB 版本必须在 5.6 以上。 - `PATH`: Tidb 或者 SQLite3 数据文件存放路径。 - `LOG_SQL`: **true**: 显示生成的SQL,默认为真。 - `MAX_IDLE_CONNS` **0**: 最大空闲数据库连接 @@ -98,8 +101,12 @@ menu: - `ISSUE_INDEXER_QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: 当 `ISSUE_INDEXER_QUEUE_TYPE` 为 `redis` 时,保存Redis队列的连接字符串。 - `ISSUE_INDEXER_QUEUE_BATCH_NUMBER`: **20**: 队列处理中批量提交数量。 -- `REPO_INDEXER_ENABLED`: **false**: 是否启用代码搜索(启用后会占用比较大的磁盘空间)。 +- `REPO_INDEXER_ENABLED`: **false**: 是否启用代码搜索(启用后会占用比较大的磁盘空间,如果是bleve可能需要占用约6倍存储空间)。 +- `REPO_INDEXER_TYPE`: **bleve**: 代码搜索引擎类型,可以为 `bleve` 或者 `elasticsearch`。 - `REPO_INDEXER_PATH`: **indexers/repos.bleve**: 用于代码搜索的索引文件路径。 +- `REPO_INDEXER_CONN_STR`: ****: 代码搜索引擎连接字符串,当 `REPO_INDEXER_TYPE` 为 `elasticsearch` 时有效。例如: http://elastic:changeme@localhost:9200 +- `REPO_INDEXER_NAME`: **gitea_codes**: 代码搜索引擎的名字,当 `REPO_INDEXER_TYPE` 为 `elasticsearch` 时有效。 + - `UPDATE_BUFFER_LEN`: **20**: 代码索引请求的缓冲区长度。 - `MAX_FILE_SIZE`: **1048576**: 进行解析的源代码文件的最大长度,小于该值时才会索引。 @@ -117,6 +124,7 @@ menu: - `ACTIVE_CODE_LIVE_MINUTES`: 登录验证码失效时间,单位分钟。 - `RESET_PASSWD_CODE_LIVE_MINUTES`: 重置密码失效时间,单位分钟。 - `REGISTER_EMAIL_CONFIRM`: 启用注册邮件激活,前提是 `Mailer` 已经启用。 +- `REGISTER_MANUAL_CONFIRM`: **false**: 新注册用户必须由管理员手动激活,启用此选项需取消`REGISTER_EMAIL_CONFIRM`. - `DISABLE_REGISTRATION`: 禁用注册,启用后只能用管理员添加用户。 - `SHOW_REGISTRATION_BUTTON`: 是否显示注册按钮。 - `REQUIRE_SIGNIN_VIEW`: 是否所有页面都必须登录后才可访问。 @@ -177,13 +185,35 @@ menu: - `DISABLE_GRAVATAR`: 开启则只使用内部头像。 - `ENABLE_FEDERATED_AVATAR`: 启用头像联盟支持 (参见 http://www.libravatar.org) +- `AVATAR_STORAGE_TYPE`: **local**: 头像存储类型,可以为 `local` 或 `minio`,分别支持本地文件系统和 minio 兼容的API。 +- `AVATAR_UPLOAD_PATH`: **data/avatars**: 存储头像的文件系统路径。 +- `AVATAR_MAX_WIDTH`: **4096**: 头像最大宽度,单位像素。 +- `AVATAR_MAX_HEIGHT`: **3072**: 头像最大高度,单位像素。 +- `AVATAR_MAX_FILE_SIZE`: **1048576** (1Mb): 头像最大大小。 + +- `REPOSITORY_AVATAR_STORAGE_TYPE`: **local**: 仓库头像存储类型,可以为 `local` 或 `minio`,分别支持本地文件系统和 minio 兼容的API。 +- `REPOSITORY_AVATAR_UPLOAD_PATH`: **data/repo-avatars**: 存储仓库头像的路径。 +- `REPOSITORY_AVATAR_FALLBACK`: **none**: 当头像丢失时的处理方式 + - none = 不显示头像 + - random = 显示随机生成的头像 + - image = 显示默认头像,通过 `REPOSITORY_AVATAR_FALLBACK_IMAGE` 设置 +- `REPOSITORY_AVATAR_FALLBACK_IMAGE`: **/img/repo_default.png**: 默认仓库头像 + ## Attachment (`attachment`) - `ENABLED`: 是否允许用户上传附件。 -- `PATH`: 附件存储路径 - `ALLOWED_TYPES`: 允许上传的附件类型。比如:`image/jpeg|image/png`,用 `*/*` 表示允许任何类型。 - `MAX_SIZE`: 附件最大限制,单位 MB,比如: `4`。 - `MAX_FILES`: 一次最多上传的附件数量,比如: `5`。 +- `STORAGE_TYPE`: **local**: 附件存储类型,`local` 将存储到本地文件夹, `minio` 将存储到 s3 兼容的对象存储服务中。 +- `PATH`: **data/attachments**: 附件存储路径,仅当 `STORAGE_TYPE` 为 `local` 时有效。 +- `MINIO_ENDPOINT`: **localhost:9000**: Minio 终端,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID ,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 +- `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 +- `MINIO_BUCKET`: **gitea**: Minio bucket to store the attachments,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 +- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 +- `MINIO_BASE_PATH`: **attachments/**: Minio base path on the bucket,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 +- `MINIO_USE_SSL`: **false**: Minio enabled ssl,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 关于 `ALLOWED_TYPES`, 在 (*)unix 系统中可以使用`file -I ` 来快速获得对应的 `MIME type`。 @@ -286,6 +316,58 @@ IS_INPUT_FILE = false - `MAX_ATTEMPTS`: **3**: 在迁移过程中的 http/https 请求重试次数。 - `RETRY_BACKOFF`: **3**: 等待下一次重试的时间,单位秒。 +- `ALLOWED_DOMAINS`: **\**: 迁移仓库的域名白名单,默认为空,表示允许从任意域名迁移仓库,多个域名用逗号分隔。 +- `BLOCKED_DOMAINS`: **\**: 迁移仓库的域名黑名单,默认为空,多个域名用逗号分隔。如果 `ALLOWED_DOMAINS` 不为空,此选项将会被忽略。 +- `ALLOW_LOCALNETWORKS`: **false**: Allow private addresses defined by RFC 1918 + +## LFS (`lfs`) + +LFS 的存储配置。 如果 `STORAGE_TYPE` 为空,则此配置将从 `[storage]` 继承。如果不为 `local` 或者 `minio` 而为 `xxx`, 则从 `[storage.xxx]` 继承。当继承时, `PATH` 默认为 `data/lfs`,`MINIO_BASE_PATH` 默认为 `lfs/`。 + +- `STORAGE_TYPE`: **local**: LFS 的存储类型,`local` 将存储到磁盘,`minio` 将存储到 s3 兼容的对象服务。 +- `SERVE_DIRECT`: **false**: 允许直接重定向到存储系统。当前,仅 Minio/S3 是支持的。 +- `CONTENT_PATH`: 存放 lfs 命令上传的文件的地方,默认是 `data/lfs`。 +- `MINIO_ENDPOINT`: **localhost:9000**: Minio 地址,仅当 `LFS_STORAGE_TYPE` 为 `minio` 时有效。 +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID,仅当 `LFS_STORAGE_TYPE` 为 `minio` 时有效。 +- `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey,仅当 `LFS_STORAGE_TYPE` 为 `minio` 时有效。 +- `MINIO_BUCKET`: **gitea**: Minio bucket,仅当 `LFS_STORAGE_TYPE` 为 `minio` 时有效。 +- `MINIO_LOCATION`: **us-east-1**: Minio location ,仅当 `LFS_STORAGE_TYPE` 为 `minio` 时有效。 +- `MINIO_BASE_PATH`: **lfs/**: Minio base path ,仅当 `LFS_STORAGE_TYPE` 为 `minio` 时有效。 +- `MINIO_USE_SSL`: **false**: Minio 是否启用 ssl ,仅当 `LFS_STORAGE_TYPE` 为 `minio` 时有效。 + +## Storage (`storage`) + +Attachments, lfs, avatars and etc 的默认存储配置。 + +- `STORAGE_TYPE`: **local**: 附件存储类型,`local` 将存储到本地文件夹, `minio` 将存储到 s3 兼容的对象存储服务中。 +- `SERVE_DIRECT`: **false**: 允许直接重定向到存储系统。当前,仅 Minio/S3 是支持的。 +- `MINIO_ENDPOINT`: **localhost:9000**: Minio 终端,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID ,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 +- `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 +- `MINIO_BUCKET`: **gitea**: Minio bucket to store the attachments,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 +- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 +- `MINIO_USE_SSL`: **false**: Minio enabled ssl,仅当 `STORAGE_TYPE` 是 `minio` 时有效。 + +你也可以自定义一个存储的名字如下: + +```ini +[storage.my_minio] +STORAGE_TYPE = minio +; Minio endpoint to connect only available when STORAGE_TYPE is `minio` +MINIO_ENDPOINT = localhost:9000 +; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio` +MINIO_ACCESS_KEY_ID = +; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` +MINIO_SECRET_ACCESS_KEY = +; Minio bucket to store the attachments only available when STORAGE_TYPE is `minio` +MINIO_BUCKET = gitea +; Minio location to create bucket only available when STORAGE_TYPE is `minio` +MINIO_LOCATION = us-east-1 +; Minio enabled ssl only available when STORAGE_TYPE is `minio` +MINIO_USE_SSL = false +``` + +然后你在 `[attachment]`, `[lfs]` 等中可以把这个名字用作 `STORAGE_TYPE` 的值。 ## Other (`other`) diff --git a/docs/content/doc/advanced/customizing-gitea.en-us.md b/docs/content/doc/advanced/customizing-gitea.en-us.md index b52a713e40af1..4ca5a42852680 100644 --- a/docs/content/doc/advanced/customizing-gitea.en-us.md +++ b/docs/content/doc/advanced/customizing-gitea.en-us.md @@ -30,32 +30,50 @@ the Linux Filesystem Standard. Gitea will attempt to create required folders, in `custom/`. Distributions may provide a symlink for `custom` using `/etc/gitea/`. Application settings can be found in file `CustomConf` which is by default, -`CustomPath/conf/app.ini` but may be different if your build has set this differently. +`$GITEA_CUSTOM/conf/app.ini` but may be different if your build has set this differently. Again `gitea help` will allow you review this variable and you can override it using the `--config` option on the `gitea` binary. - [Quick Cheat Sheet](https://docs.gitea.io/en-us/config-cheat-sheet/) -- [Complete List](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.ini.sample) +- [Complete List](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini) If the `CustomPath` folder can't be found despite checking `gitea help`, check the `GITEA_CUSTOM` environment variable; this can be used to override the default path to something else. -`GITEA_CUSTOM` might, for example, be set by an init script. +`GITEA_CUSTOM` might, for example, be set by an init script. You can check whether the value +is set under the "Configuration" tab on the site administration page. - [List of Environment Variables](https://docs.gitea.io/en-us/specific-variables/) **Note:** Gitea must perform a full restart to see configuration changes. +**Table of Contents** + +{{< toc >}} + ## Serving custom public files To make Gitea serve custom public files (like pages and images), use the folder -`custom/public/` as the webroot. Symbolic links will be followed. +`$GITEA_CUSTOM/public/` as the webroot. Symbolic links will be followed. -For example, a file `image.png` stored in `custom/public/`, can be accessed with +For example, a file `image.png` stored in `$GITEA_CUSTOM/public/`, can be accessed with the url `http://gitea.domain.tld/image.png`. +## Changing the default logo + +To build a custom logo replace `assets/logo.svg` and run `make generate-images`. This will update +these customizable logo files which you can then place in `$GITEA_CUSTOM/public/img` on your server: + +- `public/img/logo.svg` +- `public/img/logo.png` +- `public/img/favicon.png` +- `public/img/avatar_default.png` +- `public/img/apple-touch-icon.png` + ## Changing the default avatar -Place the png image at the following path: `custom/public/img/avatar_default.png` +Either generate it via above method or place the png image at the following path: + +- `$GITEA_CUSTOM/public/img/avatar_default.png` ## Customizing Gitea pages and resources @@ -63,11 +81,11 @@ Gitea's executable contains all the resources required to run: templates, images and translations. Any of them can be overridden by placing a replacement in a matching path inside the `custom` directory. For example, to replace the default `.gitignore` provided for C++ repositories, we want to replace `options/gitignore/C++`. To do this, a replacement -must be placed in `custom/options/gitignore/C++` (see about the location of the `custom` +must be placed in `$GITEA_CUSTOM/options/gitignore/C++` (see about the location of the `CustomPath` directory at the top of this document). Every single page of Gitea can be changed. Dynamic content is generated using [go templates](https://golang.org/pkg/html/template/), -which can be modified by placing replacements below the `custom/templates` directory. +which can be modified by placing replacements below the `$GITEA_CUSTOM/templates` directory. To obtain any embedded file (including templates), the [`gitea embedded` tool]({{< relref "doc/advanced/cmd-embedded.en-us.md" >}}) can be used. Alternatively, they can be found in the [`templates`](https://github.com/go-gitea/gitea/tree/master/templates) directory of Gitea source (Note: the example link is from the `master` branch. Make sure to use templates compatible with the release you are using). @@ -76,16 +94,16 @@ shouldn't be touched without fully understanding these components. ### Customizing startpage / homepage -Copy [`home.tmpl`](https://github.com/go-gitea/gitea/blob/master/templates/home.tmpl) for your version of Gitea from `templates` to `custom/templates`. +Copy [`home.tmpl`](https://github.com/go-gitea/gitea/blob/master/templates/home.tmpl) for your version of Gitea from `templates` to `$GITEA_CUSTOM/templates`. Edit as you wish. Dont forget to restart your gitea to apply the changes. ### Adding links and tabs -If all you want is to add extra links to the top navigation bar or footer, or extra tabs to the repository view, you can put them in `extra_links.tmpl` (links added to the navbar), `extra_links_footer.tmpl` (links added to the left side of footer), and `extra_tabs.tmpl` inside your `custom/templates/custom/` directory. +If all you want is to add extra links to the top navigation bar or footer, or extra tabs to the repository view, you can put them in `extra_links.tmpl` (links added to the navbar), `extra_links_footer.tmpl` (links added to the left side of footer), and `extra_tabs.tmpl` inside your `$GITEA_CUSTOM/templates/custom/` directory. For instance, let's say you are in Germany and must add the famously legally-required "Impressum"/about page, listing who is responsible for the site's content: -just place it under your "custom/public/" directory (for instance `custom/public/impressum.html`) and put a link to it in either `custom/templates/custom/extra_links.tmpl` or `custom/templates/custom/extra_links_footer.tmpl`. +just place it under your "$GITEA_CUSTOM/public/" directory (for instance `$GITEA_CUSTOM/public/impressum.html`) and put a link to it in either `$GITEA_CUSTOM/templates/custom/extra_links.tmpl` or `$GITEA_CUSTOM/templates/custom/extra_links_footer.tmpl`. To match the current style, the link should have the class name "item", and you can use `{{AppSubUrl}}` to get the base URL: `Impressum` @@ -99,7 +117,7 @@ The exact HTML needed to match the style of other tabs is in the file ### Other additions to the page -Apart from `extra_links.tmpl` and `extra_tabs.tmpl`, there are other useful templates you can put in your `custom/templates/custom/` directory: +Apart from `extra_links.tmpl` and `extra_tabs.tmpl`, there are other useful templates you can put in your `$GITEA_CUSTOM/templates/custom/` directory: - `header.tmpl`, just before the end of the `` tag where you can add custom CSS files for instance. - `body_outer_pre.tmpl`, right after the start of ``. @@ -108,45 +126,6 @@ Apart from `extra_links.tmpl` and `extra_tabs.tmpl`, there are other useful temp - `body_outer_post.tmpl`, before the bottom `