Merge branch 'main' into sync-issue-pr-and-more

This commit is contained in:
harryzcy 2023-04-06 02:18:29 -04:00
commit c733415026
No known key found for this signature in database
GPG Key ID: E3C2287691E40E35
3955 changed files with 116642 additions and 71944 deletions

View File

@ -5,6 +5,6 @@ tmp_dir = ".air"
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"]
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata", "models/fixtures", "models/migrations/fixtures", "modules/migration/file_format_testdata", "modules/avatar/identicon/testdata"]
include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
exclude_regex = ["_test.go$", "_gen.go$"]

114
.dockerignore Normal file
View File

@ -0,0 +1,114 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# IntelliJ
.idea
# Goland's output filename can not be set manually
/go_build_*
# MS VSCode
.vscode
__debug_bin
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
*coverage.out
coverage.all
cpu.out
/modules/migration/bindata.go
/modules/migration/bindata.go.hash
/modules/options/bindata.go
/modules/options/bindata.go.hash
/modules/public/bindata.go
/modules/public/bindata.go.hash
/modules/templates/bindata.go
/modules/templates/bindata.go.hash
*.db
*.log
/gitea
/gitea-vet
/debug
/integrations.test
/bin
/dist
/custom/*
!/custom/conf
/custom/conf/*
!/custom/conf/app.example.ini
/data
/indexers
/log
/public/img/avatar
/tests/integration/gitea-integration-*
/tests/integration/indexers-*
/tests/e2e/gitea-e2e-*
/tests/e2e/indexers-*
/tests/e2e/reports
/tests/e2e/test-artifacts
/tests/e2e/test-snapshots
/tests/*.ini
/node_modules
/yarn.lock
/yarn-error.log
/npm-debug.log*
/public/js
/public/serviceworker.js
/public/css
/public/fonts
/public/img/webpack
/vendor
/web_src/fomantic/node_modules
/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
/.go-licenses
# Snapcraft
snap/.snapcraft/
parts/
stage/
prime/
*.snap
*.snap-build
*_source.tar.bz2
.DS_Store
# Make evidence files
/.make_evidence
# Manpage
/man

File diff suppressed because it is too large Load Diff

View File

@ -35,9 +35,6 @@ overrides:
rules:
import/no-unresolved: [0]
import/no-extraneous-dependencies: [0]
- files: ["*.test.js"]
env:
jest: true
- files: ["*.config.js"]
rules:
import/no-unused-modules: [0]
@ -46,7 +43,7 @@ rules:
accessor-pairs: [2]
array-bracket-newline: [0]
array-bracket-spacing: [2, never]
array-callback-return: [0]
array-callback-return: [2, {checkForEach: true}]
array-element-newline: [0]
arrow-body-style: [0]
arrow-parens: [2, always]
@ -87,6 +84,7 @@ rules:
id-length: [0]
id-match: [0]
implicit-arrow-linebreak: [0]
import/consistent-type-specifier-style: [0]
import/default: [0]
import/dynamic-import-chunkname: [0]
import/export: [2]
@ -106,6 +104,7 @@ rules:
import/no-default-export: [0]
import/no-deprecated: [0]
import/no-dynamic-require: [0]
import/no-empty-named-blocks: [2]
import/no-extraneous-dependencies: [2]
import/no-import-module-exports: [0]
import/no-internal-modules: [0]
@ -150,7 +149,7 @@ rules:
jquery/no-global-eval: [2]
jquery/no-grep: [2]
jquery/no-has: [2]
jquery/no-hide: [0]
jquery/no-hide: [2]
jquery/no-html: [0]
jquery/no-in-array: [2]
jquery/no-is-array: [2]
@ -165,15 +164,15 @@ rules:
jquery/no-parse-html: [2]
jquery/no-prop: [0]
jquery/no-proxy: [2]
jquery/no-ready: [0]
jquery/no-ready: [2]
jquery/no-serialize: [2]
jquery/no-show: [0]
jquery/no-show: [2]
jquery/no-size: [2]
jquery/no-sizzle: [0]
jquery/no-slide: [0]
jquery/no-submit: [0]
jquery/no-text: [0]
jquery/no-toggle: [0]
jquery/no-toggle: [2]
jquery/no-trigger: [0]
jquery/no-trim: [2]
jquery/no-val: [0]
@ -185,6 +184,7 @@ rules:
linebreak-style: [2, unix]
lines-around-comment: [0]
lines-between-class-members: [0]
logical-assignment-operators: [0]
max-classes-per-file: [0]
max-depth: [0]
max-len: [0]
@ -201,7 +201,7 @@ rules:
newline-per-chained-call: [0]
no-alert: [0]
no-array-constructor: [2]
no-async-promise-executor: [2]
no-async-promise-executor: [0]
no-await-in-loop: [0]
no-bitwise: [0]
no-buffer-constructor: [0]
@ -231,6 +231,7 @@ rules:
no-empty-character-class: [2]
no-empty-function: [0]
no-empty-pattern: [2]
no-empty-static-block: [2]
no-empty: [2, {allowEmptyCatch: true}]
no-eq-null: [2]
no-eval: [2]
@ -245,7 +246,7 @@ rules:
no-floating-decimal: [0]
no-func-assign: [2]
no-global-assign: [2]
no-implicit-coercion: [0]
no-implicit-coercion: [2]
no-implicit-globals: [0]
no-implied-eval: [2]
no-import-assign: [2]
@ -256,7 +257,7 @@ rules:
no-irregular-whitespace: [2]
no-iterator: [2]
no-label-var: [2]
no-labels: [2]
no-labels: [0] # handled by no-restricted-syntax
no-lone-blocks: [2]
no-lonely-if: [0]
no-loop-func: [0]
@ -271,6 +272,7 @@ rules:
no-negated-condition: [0]
no-nested-ternary: [0]
no-new-func: [2]
no-new-native-nonconstructor: [2]
no-new-object: [2]
no-new-symbol: [2]
no-new-wrappers: [2]
@ -322,7 +324,7 @@ rules:
no-unused-private-class-members: [2]
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_, ignoreRestSiblings: false}]
no-use-before-define: [2, {functions: false, classes: true, variables: true, allowNamedExports: true}]
no-useless-backreference: [0]
no-useless-backreference: [2]
no-useless-call: [2]
no-useless-catch: [2]
no-useless-computed-key: [2]
@ -335,7 +337,7 @@ rules:
no-void: [2]
no-warning-comments: [0]
no-whitespace-before-property: [2]
no-with: [2]
no-with: [0] # handled by no-restricted-syntax
nonblock-statement-body-position: [2]
object-curly-newline: [0]
object-curly-spacing: [2, never]
@ -353,7 +355,7 @@ rules:
prefer-named-capture-group: [0]
prefer-numeric-literals: [2]
prefer-object-has-own: [0]
prefer-object-spread: [0]
prefer-object-spread: [2]
prefer-promise-reject-errors: [2, {allowEmptyReject: false}]
prefer-regex-literals: [2]
prefer-rest-params: [2]
@ -380,11 +382,11 @@ rules:
sonarjs/no-duplicated-branches: [0]
sonarjs/no-element-overwrite: [2]
sonarjs/no-empty-collection: [2]
sonarjs/no-extra-arguments: [0]
sonarjs/no-extra-arguments: [2]
sonarjs/no-gratuitous-expressions: [2]
sonarjs/no-identical-conditions: [2]
sonarjs/no-identical-expressions: [0]
sonarjs/no-identical-functions: [0]
sonarjs/no-identical-expressions: [2]
sonarjs/no-identical-functions: [2, 5]
sonarjs/no-ignored-return: [2]
sonarjs/no-inverted-boolean-check: [2]
sonarjs/no-nested-switch: [0]
@ -396,7 +398,7 @@ rules:
sonarjs/no-small-switch: [0]
sonarjs/no-unused-collection: [2]
sonarjs/no-use-of-empty-return-value: [2]
sonarjs/no-useless-catch: [0]
sonarjs/no-useless-catch: [2]
sonarjs/non-existent-operator: [2]
sonarjs/prefer-immediate-return: [0]
sonarjs/prefer-object-literal: [0]
@ -445,6 +447,7 @@ rules:
unicorn/no-invalid-remove-event-listener: [2]
unicorn/no-keyword-prefix: [0]
unicorn/no-lonely-if: [2]
unicorn/no-negated-condition: [0]
unicorn/no-nested-ternary: [0]
unicorn/no-new-array: [0]
unicorn/no-new-buffer: [0]
@ -455,6 +458,8 @@ rules:
unicorn/no-static-only-class: [2]
unicorn/no-thenable: [2]
unicorn/no-this-assignment: [2]
unicorn/no-typeof-undefined: [2]
unicorn/no-unnecessary-await: [2]
unicorn/no-unreadable-array-destructuring: [0]
unicorn/no-unreadable-iife: [2]
unicorn/no-unsafe-regex: [0]
@ -492,7 +497,7 @@ rules:
unicorn/prefer-native-coercion-functions: [2]
unicorn/prefer-negative-index: [2]
unicorn/prefer-node-append: [0]
unicorn/prefer-node-protocol: [0]
unicorn/prefer-node-protocol: [2]
unicorn/prefer-node-remove: [0]
unicorn/prefer-number-properties: [0]
unicorn/prefer-object-from-entries: [2]
@ -504,6 +509,7 @@ rules:
unicorn/prefer-regexp-test: [2]
unicorn/prefer-replace-all: [0]
unicorn/prefer-set-has: [0]
unicorn/prefer-set-size: [2]
unicorn/prefer-spread: [0]
unicorn/prefer-starts-ends-with: [2]
unicorn/prefer-string-slice: [0]
@ -519,6 +525,7 @@ rules:
unicorn/require-number-to-fixed-digits-argument: [2]
unicorn/require-post-message-target-origin: [0]
unicorn/string-content: [0]
unicorn/switch-case-braces: [0]
unicorn/template-indent: [2]
unicorn/text-encoding-identifier-case: [0]
unicorn/throw-new-error: [2]

1
.gitattributes vendored
View File

@ -1,5 +1,6 @@
* text=auto eol=lf
*.tmpl linguist-language=Handlebars
/assets/*.json linguist-generated
/public/vendor/** -text -eol linguist-vendored
/vendor/** -text -eol linguist-vendored
/web_src/fomantic/build/** linguist-generated

View File

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

24
.gitignore vendored
View File

@ -63,21 +63,14 @@ cpu.out
/indexers
/log
/public/img/avatar
/integrations/gitea-integration-mysql
/integrations/gitea-integration-mysql8
/integrations/gitea-integration-pgsql
/integrations/gitea-integration-sqlite
/integrations/gitea-integration-mssql
/integrations/indexers-mysql
/integrations/indexers-mysql8
/integrations/indexers-pgsql
/integrations/indexers-sqlite
/integrations/indexers-mssql
/integrations/sqlite.ini
/integrations/mysql.ini
/integrations/mysql8.ini
/integrations/pgsql.ini
/integrations/mssql.ini
/tests/integration/gitea-integration-*
/tests/integration/indexers-*
/tests/e2e/gitea-e2e-*
/tests/e2e/indexers-*
/tests/e2e/reports
/tests/e2e/test-artifacts
/tests/e2e/test-snapshots
/tests/*.ini
/node_modules
/yarn.lock
/yarn-error.log
@ -102,6 +95,7 @@ cpu.out
!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2
/VERSION
/.air
/.go-licenses
# Snapcraft
snap/.snapcraft/

50
.gitpod.yml Normal file
View File

@ -0,0 +1,50 @@
tasks:
- name: Setup
init: |
cp -r contrib/ide/vscode .vscode
make deps
make build
command: |
gp sync-done setup
exit 0
- name: Run backend
command: |
gp sync-await setup
if [ ! -f custom/conf/app.ini ]
then
mkdir -p custom/conf/
echo -e "[server]\nROOT_URL=$(gp url 3000)/" > custom/conf/app.ini
echo -e "\n[database]\nDB_TYPE = sqlite3\nPATH = $GITPOD_REPO_ROOT/data/gitea.db" >> custom/conf/app.ini
fi
export TAGS="sqlite sqlite_unlock_notify"
make watch-backend
- name: Run frontend
command: |
gp sync-await setup
make watch-frontend
openMode: split-right
- name: Run docs
command: |
gp sync-await setup
cd docs
make clean update
hugo server -D -F --baseUrl $(gp url 1313) --liveReloadPort=443 --appendPort=false --bind=0.0.0.0
openMode: split-right
vscode:
extensions:
- editorconfig.editorconfig
- dbaeumer.vscode-eslint
- golang.go
- stylelint.vscode-stylelint
- DavidAnson.vscode-markdownlint
- johnsoncodehk.volar
- ms-azuretools.vscode-docker
- zixuanchen.vitest-explorer
- alexcvzz.vscode-sqlite
ports:
- name: Gitea
port: 3000
- name: Docs
port: 1313

View File

@ -1,35 +1,34 @@
linters:
enable:
- gosimple
- deadcode
- typecheck
- govet
- errcheck
- staticcheck
- unused
- structcheck
- varcheck
- dupl
#- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- misspell
- gocritic
- bidichk
- ineffassign
- revive
- gofumpt
# - deadcode # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- depguard
- dupl
- errcheck
- gocritic
# - gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- gofumpt
- gosimple
- govet
- ineffassign
- nakedret
- unconvert
- wastedassign
- nolintlint
- revive
- staticcheck
# - structcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- stylecheck
- typecheck
- unconvert
- unused
# - varcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
# - wastedassign # disabled - https://github.com/golangci/golangci-lint/issues/2649
enable-all: false
disable-all: true
fast: false
run:
go: 1.19
go: "1.20"
timeout: 10m
skip-dirs:
- node_modules
@ -40,7 +39,7 @@ linters-settings:
stylecheck:
checks: ["all", "-ST1005", "-ST1003"]
nakedret:
max-func-lines: 0
max-func-lines: 0
gocritic:
disabled-checks:
- ifElseChain
@ -75,17 +74,21 @@ linters-settings:
- name: modifies-value-receiver
gofumpt:
extra-rules: true
lang-version: "1.19"
lang-version: "1.20"
depguard:
# TODO: use depguard to replace import checks in gitea-vet
list-type: denylist
# Check the list against standard lib.
include-go-root: true
packages-with-error-message:
- encoding/json: "use gitea's modules/json instead of encoding/json"
- github.com/unknwon/com: "use gitea's util and replacements"
- io/ioutil: "use os or io instead"
- golang.org/x/exp: "it's experimental and unreliable."
- code.gitea.io/gitea/modules/git/internal: "do not use the internal package, use AddXxx function instead"
issues:
max-issues-per-linter: 0
max-same-issues: 0
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test\.go
@ -146,9 +149,6 @@ issues:
- path: models/issue_comment_list.go
linters:
- dupl
- linters:
- misspell
text: '`Unknwon` is a misspelling of `Unknown`'
- path: models/update.go
linters:
- unused

1
.npmrc
View File

@ -3,3 +3,4 @@ fund=false
update-notifier=false
package-lock=true
save-exact=true
lockfile-version=3

View File

@ -1,32 +1,138 @@
extends: stylelint-config-standard
plugins:
- stylelint-declaration-strict-value
ignoreFiles:
- "**/*.go"
overrides:
- files: ["**/*.less"]
customSyntax: postcss-less
- files: ["**/chroma/*", "**/codemirror/*", "**/standalone/*", "**/console/*"]
rules:
scale-unlimited/declaration-strict-value: null
- files: ["**/chroma/*", "**/codemirror/*"]
rules:
block-no-empty: null
rules:
alpha-value-notation: null
annotation-no-unknown: true
at-rule-allowed-list: null
at-rule-disallowed-list: null
at-rule-empty-line-before: null
block-closing-brace-empty-line-before: null
at-rule-no-unknown: true
at-rule-no-vendor-prefix: true
at-rule-property-required-list: null
block-no-empty: true
color-function-notation: null
color-hex-alpha: null
color-hex-length: null
color-named: null
color-no-hex: null
color-no-invalid-hex: true
comment-empty-line-before: null
comment-no-empty: true
comment-pattern: null
comment-whitespace-inside: null
comment-word-disallowed-list: null
custom-media-pattern: null
custom-property-empty-line-before: null
custom-property-no-missing-var-function: true
custom-property-pattern: null
declaration-block-no-duplicate-custom-properties: true
declaration-block-no-duplicate-properties: [true, {ignore: [consecutive-duplicates-with-different-values]}]
declaration-block-no-redundant-longhand-properties: null
declaration-block-no-shorthand-property-overrides: null
declaration-block-single-line-max-declarations: null
declaration-empty-line-before: null
declaration-no-important: null
declaration-property-max-values: null
declaration-property-unit-allowed-list: null
declaration-property-unit-disallowed-list: null
declaration-property-value-allowed-list: null
declaration-property-value-disallowed-list: null
declaration-property-value-no-unknown: true
font-family-name-quotes: always-where-recommended
font-family-no-duplicate-names: true
font-family-no-missing-generic-family-keyword: true
font-weight-notation: null
function-allowed-list: null
function-calc-no-unspaced-operator: true
function-disallowed-list: null
function-linear-gradient-no-nonstandard-direction: true
function-name-case: lower
function-no-unknown: null
function-url-no-scheme-relative: null
function-url-quotes: always
function-url-scheme-allowed-list: null
function-url-scheme-disallowed-list: null
hue-degree-notation: null
indentation: 2
max-line-length: null
import-notation: string
keyframe-block-no-duplicate-selectors: true
keyframe-declaration-no-important: true
keyframe-selector-notation: null
keyframes-name-pattern: null
length-zero-no-unit: true
max-nesting-depth: null
media-feature-name-allowed-list: null
media-feature-name-disallowed-list: null
media-feature-name-no-unknown: true
media-feature-name-no-vendor-prefix: true
media-feature-name-unit-allowed-list: null
media-feature-name-value-allowed-list: null
media-feature-range-notation: null
named-grid-areas-no-invalid: true
no-descending-specificity: null
no-duplicate-at-import-rules: true
no-duplicate-selectors: true
no-empty-source: true
no-invalid-double-slash-comments: true
no-invalid-position-at-import-rule: null
number-leading-zero: never
no-irregular-whitespace: true
no-unknown-animations: null
no-unknown-custom-properties: null
number-max-precision: null
property-allowed-list: null
property-disallowed-list: null
property-no-unknown: true
property-no-vendor-prefix: null
rule-empty-line-before: null
rule-selector-property-disallowed-list: null
scale-unlimited/declaration-strict-value: [color, {ignoreValues: /^(inherit|transparent|unset|initial|currentcolor)$/}]
selector-attribute-name-disallowed-list: null
selector-attribute-operator-allowed-list: null
selector-attribute-operator-disallowed-list: null
selector-attribute-quotes: always
selector-class-pattern: null
selector-combinator-allowed-list: null
selector-combinator-disallowed-list: null
selector-disallowed-list: null
selector-id-pattern: null
selector-max-attribute: null
selector-max-class: null
selector-max-combinators: null
selector-max-compound-selectors: null
selector-max-id: null
selector-max-pseudo-class: null
selector-max-specificity: null
selector-max-type: null
selector-max-universal: null
selector-nested-pattern: null
selector-no-qualifying-type: null
selector-no-vendor-prefix: true
selector-not-notation: null
selector-pseudo-class-allowed-list: null
selector-pseudo-class-disallowed-list: null
selector-pseudo-class-no-unknown: true
selector-pseudo-element-allowed-list: null
selector-pseudo-element-colon-notation: double
selector-pseudo-element-disallowed-list: null
selector-pseudo-element-no-unknown: true
selector-type-case: lower
selector-type-no-unknown: [true, {ignore: [custom-elements]}]
shorthand-property-no-redundant-values: true
string-quotes: null
value-no-vendor-prefix: null
string-no-newline: true
time-min-milliseconds: null
unit-allowed-list: null
unit-disallowed-list: null
unit-no-unknown: true
value-keyword-case: null
value-no-vendor-prefix: [true, {ignoreValues: [box, inline-box]}]

View File

@ -4,6 +4,835 @@ 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.19.0](https://github.com/go-gitea/gitea/releases/tag/1.19.0) - 2023-03-19
* BREAKING
* Add loading yaml label template files (#22976) (#23232)
* Make issue and code search support camel case for Bleve (#22829)
* Repositories: by default disable all units except code and pulls on forks (#22541)
* Support template for merge message description (#22248)
* Remove ONLY_SHOW_RELEVANT_REPOS setting (#21962)
* Implement actions (#21937)
* Remove deprecated DSA host key from Docker Container (#21522)
* Improve valid user name check (#20136)
* SECURITY
* Return 404 instead of 403 if user can not access the repo (#23155) (#23158)
* Support scoped access tokens (#20908)
* FEATURES
* Add support for commit cross references (#22645)
* Scoped labels (#22585)
* Add Chef package registry (#22554)
* Support asciicast files as new markup (#22448)
* cgo cross-compile for freebsd (#22397)
* Add cron method to gc LFS MetaObjects (#22385)
* Add new captcha: cloudflare turnstile (#22369)
* Enable `@<user>`- completion popup on the release description textarea (#22359)
* make /{username}.png redirect to user/org avatar (#22356)
* Add Conda package registry (#22262)
* Support org/user level projects (#22235)
* Add Mermaid copy button (#22225)
* Add user secrets (#22191)
* Secrets storage with SecretKey encrypted (#22142)
* Preview images for Issue cards in Project Board view (#22112)
* Add support for incoming emails (#22056)
* Add Cargo package registry (#21888)
* Add option to prohibit fork if user reached maximum limit of repositories (#21848)
* Add attention blocks within quote blocks for `Note` and `Warning` (#21711)
* Add Feed for Releases and Tags (#21696)
* Add package registry cleanup rules (#21658)
* Add "Copy" button to file view of raw text (#21629)
* Allow disable sitemap (#21617)
* Add package registry quota limits (#21584)
* Map OIDC groups to Orgs/Teams (#21441)
* Keep languages defined in .gitattributes (#21403)
* Add Webhook authorization header (#20926)
* Supports wildcard protected branch (#20825)
* Copy citation file content, in APA and BibTex format, on repo home page (#19999)
* API
* Match api migration behavior to web behavior (#23552) (#23573)
* Purge API comment (#23451) (#23452)
* User creation API: allow custom "created" timestamps (#22549)
* Add `updated_at` field to PullReview API object (#21812)
* Add API management for issue/pull and comment attachments (#21783)
* Add API endpoint to get latest release (#21267)
* Support system hook API (#14537)
* ENHANCEMENTS
* Add `.patch` to `attachment.ALLOWED_TYPES` (#23580) (#23582)
* Fix sticky header in diff view (#23554) (#23568)
* Refactor merge/update git command calls (#23366) (#23544)
* Fix review comment context menu clipped bug (#23523) (#23543)
* Imrove scroll behavior to hash issuecomment(scroll position, auto expand if file is folded, and on refreshing) (#23513) (#23540)
* Increase horizontal page padding (#23507) (#23537)
* Use octicon-verified for gpg signatures (#23529) (#23536)
* Make time tooltips interactive (#23526) (#23527)
* Replace Less with CSS (#23508)
* Fix 'View File' button in code search (#23478) (#23483)
* Convert GitHub event on actions and fix some pull_request events. (#23037) (#23471)
* Support reflogs (#22451) (#23438)
* Fix actions frontend bugs (pagination, long name alignment) and small simplify (#23370) (#23436)
* Scoped label display and documentation tweaks (#23430) (#23433)
* Add missing tabs to org projects page (#22705) (#23412)
* Fix and move "Use this template" button (#23398) (#23408)
* Handle OpenID discovery URL errors a little nicer when creating/editing sources (#23397) (#23403)
* Rename `canWriteUnit` to `canWriteProjects` (#23386) (#23399)
* Refactor and tidy-up the merge/update branch code (#22568) (#23365)
* Refactor `setting.Database.UseXXX` to methods (#23354) (#23356)
* Fix incorrect project links and use symlink icon for org-wide projects (#23325) (#23336)
* Fix PR view misalignment caused by long name file (#23321) (#23335)
* Scoped labels: don't require holding alt key to remove (#23303) (#23331)
* Add context when rendering labels or emojis (#23281) (#23319)
* Change interactiveBorder to fix popup preview (#23169) (#23314)
* Scoped labels: set aria-disabled on muted Exclusive option for a11y (#23306) (#23311)
* update to mermaid v10 (#23178) (#23299)
* Fix code wrap for unbroken lines (#23268) (#23293)
* Use async await to fix empty quote reply at first time (#23168) (#23256)
* Fix switched citation format (#23250) (#23253)
* Allow `<video>` in MarkDown (#22892) (#23236)
* Order pull request conflict checking by recently updated, for each push (#23220) (#23225)
* Fix Fomantic UI's `touchstart` fastclick, always use `click` for click events (#23065) (#23195)
* Add word-break to sidebar-item-link (#23146) (#23180)
* Add InsecureSkipVerify to Minio Client for Storage (#23166) (#23177)
* Fix height for sticky head on large screen on PR page (#23111) (#23123)
* Change style to improve whitespaces trimming inside inline markdown code (#23093) (#23120)
* Avoid warning for system setting when start up (#23054) (#23116)
* Add accessibility to the menu on the navbar (#23059) (#23095)
* Improve accessibility for issue comments (#22612) (#23083)
* Remove delete button for review comment (#23036)
* Remove dashes between organization member avatars on hover (#23034)
* Use `gt-relative` class instead of the ambiguous `gt-pr` class (#23008)
* handle deprecated settings (#22992)
* Add scopes to API to create token and display them (#22989)
* Improve PR Review Box UI (#22986)
* Improve issues.LoadProject (#22982)
* Add all units to the units permission list in org team members sidebar (#22971)
* Rename `GetUnits` to `LoadUnits` (#22970)
* Rename `repo.GetOwner` to `repo.LoadOwner` (#22967)
* Rename "People" to "Members" in organization page and use a better icon (#22960)
* Fix avatar misalignment (#22955)
* Sort issues and pulls by recently updated in user and organization home (#22925)
* Add `title` to PR file tree items (#22918)
* First step to refactor the `.hide` to `.gt-hidden` (#22916)
* Add tooltip to issue reference (#22913)
* Always show the `command line instructions` button even if there are conflicts (#22909)
* Fix dark-colored description text in arc-green theme (#22908)
* Remove Fomantic-UI's `.hidden` CSS class for menu elements (#22895)
* Move helpers to be prefixed with `gt-` (#22879)
* Move `IsReadmeFile*` from `modules/markup/` to `modules/util` (#22877)
* Highlight focused diff file (#22870)
* Add some headings to repo views (#22869)
* Fix milestone title font problem (#22863)
* Pull Requests: setting to allow edits by maintainers by default, tweak UI (#22862)
* Introduce customized HTML elements, fix incorrect AppUrl usages in templates (#22861)
* Add `/$count` endpoints for NuGet v2 (#22855)
* Remove Fomantic-UI's `.hidden` CSS class for checkbox elements (#22851)
* Fix notification and stopwatch empty states (#22845)
* Always go full width in PR view (#22844)
* Improve AppUrl/ROOT_URL checking (#22836)
* Fix style of actions rerun button (#22835)
* Fix more HTMLURL in templates (#22831)
* Fix inconsistent Filter Project name in issue list (#22827)
* include build info in Prometheus metrics (#22819)
* Make clone URL use current page's host (#22808)
* Refactor legacy strange git operations (#22756)
* Improve error report when user passes a private key (#22726)
* set user dashboard org visibility to basic (#22706)
* Fix diff UI for unexpandable items (#22700)
* Remove 'primary' class from tab counter labels (#22687)
* Add more events details supports for actions (#22680)
* Refactor git command package to improve security and maintainability (#22678)
* Use relative url in actions view (#22675)
* set user visibility class to basic (#22674)
* Add repository setting to enable/disable releases unit (#22671)
* Remove label color from global issue filters (#22660)
* Fix poor alignment of organization description on organization home page (#22656)
* Small refactor for loading PRs (#22652)
* Allow setting access token scope by CLI (#22648)
* Improve accessibility of navigation bar and footer (#22635)
* Fixes accessibility behavior of Watching, Staring and Fork buttons (#22634)
* Fixes accessibility of empty repository commit status (#22632)
* Pull request yaml template support for including commit body in a field (#22629)
* Show migration validation error (#22619)
* set org visibility class to basic in header (#22605)
* Fix cache-control header clearing comment text when editing issue (#22604)
* Add ARIA support for Fomantic UI checkboxes (#22599)
* Add templates to customize text when creating and migrating repositories (#22597)
* Allow setting `redirect_to` cookie on OAuth login (#22594)
* Improve checkbox accessibility a bit by adding the title attribute (#22593)
* Allow issue templates to not render title (#22589)
* Webhooks: for issue close/reopen action, add commit ID that caused it (#22583)
* Fix missing title and filter in issue sidebar project menu (#22557)
* Issues: support setting issue template field values with query (#22545)
* Issues: add Project filter to issues list and search (#22544)
* Pull Requests: add color to approved/reject icon in pull requests list (#22543)
* Mute all links in issue timeline (#22533)
* Dropzone: Add "Copy link" button for new uploads (#22517)
* Support importing comment types (#22510)
* Load asciicast css async (#22502)
* Move delete user to service (#22478)
* Change use of Walk to WalkDir to improve disk performance (#22462)
* Add reply hint to mail text (#22459)
* fix wrong theme class when logged out if default theme is changed (#22408)
* Refactor the setting to make unit test easier (#22405)
* Improve utils of slices (#22379)
* Use context parameter in models/git (#22367)
* Always reuse transaction (#22362)
* Fix unstable emoji sort (#22346)
* Add context cache as a request level cache (#22294)
* Reminder for no more logs to console (#22282)
* Support estimated count with multiple schemas (#22276)
* Move `convert` package to services (#22264)
* Use dynamic package type list (#22263)
* Hide file borders on sticky diff box (#22217)
* Improve notification and stopwatch styles (#22169)
* Fixed Project view .board-column height for tall screens. (#22108)
* Use multi reader instead to concat strings (#22099)
* Use git command instead of exec.Cmd in blame (#22098)
* Fix autofilled text visibility in dark mode (#22088)
* Rename almost all Ctx functions (#22071)
* Rename actions to operations on UI (#22067)
* refactor bind functions based on generics (#22055)
* Support disabling database auto migration (#22053)
* remove duplicated read file code (#22042)
* Use link in UI which returned a relative url but not html_url which contains an absolute url (#21986)
* Skip initing disabled storages (#21985)
* Add doctor command for full GC of LFS (#21978)
* Util type to parse ref name (#21969)
* Replace fmt.Sprintf with hex.EncodeToString (#21960)
* Use random bytes to generate access token (#21959)
* Add index for access_token (#21908)
* Move all remaining colors into CSS variables (#21903)
* Webhook list enhancements (#21893)
* Embed Matrix icon as SVG (#21890)
* Remove useless "Cancel" buttons (#21872)
* fix(web): keep the pages of the navigation in the center (#21867)
* fix(web): reduce page jitter on browsers that support overlay scrollbar (#21850)
* Improvements for Content Copy (#21842)
* Tweak katex options (#21828)
* Show syntax lexer name in file view/blame (#21814)
* Remove `href="javascript:;"` in "save topics (Done)" button (#21813)
* Render number of commits in repo page in a user friendly way (#21786)
* Adjust clone timeout error to suggest increasing timeout (#21769)
* Update message of reach_limit_of_creation (#21757)
* Allow detect whether it's in a database transaction for a context.Context (#21756)
* Add configuration for CORS allowed headers (#21747)
* Move svg html render to modules/svg (#21716)
* Release and Tag List tweaks (#21712)
* Remove template previewer (#21701)
* Clean up formatting on install page (#21668)
* Configure update checker on installation page (#21655)
* Merge db.Iterate and IterateObjects (#21641)
* Add option to enable CAPTCHA validation for login (#21638)
* Allow disable RSS/Atom feed (#21622)
* Use CSS color-scheme instead of invert (#21616)
* Localize time units on activity heatmap (#21570)
* Fix UI column width, button overflow Fomantic's grid (#21559)
* feat: notify doers of a merge when automerging (#21553)
* Split migrations folder (#21549)
* feat: add button to quickly clear merge message (#21548)
* Add `context.Context` to more methods (#21546)
* Add index for hook_task table (#21545)
* Allow disable code tab (#20805)
* BUGFIXES
* Fix template error when reference Project (#23584)
* Fix dropdown icon misalignment when using fomantic icon (#23558) (#23577)
* Fix diff detail buttons wrapping, use tippy for review box (#23271) (#23546)
* Handle missing `README` in create repos API (#23387) (#23510)
* Disable sending email after push a commit to a closed PR (#23462) (#23492)
* Fix aria.js bugs: incorrect role element problem, mobile focus problem, tippy problem (#23450) (#23486)
* Fix due date being wrong on issue list (#23475) (#23477)
* Remove wrongly added column on migration test fixtures (#23456) (#23470)
* Make branches list page operations remember current page (#23420) (#23460)
* Fix missing commit status in PR which from forked repo (#23351) (#23453)
* Show edit/close/delete button on organization wide repositories (#23388) (#23429)
* Preserve file size when creating attachments (#23406) (#23426)
* Fix broken Chroma CSS styles (#23174) (#23402)
* Fix incorrect NotFound conditions in org/projects.go (#23384) (#23395)
* Set `X-Gitea-Debug` header once (#23361) (#23381)
* Pass context to avatar for projects view (#23359) (#23378)
* Fix panic when getting notes by ref (#23372) (#23377)
* Do not recognize text files as audio (#23355) (#23368)
* Fix adding of empty class name (#23352) (#23360)
* Fix various ImageDiff/SVG bugs (#23312) (#23358)
* Fix incorrect display for comment context menu (#23343) (#23344)
* Remove unnecessary space on link (#23334) (#23340)
* Fix incorrect redirect link of delete org project (#23327) (#23339)
* Fix cannot reopen after pushing commits to a closed PR (#23189) (#23324)
* Fix broken code editor diff preview (#23307) (#23320)
* Support sanitising the URL by removing extra slashes in the URL (#21333) (#23300)
* Avoid panic caused by broken payload when creating commit status (#23216) (#23294)
* Fill head commit to in payload when notifying push commits for mirroring (#23215) (#23292)
* Fix various bugs for "install" page (#23194) (#23286)
* Fix GetFilesChangedBetween if the file name may be escaped (#23272) (#23279)
* Revert relative links to absolute links in mail templates (#23267) (#23269)
* Fix commit retrieval by tag (#21804) (#23266)
* Use correct README link to render the README (#23152) (#23264)
* Close the temp file when dumping database to make the temp file can be deleted on Windows (#23249) (#23251)
* Use the correct selector to hide the checkmark of selected labels on clear (#23224) (#23228)
* Fix incorrect checkbox behaviors in the dashboard repolist's filter (#23147) (#23205)
* Properly flush unique queues on startup (#23154) (#23201)
* Pass `--global` when calling `git config --get`, for consistency with `git config --set` (#23157) (#23199)
* Make `gitea serv` respect git binary home (#23138) (#23197)
* Change button text for commenting and closing an issue at the same time (#23135) (#23182)
* Fix DBConsistency checks on MSSQL (#23132) (#23134)
* Show empty repos in Admin Repository Management page (#23114) (#23130)
* Redirect to the commit page after applying patch (#23056) (#23127)
* Fix nil context in RenderMarkdownToHtml (#23092) (#23108)
* Make issue meta dropdown support Enter, confirm before reloading (#23014) (#23102)
* Fix SyncOnCommit always return false in API of push_mirrors (#23088) (#23100)
* Fix commit name in Apply Patch page (#23086) (#23099)
* Fix some more hidden problems (#23074) (#23075)
* Bump golang.org/x/net from 0.4.0 to 0.7.0 (#22980)
* Get rules by id when editing branch protection rule (#22932)
* Fix panic when call api (/repos/{owner}/{repo}/pulls/{index}/files) (#22921)
* Increase Content field size of gpg_import_key to MEDIUMTEXT (#22897)
* Fix hidden commit status on multiple checks (#22889)
* Fix update by rebase being wrongly disabled by protected base branch (#22825)
* Make issue title edit buttons focusable and fix incorrect ajax requests (#22807)
* Fix rerun button of Actions (#22798)
* remove update language in ProfilePost (#22748)
* Do not overwrite empty DefaultBranch (#22708)
* Fix ref to trigger Actions (#22679)
* Fix time to NotifyPullRequestSynchronized (#22650)
* Show all projects, not just repo projects and open/closed projects (#22640)
* Project links should use parent link methods (#22587)
* Fix group filter for ldap source sync (#22506)
* Check quota limits for container uploads (#22450)
* Fix halfCommitter and WithTx (#22366)
* Attempt to fix TestExportUserGPGKeys (#22159)
* Fix heatmap first color being unused (#22157)
* Fix scroll over mermaid frame (#21925)
* Move migration test fixtures to the correct directories (#21901)
* fix(web): add `alt` for logo in home page (#21887)
* Fix webhook attachment text is not set in review comment (#21763)
* Alter package_version.metadata_json to LONGTEXT (#21667)
* Ensure that Webhook tasks are not double delivered (#21558)
* TESTING
* Make CI use a dummy password hasher for all tests (#22983)
* Disable test for incoming email (#22686)
* Move fuzz tests into tests/fuzz (#22376)
* Test views of LFS files (#22196)
* Specify ID in `TestAPITeam` (#22192)
* verify nodeinfo response by schema (#22137)
* Skip GitHub migration tests if the API token is undefined (#21824)
* Add a simple test for external renderer (#20033)
* TRANSLATION
* Use "Title Case" for text "Reference in new issue" (#22936)
* BUILD
* Wrap unless-check in docker manifests (#23079) (#23081)
* Adjust manifest to prevent tagging latest on rcs (#22811)
* update to build with go1.20 (#22732)
* Add Bash and Zsh completion scripts (#22646)
* Add Contributed backport command (#22643)
* Remove deprecated packages & staticcheck fixes (#22012)
* Update to Alpine 3.17 (#21904)
* Fix webpack license warning (#21815)
* DOCS
* Update documentation for the new YAML label file format (#23020) (#23341)
* Update hacking-on-gitea-zh_cn documentation (#23315) (#23323)
* Add basic documentation for labels, including scoped labels (#23304) (#23309)
* Re-add accidentally removed `hacking-on-gitea.zh-cn.md` (#23297) (#23305)
* Fix secrets overview page missing from docs sidebar (#23143) (#23145)
* Add some guidelines for refactoring (#22880)
* Explain that the no-access team unit does not affect public repositories (#22661)
* Fix incorrect Redis URL snippets in the example app.ini (#22573)
* docs: add swagger.json file location to FAQ (#22489)
* Update index.de-de.md (#22363)
* Update Gmail mailer configuration (#22291)
* Add missed reverse proxy authentication documentation (#22250)
* Add plural definitions for German translations (#21802)
* Attempt clarify AppWorkPath etc. (#21656)
* Add some documentation to packages (#21648)
* MISC
* Use `<nav>` instead of `<div>` in the global navbar (#23125) (#23533)
* Do not create commit graph for temporary repos (#23219) (#23229)
* Update button is shown when a Pull Request is marked WIP - Issue #21740 (#22683)
* Add main landmark to templates and adjust titles (#22670)
* Fix error on account activation with wrong passwd (#22609)
* Update JS dependencies (#22538)
* Display unreferenced packages total size in package admin panel (#22498)
* Mobile fix for Project view: Add delay to Sortable.js on mobile, to ensure scrolling is possible. (#22152)
* Update chroma to v2.4.0 (#22000)
* Hide collapse icon in diff with no lines (#21094)
## [1.18.5](https://github.com/go-gitea/gitea/releases/tag/v1.18.5) - 2023-02-21
* ENHANCEMENTS
* Hide 2FA status from other members in organization members list (#22999) (#23023)
* BUGFIXES
* Add force_merge to merge request and fix checking mergable (#23010) (#23032)
* Use `--message=%s` for git commit message (#23028) (#23029)
* Render access log template as text instead of HTML (#23013) (#23025)
* Fix the Manually Merged form (#23015) (#23017)
* Use beforeCommit instead of baseCommit (#22949) (#22996)
* Display attachments of review comment when comment content is blank (#23035) (#23046)
* Return empty url for submodule tree entries (#23043) (#23048)
## [1.18.4](https://github.com/go-gitea/gitea/releases/tag/1.18.4) - 2023-02-20
* SECURITY
* Provide the ability to set password hash algorithm parameters (#22942) (#22943)
* Add command to bulk set must-change-password (#22823) (#22928)
* ENHANCEMENTS
* Use import of OCI structs (#22765) (#22805)
* Fix color of tertiary button on dark theme (#22739) (#22744)
* Link issue and pull requests status change in UI notifications directly to their event in the timelined view. (#22627) (#22642)
* BUGFIXES
* Notify on container image create (#22806) (#22965)
* Fix blame view missing lines (#22826) (#22929)
* Fix incorrect role labels for migrated issues and comments (#22914) (#22923)
* Fix PR file tree folders no longer collapsing (#22864) (#22872)
* Escape filename when assemble URL (#22850) (#22871)
* Fix isAllowed of escapeStreamer (#22814) (#22837)
* Load issue before accessing index in merge message (#22822) (#22830)
* Improve trace logging for pulls and processes (#22633) (#22812)
* Fix restore repo bug, clarify the problem of ForeignIndex (#22776) (#22794)
* Add default user visibility to cli command "admin user create" (#22750) (#22760)
* Escape path for the file list (#22741) (#22757)
* Fix bugs with WebAuthn preventing sign in and registration. (#22651) (#22721)
* Add missing close bracket in imagediff (#22710) (#22712)
* Move code comments to a standalone file and fix the bug when adding a reply to an outdated review appears to not post(#20821) (#22707)
* Fix line spacing for plaintext previews (#22699) (#22701)
* Fix wrong hint when deleting a branch successfully from pull request UI (#22673) (#22698)
* Fix README TOC links (#22577) (#22677)
* Fix missing message in git hook when pull requests disabled on fork (#22625) (#22658)
* Improve checkIfPRContentChanged (#22611) (#22644)
* Prevent duplicate labels when importing more than 99 (#22591) (#22598)
* Don't return duplicated users who can create org repo (#22560) (#22562)
* BUILD
* Upgrade golangcilint to v1.51.0 (#22764)
* MISC
* Use proxy for pull mirror (#22771) (#22772)
* Use `--index-url` in PyPi description (#22620) (#22636)
## [1.18.3](https://github.com/go-gitea/gitea/releases/tag/v1.18.3) - 2023-01-23
* SECURITY
* Prevent multiple `To` recipients (#22566) (#22569)
* BUGFIXES
* Truncate commit summary on repo files table. (#22551) (#22552)
* Mute all links in issue timeline (#22534)
## [1.18.2](https://github.com/go-gitea/gitea/releases/tag/v1.18.2) - 2023-01-19
* BUGFIXES
* Fix issue not auto-closing when it includes a reference to a branch (#22514) (#22521)
* Fix invalid issue branch reference if not specified in template (#22513) (#22520)
* Fix 500 error viewing pull request when fork has pull requests disabled (#22512) (#22515)
* Reliable selection of admin user (#22509) (#22511)
* Set disable_gravatar/enable_federated_avatar when offline mode is true (#22479) (#22496)
* BUILD
* cgo cross-compile for freebsd (#22397) (#22519)
## [1.18.1](https://github.com/go-gitea/gitea/releases/tag/v1.18.1) - 2023-01-17
* API
* Add `sync_on_commit` option for push mirrors api (#22271) (#22292)
* BUGFIXES
* Update `github.com/zeripath/zapx/v15` (#22485)
* Fix pull request API field `closed_at` always being `null` (#22482) (#22483)
* Fix container blob mount (#22226) (#22476)
* Fix error when calculating repository size (#22392) (#22474)
* Fix Operator does not exist bug on explore page with ONLY_SHOW_RELEVANT_REPOS (#22454) (#22472)
* Fix environments for KaTeX and error reporting (#22453) (#22473)
* Remove the netgo tag for Windows build (#22467) (#22468)
* Fix migration from GitBucket (#22477) (#22465)
* Prevent panic on looking at api "git" endpoints for empty repos (#22457) (#22458)
* Fix PR status layout on mobile (#21547) (#22441)
* Fix wechatwork webhook sends empty content in PR review (#21762) (#22440)
* Remove duplicate "Actions" label in mobile view (#21974) (#22439)
* Fix leaving organization bug on user settings -> orgs (#21983) (#22438)
* Fixed colour transparency regex matching in project board sorting (#22092) (#22437)
* Correctly handle select on multiple channels in Queues (#22146) (#22428)
* Prepend refs/heads/ to issue template refs (#20461) (#22427)
* Restore function to "Show more" buttons (#22399) (#22426)
* Continue GCing other repos on error in one repo (#22422) (#22425)
* Allow HOST has no port (#22280) (#22409)
* Fix omit avatar_url in discord payload when empty (#22393) (#22394)
* Don't display stop watch top bar icon when disabled and hidden when click other place (#22374) (#22387)
* Don't lookup mail server when using sendmail (#22300) (#22383)
* Fix gravatar disable bug (#22337)
* Fix update settings table on install (#22326) (#22327)
* Fix sitemap (#22272) (#22320)
* Fix code search title translation (#22285) (#22316)
* Fix due date rendering the wrong date in issue (#22302) (#22306)
* Fix get system setting bug when enabled redis cache (#22298)
* Fix bug of DisableGravatar default value (#22297)
* Fix key signature error page (#22229) (#22230)
* TESTING
* Remove test session cache to reduce possible concurrent problem (#22199) (#22429)
* MISC
* Restore previous official review when an official review is deleted (#22449) (#22460)
* Log STDERR of external renderer when it fails (#22442) (#22444)
## [1.18.0](https://github.com/go-gitea/gitea/releases/tag/v1.18.0) - 2022-12-29
* SECURITY
* Remove ReverseProxy authentication from the API (#22219) (#22251)
* Support Go Vulnerability Management (#21139)
* Forbid HTML string tooltips (#20935)
* BREAKING
* Rework mailer settings (#18982)
* Remove U2F support (#20141)
* Refactor `i18n` to `locale` (#20153)
* Enable contenthash in filename for dynamic assets (#20813)
* FEATURES
* Add color previews in markdown (#21474)
* Allow package version sorting (#21453)
* Add support for Chocolatey/NuGet v2 API (#21393)
* Add API endpoint to get changed files of a PR (#21177)
* Add filetree on left of diff view (#21012)
* Support Issue forms and PR forms (#20987)
* Add support for Vagrant packages (#20930)
* Add support for `npm unpublish` (#20688)
* Add badge capabilities to users (#20607)
* Add issue filter for Author (#20578)
* Add KaTeX rendering to Markdown. (#20571)
* Add support for Pub packages (#20560)
* Support localized README (#20508)
* Add support mCaptcha as captcha provider (#20458)
* Add team member invite by email (#20307)
* Added email notification option to receive all own messages (#20179)
* Switch Unicode Escaping to a VSCode-like system (#19990)
* Add user/organization code search (#19977)
* Only show relevant repositories on explore page (#19361)
* User keypairs and HTTP signatures for ActivityPub federation using go-ap (#19133)
* Add sitemap support (#18407)
* Allow creation of OAuth2 applications for orgs (#18084)
* Add system setting table with cache and also add cache supports for user setting (#18058)
* Add pages to view watched repos and subscribed issues/PRs (#17156)
* Support Proxy protocol (#12527)
* Implement sync push mirror on commit (#19411)
* API
* Allow empty assignees on pull request edit (#22150) (#22214)
* Make external issue tracker regexp configurable via API (#21338)
* Add name field for org api (#21270)
* Show teams with no members if user is admin (#21204)
* Add latest commit's SHA to content response (#20398)
* Add allow_rebase_update, default_delete_branch_after_merge to repository api response (#20079)
* Add new endpoints for push mirrors management (#19841)
* ENHANCEMENTS
* Add setting to disable the git apply step in test patch (#22130) (#22170)
* Multiple improvements for comment edit diff (#21990) (#22007)
* Fix button in branch list, avoid unexpected page jump before restore branch actually done (#21562) (#21928)
* Fix flex layout for repo list icons (#21896) (#21920)
* Fix vertical align of committer avatar rendered by email address (#21884) (#21918)
* Fix setting HTTP headers after write (#21833) (#21877)
* Color and Style enhancements (#21784, #21799) (#21868)
* Ignore line anchor links with leading zeroes (#21728) (#21776)
* Quick fixes monaco-editor error: "vs.editor.nullLanguage" (#21734) (#21738)
* Use CSS color-scheme instead of invert (#21616) (#21623)
* Respect user's locale when rendering the date range in the repo activity page (#21410)
* Change `commits-table` column width (#21564)
* Refactor git command arguments and make all arguments to be safe to be used (#21535)
* CSS color enhancements (#21534)
* Add link to user profile in markdown mention only if user exists (#21533, #21554)
* Add option to skip index dirs (#21501)
* Diff file tree tweaks (#21446)
* Localize all timestamps (#21440)
* Add `code` highlighting in issue titles (#21432)
* Use Name instead of DisplayName in LFS Lock (#21415)
* Consolidate more CSS colors into variables (#21402)
* Redirect to new repository owner (#21398)
* Use ISO date format instead of hard-coded English date format for date range in repo activity page (#21396)
* Use weighted algorithm for string matching when finding files in repo (#21370)
* Show private data in feeds (#21369)
* Refactor parseTreeEntries, speed up tree list (#21368)
* Add GET and DELETE endpoints for Docker blob uploads (#21367)
* Add nicer error handling on template compile errors (#21350)
* Add `stat` to `ToCommit` function for speed (#21337)
* Support instance-wide OAuth2 applications (#21335)
* Record OAuth client type at registration (#21316)
* Add new CSS variables --color-accent and --color-small-accent (#21305)
* Improve error descriptions for unauthorized_client (#21292)
* Case-insensitive "find files in repo" (#21269)
* Consolidate more CSS rules, fix inline code on arc-green (#21260)
* Log real ip of requests from ssh (#21216)
* Save files in local storage as group readable (#21198)
* Enable fluid page layout on medium size viewports (#21178)
* File header tweaks (#21175)
* Added missing headers on user packages page (#21172)
* Display image digest for container packages (#21170)
* Skip dirty check for team forms (#21154)
* Keep path when creating a new branch (#21153)
* Remove fomantic image module (#21145)
* Make labels clickable in the comments section. (#21137)
* Sort branches and tags by date descending (#21136)
* Better repo API unit checks (#21130)
* Improve commit status icons (#21124)
* Limit length of repo description and repo url input fields (#21119)
* Show .editorconfig errors in frontend (#21088)
* Allow poster to choose reviewers (#21084)
* Remove black labels and CSS cleanup (#21003)
* Make e-mail sanity check more precise (#20991)
* Use native inputs in whitespace dropdown (#20980)
* Enhance package date display (#20928)
* Display total blob size of a package version (#20927)
* Show language name on hover (#20923)
* Show instructions for all generic package files (#20917)
* Refactor AssertExistsAndLoadBean to use generics (#20797)
* Move the official website link at the footer of gitea (#20777)
* Add support for full name in reverse proxy auth (#20776)
* Remove useless JS operation for relative time tooltips (#20756)
* Replace some icons with SVG (#20741)
* Change commit status icons to SVG (#20736)
* Improve single repo action for issue and pull requests (#20730)
* Allow multiple files in generic packages (#20661)
* Add option to create new issue from /issues page (#20650)
* Background color of private list-items updated (#20630)
* Added search input field to issue filter (#20623)
* Increase default item listing size `ISSUE_PAGING_NUM` to 20 (#20547)
* Modify milestone search keywords to be case insensitive again (#20513)
* Show hint to link package to repo when viewing empty repo package list (#20504)
* Add Tar ZSTD support (#20493)
* Make code review checkboxes clickable (#20481)
* Add "X-Gitea-Object-Type" header for GET `/raw/` & `/media/` API (#20438)
* Display project in issue list (#20434)
* Prepend commit message to template content when opening a new PR (#20429)
* Replace fomantic popup module with tippy.js (#20428)
* Allow to specify colors for text in markup (#20363)
* Allow access to the Public Organization Member lists with minimal permissions (#20330)
* Use default values when provided values are empty (#20318)
* Vertical align navbar avatar at middle (#20302)
* Delete cancel button in repo creation page (#21381)
* Include login_name in adminCreateUser response (#20283)
* fix: icon margin in user/settings/repos (#20281)
* Remove blue text on migrate page (#20273)
* Modify milestone search keywords to be case insensitive (#20266)
* Move some files into models' sub packages (#20262)
* Add tooltip to repo icons in explore page (#20241)
* Remove deprecated licenses (#20222)
* Webhook for Wiki changes (#20219)
* Share HTML template renderers and create a watcher framework (#20218)
* Allow enable LDAP source and disable user sync via CLI (#20206)
* Adds a checkbox to select all issues/PRs (#20177)
* Refactor `i18n` to `locale` (#20153)
* Disable status checks in template if none found (#20088)
* Allow manager logging to set SQL (#20064)
* Add order by for assignee no sort issue (#20053)
* Take a stab at porting existing components to Vue3 (#20044)
* Add doctor command to write commit-graphs (#20007)
* Add support for authentication based on reverse proxy email (#19949)
* Enable spellcheck for EasyMDE, use contenteditable mode (#19776)
* Allow specifying SECRET_KEY_URI, similar to INTERNAL_TOKEN_URI (#19663)
* Rework mailer settings (#18982)
* Add option to purge users (#18064)
* Add author search input (#21246)
* Make rss/atom identifier globally unique (#21550)
* BUGFIXES
* Auth interface return error when verify failure (#22119) (#22259)
* Use complete SHA to create and query commit status (#22244) (#22257)
* Update bleve and zapx to fix unaligned atomic (#22031) (#22218)
* Prevent panic in doctor command when running default checks (#21791) (#21807)
* Load GitRepo in API before deleting issue (#21720) (#21796)
* Ignore line anchor links with leading zeroes (#21728) (#21776)
* Set last login when activating account (#21731) (#21755)
* Fix UI language switching bug (#21597) (#21749)
* Quick fixes monaco-editor error: "vs.editor.nullLanguage" (#21734) (#21738)
* Allow local package identifiers for PyPI packages (#21690) (#21727)
* Deal with markdown template without metadata (#21639) (#21654)
* Fix opaque background on mermaid diagrams (#21642) (#21652)
* Fix repository adoption on Windows (#21646) (#21650)
* Sync git hooks when config file path changed (#21619) (#21626)
* Fix 500 on PR files API (#21602) (#21607)
* Fix `Timestamp.IsZero` (#21593) (#21603)
* Fix viewing user subscriptions (#21482)
* Fix mermaid-related bugs (#21431)
* Fix branch dropdown shifting on page load (#21428)
* Fix default theme-auto selector when nologin (#21346)
* Fix and improve incorrect error messages (#21342)
* Fix formatted link for PR review notifications to matrix (#21319)
* Center-aligning content of WebAuthN page (#21127)
* Remove follow from commits by file (#20765)
* Fix commit status popup (#20737)
* Fix init mail render logic (#20704)
* Use correct page size for link header pagination (#20546)
* Preserve unix socket file (#20499)
* Use tippy.js for context popup (#20393)
* Add missing parameter for error in log message (#20144)
* Do not allow organisation owners add themselves as collaborator (#20043)
* Rework file highlight rendering and fix yaml copy-paste (#19967)
* Improve code diff highlight, fix incorrect rendered diff result (#19958)
* TESTING
* Improve OAuth integration tests (#21390)
* Add playwright tests (#20123)
* BUILD
* Switch to building with go1.19 (#20695)
* Update JS dependencies, adjust eslint (#20659)
* Add more linters to improve code readability (#19989)
## [1.17.4](https://github.com/go-gitea/gitea/releases/tag/v1.17.4) - 2022-12-21
* SECURITY
* Do not allow Ghost access to limited visible user/org (#21849) (#21875)
* Fix package access for admins and inactive users (#21580) (#21592)
* ENHANCEMENTS
* Fix button in branch list, avoid unexpected page jump before restore branch actually done (#21562) (#21927)
* Fix vertical align of committer avatar rendered by email address (#21884) (#21919)
* Fix setting HTTP headers after write (#21833) (#21874)
* Ignore line anchor links with leading zeroes (#21728) (#21777)
* Enable Monaco automaticLayout (#21516)
* BUGFIXES
* Do not list active repositories as unadopted (#22034) (#22167)
* Correctly handle moved files in apply patch (#22118) (#22136)
* Fix condition for is_internal (#22095) (#22131)
* Fix permission check on issue/pull lock (#22114)
* Fix sorting admin user list by last login (#22081) (#22106)
* Workaround for container registry push/pull errors (#21862) (#22069)
* Fix issue/PR numbers (#22037) (#22045)
* Handle empty author names (#21902) (#22028)
* Fix ListBranches to handle empty case (#21921) (#22025)
* Fix enabling partial clones on 1.17 (#21809)
* Prevent panic in doctor command when running default checks (#21791) (#21808)
* Upgrade golang.org/x/crypto (#21792) (#21794)
* Init git module before database migration (#21764) (#21766)
* Set last login when activating account (#21731) (#21754)
* Add HEAD fix to gitea doctor (#21352) (#21751)
* Fix UI language switching bug (#21597) (#21748)
* Remove semver compatible flag and change pypi to an array of test cases (#21708) (#21729)
* Allow local package identifiers for PyPI packages (#21690) (#21726)
* Fix repository adoption on Windows (#21646) (#21651)
* Sync git hooks when config file path changed (#21619) (#21625)
* Added check for disabled Packages (#21540) (#21614)
* Fix `Timestamp.IsZero` (#21593) (#21604)
* Fix issues count bug (#21600)
* Support binary deploy in npm packages (#21589)
* Update milestone counters when issue is deleted (#21459) (#21586)
* SessionUser protection against nil pointer dereference (#21581)
* Case-insensitive NuGet symbol file GUID (#21409) (#21575)
* Suppress `ExternalLoginUserNotExist` error (#21504) (#21572)
* Prevent Authorization header for presigned LFS urls (#21531) (#21569)
* Update binding to fix bugs (#21560)
* Fix generating compare link (#21519) (#21530)
* Ignore error when retrieving changed PR review files (#21487) (#21524)
* Fix incorrect notification commit url (#21479) (#21483)
* Display total commit count in hook message (#21400) (#21481)
* Enforce grouped NuGet search results (#21442) (#21480)
* Return 404 when user is not found on avatar (#21476) (#21477)
* Normalize NuGet package version on upload (#22186) (#22201)
* MISC
* Check for zero time instant in TimeStamp.IsZero() (#22171) (#22173)
* Fix warn in database structs sync (#22111)
* Allow for resolution of NPM registry paths that match upstream (#21568) (#21723)
## [1.17.3](https://github.com/go-gitea/gitea/releases/tag/v1.17.3) - 2022-10-15
* SECURITY
* Sanitize and Escape refs in git backend (#21464) (#21463)
* Bump `golang.org/x/text` (#21412) (#21413)
* Update bluemonday (#21281) (#21287)
* ENHANCEMENTS
* Fix empty container layer history and UI (#21251) (#21278)
* Use en-US as fallback when using other default language (#21200) (#21256)
* Make the vscode clone link respect transport protocol (#20557) (#21128)
* BUGFIXES
* Do DB update after merge in hammer context (#21401) (#21416)
* Add Num{Issues,Pulls} stats checks (#21404) (#21414)
* Stop logging CheckPath returns error: context canceled (#21064) (#21405)
* Parse OAuth Authorization header when request omits client secret (#21351) (#21374)
* Ignore port for loopback redirect URIs (#21293) (#21373)
* Set SemverCompatible to false for Conan packages (#21275) (#21366)
* Tag list should include draft releases with existing tags (#21263) (#21365)
* Fix linked account translation (#21331) (#21334)
* Make NuGet service index publicly accessible (#21242) (#21277)
* Foreign ID conflicts if ID is 0 for each item (#21271) (#21272)
* Use absolute links in feeds (#21229) (#21265)
* Prevent invalid behavior for file reviewing when loading more files (#21230) (#21234)
* Respect `REQUIRE_SIGNIN_VIEW` for packages (#20873) (#21232)
* Treat git object mode 40755 as directory (#21195) (#21218)
* Allow uppercase ASCII alphabet in PyPI package names (#21095) (#21217)
* Fix limited user cannot view himself's profile (#21212)
* Fix template bug of admin monitor (#21209)
* Fix reaction of issues (#21185) (#21196)
* Fix CSV diff for added/deleted files (#21189) (#21193)
* Fix pagination limit parameter problem (#21111)
* TESTING
* Fix missing m.Run() in TestMain (#21341)
* BUILD
* Use Go 1.19 fmt for Gitea 1.17, sync emoji data (#21239)
## [1.17.2](https://github.com/go-gitea/gitea/releases/tag/v1.17.2) - 2022-09-06
* SECURITY
* Double check CloneURL is acceptable (#20869) (#20892)
* Add more checks in migration code (#21011) (#21050)
* ENHANCEMENTS
* Fix hard-coded timeout and error panic in API archive download endpoint (#20925) (#21051)
* Improve arc-green code theme (#21039) (#21042)
* Enable contenthash in filename for dynamic assets (#20813) (#20932)
* Don't open new page for ext wiki on same repository (#20725) (#20910)
* Disable doctor logging on panic (#20847) (#20898)
* Remove calls to load Mirrors in user.Dashboard (#20855) (#20897)
* Update codemirror to 5.65.8 (#20875)
* Rework repo buttons (#20602, #20718) (#20719)
* BUGFIXES
* Ensure delete user deletes all comments (#21067) (#21068)
* Delete unreferenced packages when deleting a package version (#20977) (#21060)
* Redirect if user does not exist on admin pages (#20981) (#21059)
* Set uploadpack.allowFilter etc on gitea serv to enable partial clones with ssh (#20902) (#21058)
* Fix 500 on time in timeline API (#21052) (#21057)
* Fill the specified ref in webhook test payload (#20961) (#21055)
* Add another index for Action table on postgres (#21033) (#21054)
* Fix broken insecureskipverify handling in redis connection uris (#20967) (#21053)
* Add Dev, Peer and Optional dependencies to npm PackageMetadataVersion (#21017) (#21044)
* Do not add links to Posters or Assignees with ID < 0 (#20577) (#21037)
* Fix modified due date message (#20388) (#21032)
* Fix missed sort bug (#21006)
* Fix input.value attr for RequiredClaimName/Value (#20946) (#21001)
* Change review buttons to icons to make space for text (#20934) (#20978)
* Fix download archiver of a commit (#20962) (#20971)
* Return 404 NotFound if requested attachment does not exist (#20886) (#20941)
* Set no-tags in git fetch on compare (#20893) (#20936)
* Allow multiple metadata files for Maven packages (#20674) (#20916)
* Increase Content field size of gpg_key and public_key to MEDIUMTEXT (#20896) (#20911)
* Fix mirror address setting not working (#20850) (#20904)
* Fix push mirror address backend get error Address cause setting page display error (#20593) (#20901)
* Fix panic when an invalid oauth2 name is passed (#20820) (#20900)
* In PushMirrorsIterate and MirrorsIterate if limit is negative do not set it (#20837) (#20899)
* Ensure that graceful start-up is informed of unused SSH listener (#20877) (#20888)
* Pad GPG Key ID with preceding zeroes (#20878) (#20885)
* Fix SQL Query for `SearchTeam` (#20844) (#20872)
* Fix the mode of custom dir to 0700 in docker-rootless (#20861) (#20867)
* Fix UI mis-align for PR commit history (#20845) (#20859)
## [1.17.1](https://github.com/go-gitea/gitea/releases/tag/1.17.1) - 2022-08-17
* SECURITY
* Correctly escape within tribute.js (#20831) (#20832)
* ENHANCEMENTS
* Add support for NuGet API keys (#20721) (#20734)
* Display project in issue list (#20583)
* Add disable download source configuration (#20548) (#20579)
* Add username check to doctor (#20140) (#20671)
* Enable Wire 2 for Internal SSH Server (#20616) (#20617)
* BUGFIXES
* Use the total issue count for UI (#20785) (#20827)
* Add proxy host into allow list (#20798) (#20819)
* Add missing translation for queue flush workers (#20791) (#20792)
* Improve comment header for mobile (#20781) (#20789)
* Fix git.Init for doctor sub-command (#20782) (#20783)
* Check webhooks slice length before calling xorm (#20642) (#20768)
* Remove manual rollback for failed generated repositories (#20639) (#20762)
* Use correct field name in npm template (#20675) (#20760)
* Keep download count on Container tag overwrite (#20728) (#20735)
* Fix v220 migration to be compatible for MSSQL 2008 r2 (#20702) (#20707)
* Use request timeout for git service rpc (#20689) (#20693)
* Send correct NuGet status codes (#20647) (#20677)
* Use correct context to get package content (#20673) (#20676)
* Fix the JS error "EventSource is not defined" caused by some non-standard browsers (#20584) (#20663)
* Add default commit messages to PR for squash merge (#20618) (#20645)
* Fix package upload for files >32mb (#20622) (#20635)
* Fix the new-line copy-paste for rendered code (#20612)
* Clean up and fix clone button script (#20415 & #20600) (#20599)
* Fix default merge style (#20564) (#20565)
* Add repository condition for issue count (#20454) (#20496)
* Make branch icon stand out more (#20726) (#20774)
* Fix loading button with invalid form (#20754) (#20759)
* Fix SecToTime edge-cases (#20610) (#20611)
* Executable check always returns true for windows (#20637) (#20835)
* Check issue labels slice length before calling xorm Insert (#20655) (#20836)
* Fix owners cannot create organization repos bug (#20841) (#20854)
* Prevent 500 is head repo does not have PullRequest unit in IsUserAllowedToUpdate (#20839) (#20848)
## [1.17.0](https://github.com/go-gitea/gitea/releases/tag/v1.17.0) - 2022-07-30
* BREAKING

96
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,96 @@
# Gitea Community Code of Conduct
## About
Online communities include people from many different backgrounds. The Gitea contributors are committed to providing a friendly, safe and welcoming environment for all, regardless of gender identity and expression, sexual orientation, disabilities, neurodiversity, physical appearance, body size, ethnicity, nationality, race, age, religion, or similar personal characteristics.
The first goal of the Code of Conduct is to specify a baseline standard of behavior so that people with different social values and communication styles can talk about Gitea effectively, productively, and respectfully.
The second goal is to provide a mechanism for resolving conflicts in the community when they arise.
The third goal of the Code of Conduct is to make our community welcoming to people from different backgrounds. Diversity is critical to the project; for Gitea to be successful, it needs contributors and users from all backgrounds.
We believe that healthy debate and disagreement are essential to a healthy project and community. However, it is never ok to be disrespectful. We value diverse opinions, but we value respectful behavior more.
## Community values
These are the values to which people in the Gitea community should aspire.
- **Be friendly and welcoming.**
- **Be patient.**
- Remember that people have varying communication styles and that not everyone is using their native language. (Meaning and tone can be lost in translation.)
- **Be thoughtful.**
- Productive communication requires effort. Think about how your words will be interpreted.
- Remember that sometimes it is best to refrain entirely from commenting.
- **Be respectful.**
- In particular, respect differences of opinion.
- **Be charitable.**
- Interpret the arguments of others in good faith, do not seek to disagree.
- When we do disagree, try to understand why.
- **Be constructive.**
- Avoid derailing: stay on topic; if you want to talk about something else, start a new conversation.
- Avoid unconstructive criticism: don't merely decry the current state of affairs; offer—or at least solicit—suggestions as to how things may be improved.
- Avoid snarking (pithy, unproductive, sniping comments)
- Avoid discussing potentially offensive or sensitive issues; this all too often leads to unnecessary conflict.
- Avoid microaggressions (brief and commonplace verbal, behavioral and environmental indignities that communicate hostile, derogatory or negative slights and insults to a person or group).
- **Be responsible.**
- What you say and do matters. Take responsibility for your words and actions, including their consequences, whether intended or otherwise.
People are complicated. You should expect to be misunderstood and to misunderstand others; when this inevitably occurs, resist the urge to be defensive or assign blame. Try not to take offense where no offense was intended. Give people the benefit of the doubt. Even if the intent was to provoke, do not rise to it. It is the responsibility of all parties to de-escalate conflict when it arises.
## Code of Conduct
### Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
### Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
### Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject: comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, as well as to ban (temporarily or permanently) any contributor for behaviors that they deem inappropriate, threatening, offensive, or harmful.
### Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
This Code of Conduct also applies outside the project spaces when the Project Stewards have a reasonable belief that an individuals behavior may have a negative impact on the project or its community.
### Conflict Resolution
We do not believe that all conflict is bad; healthy debate and disagreement often yield positive results. However, it is never okay to be disrespectful or to engage in behavior that violates the projects code of conduct.
If you see someone violating the code of conduct, you are encouraged to address the behavior directly with those involved. Many issues can be resolved quickly and easily, and this gives people more control over the outcome of their dispute. If you are unable to resolve the matter for any reason, or if the behavior is threatening or harassing, report it. We are dedicated to providing an environment where participants feel welcome and safe.
Reports should be directed to the Gitea Project Stewards at conduct@gitea.com. It is the Project Stewards duty to receive and address reported violations of the code of conduct. They will then work with a committee consisting of representatives from the technical-oversight-committee.
We will investigate every complaint, but you may not receive a direct response. We will use our discretion in determining when and how to follow up on reported incidents, which may range from not taking action to permanent expulsion from the project and project-sponsored spaces. Under normal circumstances, we will notify the accused of the report and provide them an opportunity to discuss it before any action is taken. If there is a consensus between maintainers that such an endeavor would be useless (i.e. in case of an obvious spammer), we reserve the right to take action without notifying the accused first. The identity of the reporter will be omitted from the details of the report supplied to the accused. In potentially harmful situations, such as ongoing harassment or threats to anyones safety, we may take action without notice.
### Attribution
This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
## Summary
- Treat everyone with respect and kindness.
- Be thoughtful in how you communicate.
- Dont be destructive or inflammatory.
- If you encounter an issue, please mail conduct@gitea.com.

View File

@ -86,8 +86,10 @@ Here's how to run the test suite:
| | |
| :------------------------------------- | :----------------------------------------------- |
|``make test[\#TestSpecificName]`` | run unit test |
|``make test-sqlite[\#TestSpecificName]``| run [integration](integrations) test for SQLite |
|[More details about integrations](integrations/README.md) |
|``make test-sqlite[\#TestSpecificName]``| run [integration](tests/integration) test for SQLite |
|[More details about integration tests](tests/integration/README.md) |
|``make test-e2e-sqlite[\#TestSpecificFileName]``| run [end-to-end](tests/e2e) test for SQLite |
|[More details about e2e tests](tests/e2e/README.md) |
## Vendoring
@ -144,6 +146,16 @@ If your PR could cause a breaking change you must add a BREAKING section to this
To explain how this could affect users and how to mitigate these changes.
Once code review starts on your PR, do not rebase nor squash your branch as it makes it
difficult to review the new changes. Only if there is a need, sync your branch by merging
the base branch into yours. Don't worry about merge commits messing up your tree as
the final merge process squashes all commits into one, with the visible commit message (first
line) being the PR title + PR index and description being the PR's first comment.
Once your PR gets the `lgtm/done` label, don't worry about keeping it up-to-date or breaking
builds (unless there's a merge conflict or a request is made by a maintainer to make
modifications). It is the maintainer team's responsibility from this point to get it merged.
## Styleguide
For imports you should use the following format (*without* the comments)
@ -168,17 +180,24 @@ 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. 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.
- **modules:** Different modules to handle specific functionality in Gitea. Shall only depend on other modules but not other packages (models, services).
- **public:** Frontend files (javascript, images, css, etc.)
- **routers:** Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) shall not depend on routers
- **routers:** Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) shall not depend on routers.
- **services:** Support functions for common routing operations. Uses models and modules to handle the request.
- **templates:** Golang templates for generating the html output.
- **tests/e2e:** End to end tests
- **tests/integration:** Integration tests
- **tests/gitea-repositories-meta:** Sample repos used in integration tests. Adding a new repo requires editing `models/fixtures/repositories.yml` and `models/fixtures/repo_unit.yml` to match.
- **tests/gitea-lfs-meta:** Sample LFS objects used in integration tests. Adding a new object requires editing `models/fixtures/lfs_meta_object.yml` to match.
- **vendor:** External code that Gitea depends on.
## Documentation
If you add a new feature or change an existing aspect of Gitea, the documentation for that feature must be created or updated.
## API v1
The API is documented by [swagger](http://try.gitea.io/api/swagger) and is based on [GitHub API v3](https://developer.github.com/v3/).
@ -227,27 +246,6 @@ An endpoint which changes/edits an object expects all fields to be optional (exc
- support pagination (`page` & `limit` options in query)
- set `X-Total-Count` header via **SetTotalCountHeader** ([example](https://github.com/go-gitea/gitea/blob/7aae98cc5d4113f1e9918b7ee7dd09f67c189e3e/routers/api/v1/repo/issue.go#L444))
## Large Character Comments
Throughout the codebase there are large-text comments for sections of code, e.g.:
```go
// __________ .__
// \______ \ _______ _|__| ______ _ __
// | _// __ \ \/ / |/ __ \ \/ \/ /
// | | \ ___/\ /| \ ___/\ /
// |____|_ /\___ >\_/ |__|\___ >\/\_/
// \/ \/ \/
```
These were created using the `figlet` tool with the `graffiti` font.
A simple way of creating these is to use the following:
```bash
figlet -f graffiti Review | sed -e's+^+// +' - | xclip -sel clip -in
```
## Backports and Frontports
Occasionally backports of PRs are required.
@ -269,26 +267,10 @@ with the rest of the summary matching the original PR. Similarly for frontports
---
The below is a script that may be helpful in creating backports. YMMV.
A command to help create backports can be found in `contrib/backport` and can be installed (from inside the gitea repo root directory) using:
```bash
#!/bin/sh
PR="$1"
SHA="$2"
VERSION="$3"
if [ -z "$SHA" ]; then
SHA=$(gh api /repos/go-gitea/gitea/pulls/$PR -q '.merge_commit_sha')
fi
if [ -z "$VERSION" ]; then
VERSION="v1.16"
fi
echo git checkout origin/release/"$VERSION" -b backport-$PR-$VERSION
git checkout origin/release/"$VERSION" -b backport-$PR-$VERSION
git cherry-pick $SHA && git commit --amend && git push zeripath backport-$PR-$VERSION && xdg-open https://github.com/go-gitea/gitea/compare/release/"$VERSION"...zeripath:backport-$PR-$VERSION
go install contrib/backport/backport.go
```
## Developer Certificate of Origin (DCO)
@ -317,9 +299,7 @@ known as the release freeze. All the feature pull requests should be
merged before feature freeze. And, during the frozen period, a corresponding
release branch is open for fixes backported from main branch. Release candidates
are made during this period for user testing to
obtain a final version that is maintained in this branch. A release is
maintained by issuing patch releases to only correct critical problems
such as crashes or security issues.
obtain a final version that is maintained in this branch.
Major release cycles are seasonal. They always begin on the 25th and end on
the 24th (i.e., the 25th of December to March 24th).
@ -329,6 +309,16 @@ for the previous version. For example, if the latest, published release is
v1.2, then minor changes for the previous release—e.g., v1.1.0 -> v1.1.1—are
still possible.
The previous release gets fixes for:
- Security issues
- Critical bugs
- Regressions
- Build issues
- Necessary enhancements (including necessary UI/UX fixes)
The backported fixes should avoid breaking downgrade between minor releases as much as possible.
## Maintainers
To make sure every PR is checked, we have [team
@ -443,9 +433,9 @@ be reviewed by two maintainers and must pass the automatic tests.
Code that you contribute should use the standard copyright header:
```
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// Copyright <year> The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
```
Files in the repository contain copyright from the year they are added

4
DCO
View File

@ -2,8 +2,6 @@ Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
@ -33,4 +31,4 @@ By making a contribution to this project, I certify that:
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
this project or the open source license(s) involved.

View File

@ -1,5 +1,5 @@
#Build stage
FROM golang:1.19-alpine3.16 AS build-env
FROM golang:1.20-alpine3.17 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}
@ -23,7 +23,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
# Begin env-to-ini build
RUN go build contrib/environment-to-ini/environment-to-ini.go
FROM alpine:3.16
FROM alpine:3.17
LABEL maintainer="maintainers@gitea.io"
EXPOSE 22 3000
@ -64,5 +64,7 @@ CMD ["/bin/s6-svscan", "/etc/s6"]
COPY docker/root /
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
RUN chmod 755 /usr/bin/entrypoint /app/gitea/gitea /usr/local/bin/gitea /usr/local/bin/environment-to-ini
RUN chmod 755 /etc/s6/gitea/* /etc/s6/openssh/* /etc/s6/.s6-svscan/*
RUN chmod 644 /etc/profile.d/gitea_bash_autocomplete.sh

View File

@ -1,5 +1,5 @@
#Build stage
FROM golang:1.19-alpine3.16 AS build-env
FROM golang:1.20-alpine3.17 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}
@ -23,7 +23,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
# Begin env-to-ini build
RUN go build contrib/environment-to-ini/environment-to-ini.go
FROM alpine:3.16
FROM alpine:3.17
LABEL maintainer="maintainers@gitea.io"
EXPOSE 2222 3000
@ -31,6 +31,7 @@ EXPOSE 2222 3000
RUN apk --no-cache add \
bash \
ca-certificates \
dumb-init \
gettext \
git \
curl \
@ -53,7 +54,9 @@ 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 /app/gitea/gitea
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
RUN chmod 755 /usr/local/bin/docker-entrypoint.sh /usr/local/bin/docker-setup.sh /app/gitea/gitea /usr/local/bin/gitea /usr/local/bin/environment-to-ini
RUN chmod 644 /etc/profile.d/gitea_bash_autocomplete.sh
#git:git
USER 1000:1000
@ -68,6 +71,6 @@ ENV HOME "/var/lib/gitea/git"
VOLUME ["/var/lib/gitea", "/etc/gitea"]
WORKDIR /var/lib/gitea
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"]
CMD []

View File

@ -5,8 +5,6 @@ Kees de Vries <bouwko@gmail.com> (@Bwko)
Kim Carlbäcker <kim.carlbacker@gmail.com> (@bkcsoft)
LefsFlare <nobody@nobody.tld> (@LefsFlarey)
Lunny Xiao <xiaolunwen@gmail.com> (@lunny)
Matthias Loibl <mail@matthiasloibl.com> (@metalmatze)
Morgan Bazalgette <the@howl.moe> (@thehowl)
Rachid Zarouali <nobody@nobody.tld> (@xinity)
Rémy Boulanouar <admin@dblk.org> (@DblK)
Sandro Santilli <strk@kbt.io> (@strk)
@ -44,7 +42,10 @@ Janis Estelmann <admin@oldschoolhack.me> (@KN4CK3R)
Steven Kriegler <sk.bunsenbrenner@gmail.com> (@justusbunsi)
Jimmy Praet <jimmy.praet@telenet.be> (@jpraet)
Leon Hofmeister <dev.lh@web.de> (@delvh)
Gusted <williamzijl7@hotmail.com) (@Gusted)
silentcode <silentcode@senga.org> (@silentcodeg)
Wim <wim@42.be> (@42wim)
xinyu <xinyu@nerv.org.cn> (@penlinux)
Jason Song <i@wolfogre.com> (@wolfogre)
Yarden Shoham <git@yardenshoham.com> (@yardenshoham)
Yu Tian <zettat123@gmail.com> (@Zettat123)
Eddie Yang <576951401@qq.com> (@yp05327)
Dong Ge <gedong_1994@163.com> (@sillyguodong)
Xinyi Gong <hestergong@gmail.com> (@HesterG)

406
Makefile
View File

@ -23,17 +23,19 @@ SHASUM ?= shasum -a 256
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
COMMA := ,
XGO_VERSION := go-1.19.x
XGO_VERSION := go-1.20.x
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.40.4
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.5.0
ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.1
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.1
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.47.0
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.6.0
ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.2
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.4.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.2
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.29.0
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.4
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.5.0
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@latest
DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest
@ -75,6 +77,7 @@ ifeq ($(RACE_ENABLED),true)
endif
STORED_VERSION_FILE := VERSION
HUGO_VERSION ?= 0.111.3
ifneq ($(DRONE_TAG),)
VERSION ?= $(subst v,,$(DRONE_TAG))
@ -98,11 +101,12 @@ LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(G
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/models/migrations code.gitea.io/gitea/integrations/migration-test code.gitea.io/gitea/integrations,$(shell $(GO) list ./... | grep -v /vendor/))
GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
FOMANTIC_WORK_DIR := web_src/fomantic
WEBPACK_SOURCES := $(shell find web_src/js web_src/less -type f)
WEBPACK_SOURCES := $(shell find web_src/js web_src/css -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/img/webpack public/serviceworker.js
@ -110,25 +114,39 @@ WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/img/webpack pub
BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
GENERATED_GO_DEST := modules/charset/invisible_gen.go modules/charset/ambiguous_gen.go
SVG_DEST_DIR := public/img/svg
AIR_TMP_DIR := .air
GO_LICENSE_TMP_DIR := .go-licenses
GO_LICENSE_FILE := assets/go-licenses.json
TAGS ?=
TAGS_SPLIT := $(subst $(COMMA), ,$(TAGS))
TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags
TEST_TAGS ?= sqlite sqlite_unlock_notify
TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMANTIC_WORK_DIR)/node_modules $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR)
TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMANTIC_WORK_DIR)/node_modules $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR) $(GO_LICENSE_TMP_DIR)
GO_DIRS := cmd integrations models modules routers build services tools
GO_DIRS := build cmd models modules routers services tests
WEB_DIRS := web_src/js web_src/css
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)
GO_SOURCES += $(GENERATED_GO_DEST)
GO_SOURCES_NO_BINDATA := $(GO_SOURCES)
ifeq ($(filter $(TAGS_SPLIT),bindata),bindata)
GO_SOURCES += $(BINDATA_DEST)
GENERATED_GO_DEST += $(BINDATA_DEST)
endif
# Force installation of playwright dependencies by setting this flag
ifdef DEPS_PLAYWRIGHT
PLAYWRIGHT_FLAGS += --with-deps
endif
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
@ -171,8 +189,10 @@ help:
@echo " - clean delete backend and integration files"
@echo " - clean-all delete backend, frontend and integration files"
@echo " - deps install dependencies"
@echo " - deps-docs install docs dependencies"
@echo " - deps-frontend install frontend dependencies"
@echo " - deps-backend install backend dependencies"
@echo " - deps-tools install tool dependencies"
@echo " - lint lint everything"
@echo " - lint-frontend lint frontend files"
@echo " - lint-backend lint backend files"
@ -182,6 +202,7 @@ help:
@echo " - test test everything"
@echo " - test-frontend test frontend files"
@echo " - test-backend test backend files"
@echo " - test-e2e[\#TestSpecificName] test end to end using playwright"
@echo " - webpack build webpack files"
@echo " - svg build svg files"
@echo " - fomantic build fomantic files"
@ -193,11 +214,11 @@ help:
@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 " - go-licenses regenerate go licenses"
@echo " - vet examines Go source code and reports suspicious constructs"
@echo " - tidy run go mod tidy"
@echo " - test[\#TestSpecificName] run unit test"
@echo " - test-sqlite[\#TestSpecificName] run integration test for sqlite"
@echo " - pr#<index> build and start gitea from a PR with integration test data loaded"
.PHONY: go-check
go-check:
@ -236,14 +257,33 @@ clean:
$(GO) clean -i ./...
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \
integrations*.test \
integrations/gitea-integration-pgsql/ integrations/gitea-integration-mysql/ integrations/gitea-integration-mysql8/ integrations/gitea-integration-sqlite/ \
integrations/gitea-integration-mssql/ integrations/indexers-mysql/ integrations/indexers-mysql8/ integrations/indexers-pgsql integrations/indexers-sqlite \
integrations/indexers-mssql integrations/mysql.ini integrations/mysql8.ini integrations/pgsql.ini integrations/mssql.ini man/
e2e*.test \
tests/integration/gitea-integration-pgsql/ tests/integration/gitea-integration-mysql/ tests/integration/gitea-integration-mysql8/ tests/integration/gitea-integration-sqlite/ \
tests/integration/gitea-integration-mssql/ tests/integration/indexers-mysql/ tests/integration/indexers-mysql8/ tests/integration/indexers-pgsql tests/integration/indexers-sqlite \
tests/integration/indexers-mssql tests/mysql.ini tests/mysql8.ini tests/pgsql.ini tests/mssql.ini man/ \
tests/e2e/gitea-e2e-pgsql/ tests/e2e/gitea-e2e-mysql/ tests/e2e/gitea-e2e-mysql8/ tests/e2e/gitea-e2e-sqlite/ \
tests/e2e/gitea-e2e-mssql/ tests/e2e/indexers-mysql/ tests/e2e/indexers-mysql8/ tests/e2e/indexers-pgsql/ tests/e2e/indexers-sqlite/ \
tests/e2e/indexers-mssql/ tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/
.PHONY: fmt
fmt:
@echo "Running gitea-fmt (with gofumpt)..."
@MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
@# strip whitespace after '{{' and before `}}` unless there is only whitespace before it
@$(SED_INPLACE) -e 's/{{[ ]\{1,\}/{{/g' -e '/^[ ]\{1,\}}}/! s/[ ]\{1,\}}}/}}/g' $(TEMPLATES)
.PHONY: fmt-check
fmt-check: fmt
@diff=$$(git diff --color=always $(GO_SOURCES) templates $(WEB_DIRS)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi
.PHONY: misspell-check
misspell-check:
go run $(MISSPELL_PACKAGE) -error $(GO_DIRS) $(WEB_DIRS)
.PHONY: vet
vet:
@ -261,14 +301,16 @@ TAGS_PREREQ := $(TAGS_EVIDENCE)
endif
.PHONY: generate-swagger
generate-swagger:
generate-swagger: $(SWAGGER_SPEC)
$(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA)
$(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
$(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)'
.PHONY: swagger-check
swagger-check: generate-swagger
@diff=$$(git diff '$(SWAGGER_SPEC)'); \
@diff=$$(git diff --color=always '$(SWAGGER_SPEC)'); \
if [ -n "$$diff" ]; then \
echo "Please run 'make generate-swagger' and commit the result:"; \
echo "$${diff}"; \
@ -286,16 +328,6 @@ errcheck:
@echo "Running errcheck..."
$(GO) run $(ERRCHECK_PACKAGE) $(GO_PACKAGES)
.PHONY: fmt-check
fmt-check:
# get all go files and run gitea-fmt (with gofmt) on them
@diff=$$(MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -l '{file-list}'); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi
.PHONY: checks
checks: checks-frontend checks-backend
@ -303,15 +335,15 @@ checks: checks-frontend checks-backend
checks-frontend: lockfile-check svg-check
.PHONY: checks-backend
checks-backend: gomod-check swagger-check swagger-validate
checks-backend: tidy-check swagger-check fmt-check misspell-check swagger-validate security-check
.PHONY: lint
lint: lint-frontend lint-backend
.PHONY: lint-frontend
lint-frontend: node_modules
npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js docs/assets/js
npx stylelint --color --max-warnings=0 web_src/less
npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js docs/assets/js tests/e2e
npx stylelint --color --max-warnings=0 web_src/css
npx spectral lint -q -F hint $(SWAGGER_SPEC)
npx markdownlint docs *.md
@ -320,7 +352,7 @@ lint-backend: golangci-lint vet editorconfig-checker
.PHONY: watch
watch:
bash tools/watch.sh
bash build/watch.sh
.PHONY: watch-frontend
watch-frontend: node-check node_modules
@ -329,7 +361,7 @@ watch-frontend: node-check node_modules
.PHONY: watch-backend
watch-backend: go-check
$(GO) run $(AIR_PACKAGE) -c .air.toml
GITEA_RUN_MODE=dev $(GO) run $(AIR_PACKAGE) -c .air.toml
.PHONY: test
test: test-frontend test-backend
@ -337,11 +369,11 @@ test: test-frontend test-backend
.PHONY: test-backend
test-backend:
@echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..."
@$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_PACKAGES)
@$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_PACKAGES)
.PHONY: test-frontend
test-frontend: node_modules
@NODE_OPTIONS="--experimental-vm-modules --no-warnings" npx jest --color
npx vitest
.PHONY: test-check
test-check:
@ -358,7 +390,7 @@ test-check:
.PHONY: test\#%
test\#%:
@echo "Running go test with -tags '$(TEST_TAGS)'..."
@$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_PACKAGES)
@$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES)
.PHONY: coverage
coverage:
@ -369,47 +401,51 @@ coverage:
.PHONY: unit-test-coverage
unit-test-coverage:
@echo "Running unit-test-coverage $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..."
@$(GO) test $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
@$(GO) test $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_TEST_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
.PHONY: tidy
tidy:
$(eval MIN_GO_VERSION := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2))
$(GO) mod tidy -compat=$(MIN_GO_VERSION)
@$(MAKE) --no-print-directory $(GO_LICENSE_FILE)
.PHONY: vendor
vendor: tidy
vendor: go.mod go.sum
$(GO) mod vendor
@touch vendor
.PHONY: gomod-check
gomod-check: tidy
@diff=$$(git diff go.sum); \
.PHONY: tidy-check
tidy-check: tidy
@diff=$$(git diff --color=always go.mod go.sum $(GO_LICENSE_FILE)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make tidy' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi
.PHONY: go-licenses
go-licenses: $(GO_LICENSE_FILE)
$(GO_LICENSE_FILE): go.mod go.sum
-$(GO) run $(GO_LICENSES_PACKAGE) save . --force --save_path=$(GO_LICENSE_TMP_DIR) 2>/dev/null
$(GO) run build/generate-go-licenses.go $(GO_LICENSE_TMP_DIR) $(GO_LICENSE_FILE)
@rm -rf $(GO_LICENSE_TMP_DIR)
generate-ini-sqlite:
sed -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
integrations/sqlite.ini.tmpl > integrations/sqlite.ini
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
tests/sqlite.ini.tmpl > tests/sqlite.ini
.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=tests/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=tests/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*)
.PHONY: test-sqlite-migration
test-sqlite-migration: migrations.sqlite.test migrations.individual.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.individual.sqlite.test
.PHONY: test-sqlite-migration\#%
test-sqlite-migration\#%: migrations.sqlite.test migrations.individual.sqlite.test generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./migrations.individual.sqlite.test -test.run $(subst .,/,$*)
test-sqlite-migration: migrations.sqlite.test migrations.individual.sqlite.test
generate-ini-mysql:
sed -e 's|{{TEST_MYSQL_HOST}}|${TEST_MYSQL_HOST}|g' \
@ -417,20 +453,20 @@ generate-ini-mysql:
-e 's|{{TEST_MYSQL_USERNAME}}|${TEST_MYSQL_USERNAME}|g' \
-e 's|{{TEST_MYSQL_PASSWORD}}|${TEST_MYSQL_PASSWORD}|g' \
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
integrations/mysql.ini.tmpl > integrations/mysql.ini
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
tests/mysql.ini.tmpl > tests/mysql.ini
.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=tests/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=tests/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*)
.PHONY: test-mysql-migration
test-mysql-migration: migrations.mysql.test migrations.individual.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.individual.mysql.test
test-mysql-migration: migrations.mysql.test migrations.individual.mysql.test
generate-ini-mysql8:
sed -e 's|{{TEST_MYSQL8_HOST}}|${TEST_MYSQL8_HOST}|g' \
@ -438,20 +474,20 @@ generate-ini-mysql8:
-e 's|{{TEST_MYSQL8_USERNAME}}|${TEST_MYSQL8_USERNAME}|g' \
-e 's|{{TEST_MYSQL8_PASSWORD}}|${TEST_MYSQL8_PASSWORD}|g' \
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
integrations/mysql8.ini.tmpl > integrations/mysql8.ini
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
tests/mysql8.ini.tmpl > tests/mysql8.ini
.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=tests/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=tests/mysql8.ini ./integrations.mysql8.test -test.run $(subst .,/,$*)
.PHONY: test-mysql8-migration
test-mysql8-migration: migrations.mysql8.test migrations.individual.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.individual.mysql8.test
test-mysql8-migration: migrations.mysql8.test migrations.individual.mysql8.test
generate-ini-pgsql:
sed -e 's|{{TEST_PGSQL_HOST}}|${TEST_PGSQL_HOST}|g' \
@ -460,20 +496,20 @@ generate-ini-pgsql:
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
-e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
integrations/pgsql.ini.tmpl > integrations/pgsql.ini
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
tests/pgsql.ini.tmpl > tests/pgsql.ini
.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=tests/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=tests/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*)
.PHONY: test-pgsql-migration
test-pgsql-migration: migrations.pgsql.test migrations.individual.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.individual.pgsql.test
test-pgsql-migration: migrations.pgsql.test migrations.individual.pgsql.test
generate-ini-mssql:
sed -e 's|{{TEST_MSSQL_HOST}}|${TEST_MSSQL_HOST}|g' \
@ -481,105 +517,205 @@ generate-ini-mssql:
-e 's|{{TEST_MSSQL_USERNAME}}|${TEST_MSSQL_USERNAME}|g' \
-e 's|{{TEST_MSSQL_PASSWORD}}|${TEST_MSSQL_PASSWORD}|g' \
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
integrations/mssql.ini.tmpl > integrations/mssql.ini
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
tests/mssql.ini.tmpl > tests/mssql.ini
.PHONY: test-mssql
test-mssql: integrations.mssql.test generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mssql.ini ./integrations.mssql.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test
.PHONY: test-mssql\#%
test-mssql\#%: integrations.mssql.test generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*)
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*)
.PHONY: test-mssql-migration
test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mssql.ini ./migrations.mssql.test -test.failfast
GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mssql.ini ./migrations.individual.mssql.test -test.failfast
test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test
.PHONY: playwright
playwright: $(PLAYWRIGHT_DIR)
npm install --no-save @playwright/test
npx playwright install $(PLAYWRIGHT_FLAGS)
.PHONY: test-e2e%
test-e2e%: TEST_TYPE ?= e2e
# Clear display env variable. Otherwise, chromium tests can fail.
DISPLAY=
.PHONY: test-e2e
test-e2e: test-e2e-sqlite
.PHONY: test-e2e-sqlite
test-e2e-sqlite: playwright e2e.sqlite.test generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test
.PHONY: test-e2e-sqlite\#%
test-e2e-sqlite\#%: playwright e2e.sqlite.test generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestE2e/$*
.PHONY: test-e2e-mysql
test-e2e-mysql: playwright e2e.mysql.test generate-ini-mysql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test
.PHONY: test-e2e-mysql\#%
test-e2e-mysql\#%: playwright e2e.mysql.test generate-ini-mysql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test -test.run TestE2e/$*
.PHONY: test-e2e-mysql8
test-e2e-mysql8: playwright e2e.mysql8.test generate-ini-mysql8
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./e2e.mysql8.test
.PHONY: test-e2e-mysql8\#%
test-e2e-mysql8\#%: playwright e2e.mysql8.test generate-ini-mysql8
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./e2e.mysql8.test -test.run TestE2e/$*
.PHONY: test-e2e-pgsql
test-e2e-pgsql: playwright e2e.pgsql.test generate-ini-pgsql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test
.PHONY: test-e2e-pgsql\#%
test-e2e-pgsql\#%: playwright e2e.pgsql.test generate-ini-pgsql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test -test.run TestE2e/$*
.PHONY: test-e2e-mssql
test-e2e-mssql: playwright e2e.mssql.test generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./e2e.mssql.test
.PHONY: test-e2e-mssql\#%
test-e2e-mssql\#%: playwright e2e.mssql.test generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./e2e.mssql.test -test.run TestE2e/$*
.PHONY: 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=tests/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=tests/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
.PHONY: bench-mssql
bench-mssql: integrations.mssql.test generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/mssql.ini ./integrations.mssql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/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=tests/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=tests/mysql.ini ./integrations.cover.test -test.coverprofile=integration.coverage.out
.PHONY: integration-test-coverage-sqlite
integration-test-coverage-sqlite: integrations.cover.sqlite.test generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./integrations.cover.sqlite.test -test.coverprofile=integration.coverage.out
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.cover.sqlite.test -test.coverprofile=integration.coverage.out
integrations.mysql.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations -o integrations.mysql.test
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql.test
integrations.mysql8.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations -o integrations.mysql8.test
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql8.test
integrations.pgsql.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations -o integrations.pgsql.test
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.pgsql.test
integrations.mssql.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations -o integrations.mssql.test
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mssql.test
integrations.sqlite.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations -o integrations.sqlite.test -tags '$(TEST_TAGS)'
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.sqlite.test -tags '$(TEST_TAGS)'
integrations.cover.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations -coverpkg $(shell echo $(GO_PACKAGES) | tr ' ' ',') -o integrations.cover.test
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.test
integrations.cover.sqlite.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations -coverpkg $(shell echo $(GO_PACKAGES) | tr ' ' ',') -o integrations.cover.sqlite.test -tags '$(TEST_TAGS)'
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.sqlite.test -tags '$(TEST_TAGS)'
.PHONY: migrations.mysql.test
migrations.mysql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations/migration-test -o migrations.mysql.test
migrations.mysql.test: $(GO_SOURCES) generate-ini-mysql
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./migrations.mysql.test
.PHONY: migrations.mysql8.test
migrations.mysql8.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations/migration-test -o migrations.mysql8.test
migrations.mysql8.test: $(GO_SOURCES) generate-ini-mysql8
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql8.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./migrations.mysql8.test
.PHONY: migrations.pgsql.test
migrations.pgsql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations/migration-test -o migrations.pgsql.test
migrations.pgsql.test: $(GO_SOURCES) generate-ini-pgsql
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./migrations.pgsql.test
.PHONY: migrations.mssql.test
migrations.mssql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations/migration-test -o migrations.mssql.test
migrations.mssql.test: $(GO_SOURCES) generate-ini-mssql
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mssql.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./migrations.mssql.test
.PHONY: migrations.sqlite.test
migrations.sqlite.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)'
migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)'
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./migrations.sqlite.test
.PHONY: migrations.individual.mysql.test
migrations.individual.mysql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/models/migrations -o migrations.individual.mysql.test
for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \
done
.PHONY: migrations.individual.mysql8.test
migrations.individual.mysql8.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/models/migrations -o migrations.individual.mysql8.test
for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \
done
.PHONY: migrations.individual.mysql8.test\#%
migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
.PHONY: migrations.individual.pgsql.test
migrations.individual.pgsql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/models/migrations -o migrations.individual.pgsql.test
for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \
done
.PHONY: migrations.individual.pgsql.test\#%
migrations.individual.pgsql.test\#%: $(GO_SOURCES) generate-ini-pgsql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
.PHONY: migrations.individual.mssql.test
migrations.individual.mssql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/models/migrations -o migrations.individual.mssql.test
migrations.individual.mssql.test: $(GO_SOURCES) generate-ini-mssql
for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg -test.failfast; \
done
.PHONY: migrations.individual.mssql.test\#%
migrations.individual.mssql.test\#%: $(GO_SOURCES) generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
.PHONY: migrations.individual.sqlite.test
migrations.individual.sqlite.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/models/migrations -o migrations.individual.sqlite.test -tags '$(TEST_TAGS)'
migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \
done
.PHONY: migrations.individual.sqlite.test\#%
migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
e2e.mysql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mysql.test
e2e.mysql8.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mysql8.test
e2e.pgsql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.pgsql.test
e2e.mssql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mssql.test
e2e.sqlite.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.sqlite.test -tags '$(TEST_TAGS)'
.PHONY: check
check: test
@ -595,27 +731,38 @@ build: frontend backend
frontend: $(WEBPACK_DEST)
.PHONY: backend
backend: go-check generate $(EXECUTABLE)
backend: go-check generate-backend $(EXECUTABLE)
# We generate the backend before the frontend in case we in future we want to generate things in the frontend from generated files in backend
.PHONY: generate
generate: $(TAGS_PREREQ)
generate: generate-backend
.PHONY: generate-backend
generate-backend: $(TAGS_PREREQ) generate-go
.PHONY: generate-go
generate-go: $(TAGS_PREREQ)
@echo "Running go generate..."
@CC= GOOS= GOARCH= $(GO) generate -tags '$(TAGS)' $(GO_PACKAGES)
.PHONY: security-check
security-check:
go run $(GOVULNCHECK_PACKAGE) -v ./...
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
.PHONY: release
release: frontend generate release-windows release-linux release-darwin release-copy release-compress vendor release-sources release-docs release-check
release: frontend generate release-windows release-linux release-darwin release-freebsd release-copy release-compress vendor release-sources release-docs release-check
$(DIST_DIRS):
mkdir -p $(DIST_DIRS)
.PHONY: release-windows
release-windows: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
ifeq (,$(findstring gogit,$(TAGS)))
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
endif
ifeq ($(CI),true)
cp /build/* $(DIST)/binaries
@ -635,6 +782,13 @@ ifeq ($(CI),true)
cp /build/* $(DIST)/binaries
endif
.PHONY: release-freebsd
release-freebsd: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) .
ifeq ($(CI),true)
cp /build/* $(DIST)/binaries
endif
.PHONY: release-copy
release-copy: | $(DIST_DIRS)
cd $(DIST); for file in `find . -type f -name "*"`; do cp $${file} ./release/; done;
@ -662,14 +816,17 @@ 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
docs: deps-docs
cd docs; make trans-copy clean build-offline;
.PHONY: deps-docs
deps-docs:
@hash hugo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
curl -sL https://github.com/gohugoio/hugo/releases/download/v$(HUGO_VERSION)/hugo_$(HUGO_VERSION)_Linux-64bit.tar.gz | tar zxf - -C /tmp && mkdir -p ~/go/bin && mv /tmp/hugo ~/go/bin/hugo && chmod +x ~/go/bin/hugo; \
fi
.PHONY: deps
deps: deps-frontend deps-backend
deps: deps-frontend deps-backend deps-tools deps-docs
.PHONY: deps-frontend
deps-frontend: node_modules
@ -677,6 +834,9 @@ deps-frontend: node_modules
.PHONY: deps-backend
deps-backend:
$(GO) mod download
.PHONY: deps-tools
deps-tools:
$(GO) install $(AIR_PACKAGE)
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE)
$(GO) install $(ERRCHECK_PACKAGE)
@ -686,6 +846,8 @@ deps-backend:
$(GO) install $(MISSPELL_PACKAGE)
$(GO) install $(SWAGGER_PACKAGE)
$(GO) install $(XGO_PACKAGE)
$(GO) install $(GO_LICENSES_PACKAGE)
$(GO) install $(GOVULNCHECK_PACKAGE)
node_modules: package-lock.json
npm install --no-save
@ -705,6 +867,8 @@ fomantic:
cp -f $(FOMANTIC_WORK_DIR)/theme.config.less $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/theme.config
cp -rf $(FOMANTIC_WORK_DIR)/_site $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/
cd $(FOMANTIC_WORK_DIR) && npx gulp -f node_modules/fomantic-ui/gulpfile.js build
# fomantic uses "touchstart" as click event for some browsers, it's not ideal, so we force fomantic to always use "click" as click event
$(SED_INPLACE) -e 's/clickEvent[ \t]*=/clickEvent = "click", unstableClickEvent =/g' $(FOMANTIC_WORK_DIR)/build/semantic.js
$(SED_INPLACE) -e 's/\r//g' $(FOMANTIC_WORK_DIR)/build/semantic.css $(FOMANTIC_WORK_DIR)/build/semantic.js
rm -f $(FOMANTIC_WORK_DIR)/build/*.min.*
@ -725,7 +889,7 @@ svg: node-check | node_modules
.PHONY: svg-check
svg-check: svg
@git add $(SVG_DEST_DIR)
@diff=$$(git diff --cached $(SVG_DEST_DIR)); \
@diff=$$(git diff --color=always --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}"; \
@ -735,7 +899,7 @@ svg-check: svg
.PHONY: lockfile-check
lockfile-check:
npm install --package-lock-only
@diff=$$(git diff package-lock.json); \
@diff=$$(git diff --color=always package-lock.json); \
if [ -n "$$diff" ]; then \
echo "package-lock.json is inconsistent with package.json"; \
echo "Please run 'npm install --package-lock-only' and commit the result:"; \
@ -774,10 +938,6 @@ generate-manpage:
@gzip -9 man/man1/gitea.1 && echo man/man1/gitea.1.gz created
@#TODO A small script that formats config-cheat-sheet.en-us.md nicely for use as a config man page
.PHONY: pr\#%
pr\#%: clean-all
$(GO) run contrib/pr/checkout.go $*
.PHONY: golangci-lint
golangci-lint:
$(GO) run $(GOLANGCI_LINT_PACKAGE) run

View File

@ -12,14 +12,14 @@
<a href="https://discord.gg/Gitea" title="Join the Discord chat at https://discord.gg/Gitea">
<img src="https://img.shields.io/discord/322538954119184384.svg">
</a>
<a href="https://codecov.io/gh/go-gitea/gitea" title="Codecov">
<a href="https://app.codecov.io/gh/go-gitea/gitea" title="Codecov">
<img src="https://codecov.io/gh/go-gitea/gitea/branch/main/graph/badge.svg">
</a>
<a href="https://goreportcard.com/report/code.gitea.io/gitea" title="Go Report Card">
<img src="https://goreportcard.com/badge/code.gitea.io/gitea">
</a>
<a href="https://godoc.org/code.gitea.io/gitea" title="GoDoc">
<img src="https://godoc.org/code.gitea.io/gitea?status.svg">
<a href="https://pkg.go.dev/code.gitea.io/gitea" title="GoDoc">
<img src="https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg">
</a>
<a href="https://github.com/go-gitea/gitea/releases/latest" title="GitHub release">
<img src="https://img.shields.io/github/release/go-gitea/gitea.svg">
@ -33,13 +33,19 @@
<a href="https://opensource.org/licenses/MIT" title="License: MIT">
<img src="https://img.shields.io/badge/License-MIT-blue.svg">
</a>
<a href="https://gitpod.io/#https://github.com/go-gitea/gitea">
<img
src="https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod"
alt="Contribute with Gitpod"
/>
</a>
<a href="https://crowdin.com/project/gitea" title="Crowdin">
<img src="https://badges.crowdin.net/gitea/localized.svg">
</a>
<a href="https://www.tickgit.com/browse?repo=github.com/go-gitea/gitea&branch=main" title="TODOs">
<img src="https://badgen.net/https/api.tickgit.com/badgen/github.com/go-gitea/gitea/main">
</a>
<a href="https://www.bountysource.com/teams/gitea" title="Bountysource">
<a href="https://app.bountysource.com/teams/gitea" title="Bountysource">
<img src="https://img.shields.io/bountysource/team/gitea/activity">
</a>
</p>
@ -145,6 +151,7 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
<a href="https://opencollective.com/gitea/sponsor/7/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/8/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/9/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/9/avatar.svg"></a>
<a href="https://cynkra.com/" target="_blank"><img src="https://images.opencollective.com/cynkra/logo/square/64/192.png"></a>
## FAQ

View File

@ -12,14 +12,14 @@
<a href="https://discord.gg/Gitea" title="Join the Discord chat at https://discord.gg/Gitea">
<img src="https://img.shields.io/discord/322538954119184384.svg">
</a>
<a href="https://codecov.io/gh/go-gitea/gitea" title="Codecov">
<a href="https://app.codecov.io/gh/go-gitea/gitea" title="Codecov">
<img src="https://codecov.io/gh/go-gitea/gitea/branch/main/graph/badge.svg">
</a>
<a href="https://goreportcard.com/report/code.gitea.io/gitea" title="Go Report Card">
<img src="https://goreportcard.com/badge/code.gitea.io/gitea">
</a>
<a href="https://godoc.org/code.gitea.io/gitea" title="GoDoc">
<img src="https://godoc.org/code.gitea.io/gitea?status.svg">
<a href="https://pkg.go.dev/code.gitea.io/gitea" title="GoDoc">
<img src="https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg">
</a>
<a href="https://github.com/go-gitea/gitea/releases/latest" title="GitHub release">
<img src="https://img.shields.io/github/release/go-gitea/gitea.svg">
@ -33,13 +33,19 @@
<a href="https://opensource.org/licenses/MIT" title="License: MIT">
<img src="https://img.shields.io/badge/License-MIT-blue.svg">
</a>
<a href="https://gitpod.io/#https://github.com/go-gitea/gitea">
<img
src="https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod"
alt="Contribute with Gitpod"
/>
</a>
<a href="https://crowdin.com/project/gitea" title="Crowdin">
<img src="https://badges.crowdin.net/gitea/localized.svg">
</a>
<a href="https://www.tickgit.com/browse?repo=github.com/go-gitea/gitea&branch=main" title="TODOs">
<img src="https://badgen.net/https/api.tickgit.com/badgen/github.com/go-gitea/gitea/main">
</a>
<a href="https://img.shields.io/bountysource/team/gitea" title="Bountysource">
<a href="https://app.bountysource.com/teams/gitea" title="Bountysource">
<img src="https://img.shields.io/bountysource/team/gitea/activity">
</a>
</p>

2
assets/emoji.json generated

File diff suppressed because one or more lines are too long

1107
assets/go-licenses.json generated Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,5 @@
// 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.
// SPDX-License-Identifier: MIT
//go:build vendor

118
build/backport-locales.go Normal file
View File

@ -0,0 +1,118 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build ignore
package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"gopkg.in/ini.v1"
)
func main() {
if len(os.Args) != 2 {
println("usage: backport-locales <to-ref>")
println("eg: backport-locales release/v1.19")
os.Exit(1)
}
ini.PrettyFormat = false
mustNoErr := func(err error) {
if err != nil {
panic(err)
}
}
collectInis := func(ref string) map[string]*ini.File {
inis := map[string]*ini.File{}
err := filepath.WalkDir("options/locale", func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() || !strings.HasSuffix(d.Name(), ".ini") {
return nil
}
cfg, err := ini.LoadSources(ini.LoadOptions{
IgnoreInlineComment: true,
UnescapeValueCommentSymbols: true,
}, path)
mustNoErr(err)
inis[path] = cfg
fmt.Printf("collecting: %s @ %s\n", path, ref)
return nil
})
mustNoErr(err)
return inis
}
// collect new locales from current working directory
inisNew := collectInis("HEAD")
// switch to the target ref, and collect the old locales
cmd := exec.Command("git", "checkout", os.Args[1])
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
mustNoErr(cmd.Run())
inisOld := collectInis(os.Args[1])
// use old en-US as the base, and copy the new translations to the old locales
enUsOld := inisOld["options/locale/locale_en-US.ini"]
brokenWarned := map[string]bool{}
for path, iniOld := range inisOld {
if iniOld == enUsOld {
continue
}
iniNew := inisNew[path]
if iniNew == nil {
continue
}
for _, secEnUS := range enUsOld.Sections() {
secOld := iniOld.Section(secEnUS.Name())
secNew := iniNew.Section(secEnUS.Name())
for _, keyEnUs := range secEnUS.Keys() {
if secNew.HasKey(keyEnUs.Name()) {
oldStr := secOld.Key(keyEnUs.Name()).String()
newStr := secNew.Key(keyEnUs.Name()).String()
broken := oldStr != "" && strings.Count(oldStr, "%") != strings.Count(newStr, "%")
broken = broken || strings.Contains(oldStr, "\n") || strings.Contains(oldStr, "\n")
if broken {
brokenWarned[secOld.Name()+"."+keyEnUs.Name()] = true
fmt.Println("----")
fmt.Printf("WARNING: skip broken locale: %s , [%s] %s\n", path, secEnUS.Name(), keyEnUs.Name())
fmt.Printf("\told: %s\n", strings.ReplaceAll(oldStr, "\n", "\\n"))
fmt.Printf("\tnew: %s\n", strings.ReplaceAll(newStr, "\n", "\\n"))
continue
}
secOld.Key(keyEnUs.Name()).SetValue(newStr)
}
}
}
mustNoErr(iniOld.SaveTo(path))
}
fmt.Println("========")
for path, iniNew := range inisNew {
for _, sec := range iniNew.Sections() {
for _, key := range sec.Keys() {
str := sec.Key(key.Name()).String()
broken := strings.Contains(str, "\n")
broken = broken || strings.HasPrefix(str, "`") != strings.HasSuffix(str, "`")
broken = broken || strings.HasPrefix(str, "\"`")
broken = broken || strings.HasPrefix(str, "`\"")
broken = broken || strings.Count(str, `"`)%2 == 1
broken = broken || strings.Count(str, "`")%2 == 1
if broken && !brokenWarned[sec.Name()+"."+key.Name()] {
fmt.Printf("WARNING: found broken locale: %s , [%s] %s\n", path, sec.Name(), key.Name())
fmt.Printf("\tstr: %s\n", strings.ReplaceAll(str, "\n", "\\n"))
fmt.Println("----")
}
}
}
}
}

View File

@ -1,6 +1,5 @@
// Copyright 2021 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.
// SPDX-License-Identifier: MIT
//go:build ignore
@ -20,7 +19,7 @@ import (
)
// Windows has a limitation for command line arguments, the size can not exceed 32KB.
// So we have to feed the files to some tools (like gofmt/misspell) batch by batch
// So we have to feed the files to some tools (like gofmt) batch by batch
// We also introduce a `gitea-fmt` command, it does better import formatting than gofmt/goimports. `gitea-fmt` calls `gofmt` internally.
@ -61,18 +60,17 @@ func newFileCollector(fileFilter string, batchSize int) (*fileCollector, error)
"build",
"cmd",
"contrib",
"integrations",
"tests",
"models",
"modules",
"routers",
"services",
"tools",
}
co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`.*\bbindata\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`integrations/gitea-repositories-meta`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`integrations/migration-test`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/gitea-repositories-meta`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/integration/migration-test`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`modules/git/tests`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`models/fixtures`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`models/migrations/fixtures`))
@ -195,7 +193,6 @@ Options:
Commands:
%[1]s gofmt ...
%[1]s misspell ...
Arguments:
{file-list} the file list
@ -206,6 +203,17 @@ Example:
`, "file-batch-exec")
}
func getGoVersion() string {
goModFile, err := os.ReadFile("go.mod")
if err != nil {
log.Fatalf(`Faild to read "go.mod": %v`, err)
os.Exit(1)
}
goModVersionRegex := regexp.MustCompile(`go \d+\.\d+`)
goModVersionLine := goModVersionRegex.Find(goModFile)
return string(goModVersionLine[3:])
}
func newFileCollectorFromMainOptions(mainOptions map[string]string) (fc *fileCollector, err error) {
fileFilter := mainOptions["file-filter"]
if fileFilter == "" {
@ -228,9 +236,9 @@ func containsString(a []string, s string) bool {
return false
}
func giteaFormatGoImports(files []string, hasChangedFiles, doWriteFile bool) error {
func giteaFormatGoImports(files []string, doWriteFile bool) error {
for _, file := range files {
if err := codeformat.FormatGoImports(file, hasChangedFiles, doWriteFile); err != nil {
if err := codeformat.FormatGoImports(file, doWriteFile); err != nil {
log.Printf("failed to format go imports: %s, err=%v", file, err)
return err
}
@ -269,10 +277,8 @@ func main() {
if containsString(subArgs, "-d") {
log.Print("the -d option is not supported by gitea-fmt")
}
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-l"), containsString(subArgs, "-w")))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", "1.17"}, substArgs...)))
case "misspell":
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("MISSPELL_PACKAGE")}, substArgs...)))
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-w")))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", getGoVersion()}, substArgs...)))
default:
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
}

View File

@ -1,13 +1,11 @@
// Copyright 2021 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.
// SPDX-License-Identifier: MIT
package codeformat
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"sort"
@ -159,7 +157,7 @@ func formatGoImports(contentBytes []byte) ([]byte, error) {
}
// FormatGoImports format the imports by our rules (see unit tests)
func FormatGoImports(file string, doChangedFiles, doWriteFile bool) error {
func FormatGoImports(file string, doWriteFile bool) error {
f, err := os.Open(file)
if err != nil {
return err
@ -183,10 +181,6 @@ func FormatGoImports(file string, doChangedFiles, doWriteFile bool) error {
return nil
}
if doChangedFiles {
fmt.Println(file)
}
if doWriteFile {
f, err = os.OpenFile(file, os.O_TRUNC|os.O_WRONLY, 0o644)
if err != nil {

View File

@ -1,6 +1,5 @@
// Copyright 2021 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.
// SPDX-License-Identifier: MIT
package codeformat

View File

@ -1,6 +1,5 @@
// 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.
// SPDX-License-Identifier: MIT
//go:build ignore
@ -33,11 +32,15 @@ func needsUpdate(dir, filename string) (bool, []byte) {
hasher := sha1.New()
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
err = filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
_, _ = hasher.Write([]byte(info.Name()))
info, err := d.Info()
if err != nil {
return err
}
_, _ = hasher.Write([]byte(d.Name()))
_, _ = hasher.Write([]byte(info.ModTime().String()))
_, _ = hasher.Write([]byte(strconv.FormatInt(info.Size(), 16)))
return nil

View File

@ -1,7 +1,6 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Copyright 2015 Kenneth Shaw
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT
//go:build ignore
@ -26,7 +25,7 @@ import (
const (
gemojiURL = "https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json"
maxUnicodeVersion = 12
maxUnicodeVersion = 14
)
var flagOut = flag.String("o", "modules/emoji/emoji_data.go", "out")
@ -61,13 +60,13 @@ func main() {
// generate data
buf, err := generate()
if err != nil {
log.Fatal(err)
log.Fatalf("generate err: %v", err)
}
// write
err = os.WriteFile(*flagOut, buf, 0o644)
if err != nil {
log.Fatal(err)
log.Fatalf("WriteFile err: %v", err)
}
}
@ -190,6 +189,10 @@ func generate() ([]byte, error) {
}
}
sort.Slice(data, func(i, j int) bool {
return data[i].Aliases[0] < data[j].Aliases[0]
})
// add header
str := replacer.Replace(fmt.Sprintf(hdr, gemojiURL, data))
@ -209,13 +212,12 @@ func generate() ([]byte, error) {
const hdr = `
// 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.
// SPDX-License-Identifier: MIT
package emoji
// Code generated by gen.go. DO NOT EDIT.
// Code generated by build/generate-emoji.go. DO NOT EDIT.
// Sourced from %s
//
var GemojiData = %#v
`

View File

@ -0,0 +1,84 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build ignore
package main
import (
"encoding/json"
"io/fs"
"os"
goPath "path"
"path/filepath"
"regexp"
"sort"
"strings"
)
// regexp is based on go-license, excluding README and NOTICE
// https://github.com/google/go-licenses/blob/master/licenses/find.go
var licenseRe = regexp.MustCompile(`^(?i)((UN)?LICEN(S|C)E|COPYING).*$`)
type LicenseEntry struct {
Name string `json:"name"`
Path string `json:"path"`
LicenseText string `json:"licenseText"`
}
func main() {
base, out := os.Args[1], os.Args[2]
paths := []string{}
err := filepath.WalkDir(base, func(path string, entry fs.DirEntry, err error) error {
if err != nil {
return err
}
if entry.IsDir() || !licenseRe.MatchString(entry.Name()) {
return nil
}
paths = append(paths, path)
return nil
})
if err != nil {
panic(err)
}
sort.Strings(paths)
entries := []LicenseEntry{}
for _, path := range paths {
path := filepath.ToSlash(path)
licenseText, err := os.ReadFile(path)
if err != nil {
panic(err)
}
path = strings.Replace(path, base+"/", "", 1)
name := goPath.Dir(path)
// There might be a bug somewhere in go-licenses that sometimes interprets the
// root package as "." and sometimes as "code.gitea.io/gitea". Workaround by
// removing both of them for the sake of stable output.
if name == "." || name == "code.gitea.io/gitea" {
continue
}
entries = append(entries, LicenseEntry{
Name: name,
Path: path,
LicenseText: string(licenseText),
})
}
jsonBytes, err := json.MarshalIndent(entries, "", " ")
if err != nil {
panic(err)
}
err = os.WriteFile(out, jsonBytes, 0o644)
if err != nil {
panic(err)
}
}

View File

@ -2,7 +2,7 @@
import imageminZopfli from 'imagemin-zopfli';
import {optimize} from 'svgo';
import {fabric} from 'fabric';
import {readFile, writeFile} from 'fs/promises';
import {readFile, writeFile} from 'node:fs/promises';
function exit(err) {
if (err) console.error(err);

View File

@ -1,9 +1,9 @@
#!/usr/bin/env node
import fastGlob from 'fast-glob';
import {optimize} from 'svgo';
import {parse} from 'path';
import {readFile, writeFile, mkdir} from 'fs/promises';
import {fileURLToPath} from 'url';
import {parse} from 'node:path';
import {readFile, writeFile, mkdir} from 'node:fs/promises';
import {fileURLToPath} from 'node:url';
const glob = (pattern) => fastGlob.sync(pattern, {
cwd: fileURLToPath(new URL('..', import.meta.url)),
@ -25,14 +25,22 @@ async function processFile(file, {prefix, fullName} = {}) {
if (prefix === 'octicon') name = name.replace(/-[0-9]+$/, ''); // chop of '-16' on octicons
}
// Set the `xmlns` attribute so that the files are displayable in standalone documents
// The svg backend module will strip the attribute during startup for inline display
const {data} = optimize(await readFile(file, 'utf8'), {
plugins: [
{name: 'preset-default'},
{name: 'removeXMLNS'},
{name: 'removeDimensions'},
{name: 'prefixIds', params: {prefix: () => name}},
{name: 'addClassesToSVGElement', params: {classNames: ['svg', name]}},
{name: 'addAttributesToSVGElement', params: {attributes: [{'width': '16'}, {'height': '16'}, {'aria-hidden': 'true'}]}},
{
name: 'addAttributesToSVGElement', params: {
attributes: [
{'xmlns': 'http://www.w3.org/2000/svg'},
{'width': '16'}, {'height': '16'}, {'aria-hidden': 'true'},
]
}
},
],
});

View File

@ -1,26 +0,0 @@
// Copyright 2021 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.
//go:build ignore
package main
import (
"log"
"os"
"code.gitea.io/gitea/build/codeformat"
)
func main() {
if len(os.Args) <= 1 {
log.Fatalf("Usage: gitea-format-imports [files...]")
}
for _, file := range os.Args[1:] {
if err := codeformat.FormatGoImports(file); err != nil {
log.Fatalf("can not format file %s, err=%v", file, err)
}
}
}

View File

@ -1,7 +1,6 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Copyright (c) 2015, Wade Simmons
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT
// gocovmerge takes the results from multiple `go test -coverprofile` runs and
// merges them into one profile

20
build/test-echo.go Normal file
View File

@ -0,0 +1,20 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build ignore
package main
import (
"fmt"
"io"
"os"
)
func main() {
_, err := io.Copy(os.Stdout, os.Stdin)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v", err)
os.Exit(1)
}
}

View File

@ -1,14 +1,43 @@
#!/bin/sh
# this script runs in alpine image which only has `sh` shell
set +e
if sed --version 2>/dev/null | grep -q GNU; then
SED_INPLACE="sed -i"
else
SED_INPLACE="sed -i ''"
fi
set -e
if [ ! -f ./options/locale/locale_en-US.ini ]; then
echo "please run this script in the root directory of the project"
exit 1
fi
mv ./options/locale/locale_en-US.ini ./options/
# Make sure to only change lines that have the translation enclosed between quotes
sed -i -r -e '/^[a-zA-Z0-9_.-]+[ ]*=[ ]*".*"$/ {
s/^([a-zA-Z0-9_.-]+)[ ]*="/\1=/
s/\\"/"/g
# the "ini" library for locale has many quirks, its behavior is different from Crowdin.
# see i18n_test.go for more details
# this script helps to unquote the Crowdin outputs for the quirky ini library
# * find all `key="...\"..."` lines
# * remove the leading quote
# * remove the trailing quote
# * unescape the quotes
# * eg: key="...\"..." => key=..."...
$SED_INPLACE -r -e '/^[-.A-Za-z0-9_]+[ ]*=[ ]*".*"$/ {
s/^([-.A-Za-z0-9_]+)[ ]*=[ ]*"/\1=/
s/"$//
s/\\"/"/g
}' ./options/locale/*.ini
# * if the escaped line is incomplete like `key="...` or `key=..."`, quote it with backticks
# * eg: key="... => key=`"...`
# * eg: key=..." => key=`..."`
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*(".*[^"])$/\1=`\2`/' ./options/locale/*.ini
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*([^"].*")$/\1=`\2`/' ./options/locale/*.ini
# Remove translation under 25% of en_us
baselines=$(wc -l "./options/locale_en-US.ini" | cut -d" " -f1)
baselines=$((baselines / 4))

View File

@ -1,37 +1,30 @@
// Copyright 2016 The Gogs Authors. All rights reserved.
// Copyright 2016 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.
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"errors"
"fmt"
"net/url"
"os"
"strings"
"text/tabwriter"
"code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/auth"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
pwd "code.gitea.io/gitea/modules/password"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/util"
auth_service "code.gitea.io/gitea/services/auth"
"code.gitea.io/gitea/services/auth/source/oauth2"
"code.gitea.io/gitea/services/auth/source/smtp"
repo_service "code.gitea.io/gitea/services/repository"
user_service "code.gitea.io/gitea/services/user"
"github.com/urfave/cli"
)
@ -50,142 +43,6 @@ var (
},
}
subcmdUser = cli.Command{
Name: "user",
Usage: "Modify users",
Subcommands: []cli.Command{
microcmdUserCreate,
microcmdUserList,
microcmdUserChangePassword,
microcmdUserDelete,
microcmdUserGenerateAccessToken,
},
}
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{
cli.StringFlag{
Name: "name",
Usage: "Username. DEPRECATED: use username instead",
},
cli.StringFlag{
Name: "username",
Usage: "Username",
},
cli.StringFlag{
Name: "password",
Usage: "User password",
},
cli.StringFlag{
Name: "email",
Usage: "User email address",
},
cli.BoolFlag{
Name: "admin",
Usage: "User is an admin",
},
cli.BoolFlag{
Name: "random-password",
Usage: "Generate a random password for the user",
},
cli.BoolFlag{
Name: "must-change-password",
Usage: "Set this option to false to prevent forcing the user to change their password after initial login, (Default: true)",
},
cli.IntFlag{
Name: "random-password-length",
Usage: "Length of the random password to be generated",
Value: 12,
},
cli.BoolFlag{
Name: "access-token",
Usage: "Generate access token for the user",
},
cli.BoolFlag{
Name: "restricted",
Usage: "Make a restricted user account",
},
},
}
microcmdUserChangePassword = cli.Command{
Name: "change-password",
Usage: "Change a user's password",
Action: runChangePassword,
Flags: []cli.Flag{
cli.StringFlag{
Name: "username,u",
Value: "",
Usage: "The user to change password for",
},
cli.StringFlag{
Name: "password,p",
Value: "",
Usage: "New password to set for user",
},
},
}
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",
},
cli.BoolFlag{
Name: "purge",
Usage: "Purge user, all their repositories, organizations and comments",
},
},
Action: runDeleteUser,
}
microcmdUserGenerateAccessToken = cli.Command{
Name: "generate-access-token",
Usage: "Generate a access token for a specific user",
Flags: []cli.Flag{
cli.StringFlag{
Name: "username,u",
Usage: "Username",
},
cli.StringFlag{
Name: "token-name,t",
Usage: "Token name",
Value: "gitea-admin",
},
cli.BoolFlag{
Name: "raw",
Usage: "Display only the token value",
},
},
Action: runGenerateAccessToken,
}
subcmdRepoSyncReleases = cli.Command{
Name: "repo-sync-releases",
Usage: "Synchronize repository releases with tags",
@ -305,6 +162,11 @@ var (
Value: "false",
Usage: "Use custom URLs for GitLab/GitHub OAuth endpoints",
},
cli.StringFlag{
Name: "custom-tenant-id",
Value: "",
Usage: "Use custom Tenant ID for OAuth endpoints",
},
cli.StringFlag{
Name: "custom-auth-url",
Value: "",
@ -364,6 +226,15 @@ var (
Value: "",
Usage: "Group Claim value for restricted users",
},
cli.StringFlag{
Name: "group-team-map",
Value: "",
Usage: "JSON mapping between groups and org teams",
},
cli.BoolFlag{
Name: "group-team-map-removal",
Usage: "Activate automatic team membership removal depending on groups",
},
}
microcmdAuthUpdateOauth = cli.Command{
@ -414,9 +285,9 @@ var (
Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN",
},
cli.StringFlag{
Name: "addr",
Name: "host",
Value: "",
Usage: "SMTP Addr",
Usage: "SMTP Host",
},
cli.IntFlag{
Name: "port",
@ -469,255 +340,6 @@ var (
}
)
func runChangePassword(c *cli.Context) error {
if err := argsSet(c, "username", "password"); err != nil {
return err
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
if len(c.String("password")) < setting.MinPasswordLength {
return fmt.Errorf("Password is not long enough. Needs to be at least %d", setting.MinPasswordLength)
}
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 := user_model.GetUserByName(ctx, uname)
if err != nil {
return err
}
if err = user.SetPassword(c.String("password")); err != nil {
return err
}
if err = user_model.UpdateUserCols(ctx, user, "passwd", "passwd_hash_algo", "salt"); err != nil {
return err
}
fmt.Printf("%s's password has been successfully updated!\n", user.Name)
return nil
}
func runCreateUser(c *cli.Context) error {
if err := argsSet(c, "email"); err != nil {
return err
}
if c.IsSet("name") && c.IsSet("username") {
return errors.New("Cannot set both --name and --username flags")
}
if !c.IsSet("name") && !c.IsSet("username") {
return errors.New("One of --name or --username flags must be set")
}
if c.IsSet("password") && c.IsSet("random-password") {
return errors.New("cannot set both -random-password and -password flags")
}
var username string
if c.IsSet("username") {
username = c.String("username")
} else {
username = c.String("name")
fmt.Fprintf(os.Stderr, "--name flag is deprecated. Use --username instead.\n")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
var password string
if c.IsSet("password") {
password = c.String("password")
} else if c.IsSet("random-password") {
var err error
password, err = pwd.Generate(c.Int("random-password-length"))
if err != nil {
return err
}
fmt.Printf("generated random password is '%s'\n", password)
} else {
return errors.New("must set either password or random-password flag")
}
// always default to true
changePassword := true
// If this is the first user being created.
// Take it as the admin and don't force a password update.
if n := user_model.CountUsers(nil); n == 0 {
changePassword = false
}
if c.IsSet("must-change-password") {
changePassword = c.Bool("must-change-password")
}
restricted := util.OptionalBoolNone
if c.IsSet("restricted") {
restricted = util.OptionalBoolOf(c.Bool("restricted"))
}
u := &user_model.User{
Name: username,
Email: c.String("email"),
Passwd: password,
IsAdmin: c.Bool("admin"),
MustChangePassword: changePassword,
}
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolTrue,
IsRestricted: restricted,
}
if err := user_model.CreateUser(u, overwriteDefault); err != nil {
return fmt.Errorf("CreateUser: %v", err)
}
if c.Bool("access-token") {
t := &models.AccessToken{
Name: "gitea-admin",
UID: u.ID,
}
if err := models.NewAccessToken(t); err != nil {
return err
}
fmt.Printf("Access token was successfully created... %s\n", t.Token)
}
fmt.Printf("New user '%s' has been successfully created!\n", username)
return nil
}
func runListUsers(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
users, err := user_model.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 {
twofa := user_model.UserList(users).GetTwoFaStatus()
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n")
for _, u := range users {
fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\t%t\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin, twofa[u.ID])
}
}
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")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
if err := storage.Init(); err != nil {
return err
}
var err error
var user *user_model.User
if c.IsSet("email") {
user, err = user_model.GetUserByEmail(c.String("email"))
} else if c.IsSet("username") {
user, err = user_model.GetUserByName(ctx, c.String("username"))
} else {
user, err = user_model.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 user_service.DeleteUser(ctx, user, c.Bool("purge"))
}
func runGenerateAccessToken(c *cli.Context) error {
if !c.IsSet("username") {
return fmt.Errorf("You must provide the username to generate a token for them")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
user, err := user_model.GetUserByName(ctx, c.String("username"))
if err != nil {
return err
}
t := &models.AccessToken{
Name: c.String("token-name"),
UID: user.ID,
}
if err := models.NewAccessToken(t); err != nil {
return err
}
if c.Bool("raw") {
fmt.Printf("%s\n", t.Token)
} else {
fmt.Printf("Access token was successfully created: %s\n", t.Token)
}
return nil
}
func runRepoSyncReleases(_ *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
@ -728,7 +350,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
log.Trace("Synchronizing repository releases (this may take a while)")
for page := 1; ; page++ {
repos, count, err := repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{
repos, count, err := repo_model.SearchRepositoryByName(ctx, &repo_model.SearchRepoOptions{
ListOptions: db.ListOptions{
PageSize: repo_model.RepositoryListDefaultPageSize,
Page: page,
@ -736,7 +358,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
Private: true,
})
if err != nil {
return fmt.Errorf("SearchRepositoryByName: %v", err)
return fmt.Errorf("SearchRepositoryByName: %w", err)
}
if len(repos) == 0 {
break
@ -779,9 +401,10 @@ func runRepoSyncReleases(_ *cli.Context) error {
}
func getReleaseCount(id int64) (int64, error) {
return models.GetReleaseCountByRepoID(
return repo_model.GetReleaseCountByRepoID(
db.DefaultContext,
id,
models.FindReleasesOptions{
repo_model.FindReleasesOptions{
IncludeTags: true,
},
)
@ -815,6 +438,7 @@ func parseOAuth2Config(c *cli.Context) *oauth2.Source {
AuthURL: c.String("custom-auth-url"),
ProfileURL: c.String("custom-profile-url"),
EmailURL: c.String("custom-email-url"),
Tenant: c.String("custom-tenant-id"),
}
} else {
customURLMapping = nil
@ -833,6 +457,8 @@ func parseOAuth2Config(c *cli.Context) *oauth2.Source {
GroupClaimName: c.String("group-claim-name"),
AdminGroup: c.String("admin-group"),
RestrictedGroup: c.String("restricted-group"),
GroupTeamMap: c.String("group-team-map"),
GroupTeamMapRemoval: c.Bool("group-team-map-removal"),
}
}
@ -844,11 +470,19 @@ func runAddOauth(c *cli.Context) error {
return err
}
return auth.CreateSource(&auth.Source{
Type: auth.OAuth2,
config := parseOAuth2Config(c)
if config.Provider == "openidConnect" {
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
return fmt.Errorf("invalid Auto Discovery URL: %s (this must be a valid URL starting with http:// or https://)", config.OpenIDConnectAutoDiscoveryURL)
}
}
return auth_model.CreateSource(&auth_model.Source{
Type: auth_model.OAuth2,
Name: c.String("name"),
IsActive: true,
Cfg: parseOAuth2Config(c),
Cfg: config,
})
}
@ -864,7 +498,7 @@ func runUpdateOauth(c *cli.Context) error {
return err
}
source, err := auth.GetSourceByID(c.Int64("id"))
source, err := auth_model.GetSourceByID(c.Int64("id"))
if err != nil {
return err
}
@ -915,6 +549,12 @@ func runUpdateOauth(c *cli.Context) error {
if c.IsSet("restricted-group") {
oAuth2Config.RestrictedGroup = c.String("restricted-group")
}
if c.IsSet("group-team-map") {
oAuth2Config.GroupTeamMap = c.String("group-team-map")
}
if c.IsSet("group-team-map-removal") {
oAuth2Config.GroupTeamMapRemoval = c.Bool("group-team-map-removal")
}
// update custom URL mapping
customURLMapping := &oauth2.CustomURLMapping{}
@ -924,6 +564,7 @@ func runUpdateOauth(c *cli.Context) error {
customURLMapping.AuthURL = oAuth2Config.CustomURLMapping.AuthURL
customURLMapping.ProfileURL = oAuth2Config.CustomURLMapping.ProfileURL
customURLMapping.EmailURL = oAuth2Config.CustomURLMapping.EmailURL
customURLMapping.Tenant = oAuth2Config.CustomURLMapping.Tenant
}
if c.IsSet("use-custom-urls") && c.IsSet("custom-token-url") {
customURLMapping.TokenURL = c.String("custom-token-url")
@ -941,23 +582,27 @@ func runUpdateOauth(c *cli.Context) error {
customURLMapping.EmailURL = c.String("custom-email-url")
}
if c.IsSet("use-custom-urls") && c.IsSet("custom-tenant-id") {
customURLMapping.Tenant = c.String("custom-tenant-id")
}
oAuth2Config.CustomURLMapping = customURLMapping
source.Cfg = oAuth2Config
return auth.UpdateSource(source)
return auth_model.UpdateSource(source)
}
func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
if c.IsSet("auth-type") {
conf.Auth = c.String("auth-type")
validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"}
if !contains(validAuthTypes, strings.ToUpper(c.String("auth-type"))) {
if !util.SliceContainsString(validAuthTypes, strings.ToUpper(c.String("auth-type"))) {
return errors.New("Auth must be one of PLAIN/LOGIN/CRAM-MD5")
}
conf.Auth = c.String("auth-type")
}
if c.IsSet("addr") {
conf.Addr = c.String("addr")
if c.IsSet("host") {
conf.Host = c.String("host")
}
if c.IsSet("port") {
conf.Port = c.Int("port")
@ -1015,8 +660,8 @@ func runAddSMTP(c *cli.Context) error {
smtpConfig.Auth = "PLAIN"
}
return auth.CreateSource(&auth.Source{
Type: auth.SMTP,
return auth_model.CreateSource(&auth_model.Source{
Type: auth_model.SMTP,
Name: c.String("name"),
IsActive: active,
Cfg: &smtpConfig,
@ -1035,7 +680,7 @@ func runUpdateSMTP(c *cli.Context) error {
return err
}
source, err := auth.GetSourceByID(c.Int64("id"))
source, err := auth_model.GetSourceByID(c.Int64("id"))
if err != nil {
return err
}
@ -1056,7 +701,7 @@ func runUpdateSMTP(c *cli.Context) error {
source.Cfg = smtpConfig
return auth.UpdateSource(source)
return auth_model.UpdateSource(source)
}
func runListAuth(c *cli.Context) error {
@ -1067,7 +712,7 @@ func runListAuth(c *cli.Context) error {
return err
}
authSources, err := auth.Sources()
authSources, err := auth_model.Sources()
if err != nil {
return err
}
@ -1105,7 +750,7 @@ func runDeleteAuth(c *cli.Context) error {
return err
}
source, err := auth.GetSourceByID(c.Int64("id"))
source, err := auth_model.GetSourceByID(c.Int64("id"))
if err != nil {
return err
}

View File

@ -1,6 +1,5 @@
// Copyright 2019 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.
// SPDX-License-Identifier: MIT
package cmd

View File

@ -1,6 +1,5 @@
// Copyright 2019 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.
// SPDX-License-Identifier: MIT
package cmd

21
cmd/admin_user.go Normal file
View File

@ -0,0 +1,21 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"github.com/urfave/cli"
)
var subcmdUser = cli.Command{
Name: "user",
Usage: "Modify users",
Subcommands: []cli.Command{
microcmdUserCreate,
microcmdUserList,
microcmdUserChangePassword,
microcmdUserDelete,
microcmdUserGenerateAccessToken,
microcmdUserMustChangePassword,
},
}

View File

@ -0,0 +1,76 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"errors"
"fmt"
user_model "code.gitea.io/gitea/models/user"
pwd "code.gitea.io/gitea/modules/auth/password"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli"
)
var microcmdUserChangePassword = cli.Command{
Name: "change-password",
Usage: "Change a user's password",
Action: runChangePassword,
Flags: []cli.Flag{
cli.StringFlag{
Name: "username,u",
Value: "",
Usage: "The user to change password for",
},
cli.StringFlag{
Name: "password,p",
Value: "",
Usage: "New password to set for user",
},
},
}
func runChangePassword(c *cli.Context) error {
if err := argsSet(c, "username", "password"); err != nil {
return err
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
if len(c.String("password")) < setting.MinPasswordLength {
return fmt.Errorf("Password is not long enough. Needs to be at least %d", setting.MinPasswordLength)
}
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 := user_model.GetUserByName(ctx, uname)
if err != nil {
return err
}
if err = user.SetPassword(c.String("password")); err != nil {
return err
}
if err = user_model.UpdateUserCols(ctx, user, "passwd", "passwd_hash_algo", "salt"); err != nil {
return err
}
fmt.Printf("%s's password has been successfully updated!\n", user.Name)
return nil
}

169
cmd/admin_user_create.go Normal file
View File

@ -0,0 +1,169 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"errors"
"fmt"
"os"
auth_model "code.gitea.io/gitea/models/auth"
user_model "code.gitea.io/gitea/models/user"
pwd "code.gitea.io/gitea/modules/auth/password"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"github.com/urfave/cli"
)
var microcmdUserCreate = cli.Command{
Name: "create",
Usage: "Create a new user in database",
Action: runCreateUser,
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Usage: "Username. DEPRECATED: use username instead",
},
cli.StringFlag{
Name: "username",
Usage: "Username",
},
cli.StringFlag{
Name: "password",
Usage: "User password",
},
cli.StringFlag{
Name: "email",
Usage: "User email address",
},
cli.BoolFlag{
Name: "admin",
Usage: "User is an admin",
},
cli.BoolFlag{
Name: "random-password",
Usage: "Generate a random password for the user",
},
cli.BoolFlag{
Name: "must-change-password",
Usage: "Set this option to false to prevent forcing the user to change their password after initial login, (Default: true)",
},
cli.IntFlag{
Name: "random-password-length",
Usage: "Length of the random password to be generated",
Value: 12,
},
cli.BoolFlag{
Name: "access-token",
Usage: "Generate access token for the user",
},
cli.BoolFlag{
Name: "restricted",
Usage: "Make a restricted user account",
},
},
}
func runCreateUser(c *cli.Context) error {
if err := argsSet(c, "email"); err != nil {
return err
}
if c.IsSet("name") && c.IsSet("username") {
return errors.New("Cannot set both --name and --username flags")
}
if !c.IsSet("name") && !c.IsSet("username") {
return errors.New("One of --name or --username flags must be set")
}
if c.IsSet("password") && c.IsSet("random-password") {
return errors.New("cannot set both -random-password and -password flags")
}
var username string
if c.IsSet("username") {
username = c.String("username")
} else {
username = c.String("name")
fmt.Fprintf(os.Stderr, "--name flag is deprecated. Use --username instead.\n")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
var password string
if c.IsSet("password") {
password = c.String("password")
} else if c.IsSet("random-password") {
var err error
password, err = pwd.Generate(c.Int("random-password-length"))
if err != nil {
return err
}
fmt.Printf("generated random password is '%s'\n", password)
} else {
return errors.New("must set either password or random-password flag")
}
// always default to true
changePassword := true
// If this is the first user being created.
// Take it as the admin and don't force a password update.
if n := user_model.CountUsers(nil); n == 0 {
changePassword = false
}
if c.IsSet("must-change-password") {
changePassword = c.Bool("must-change-password")
}
restricted := util.OptionalBoolNone
if c.IsSet("restricted") {
restricted = util.OptionalBoolOf(c.Bool("restricted"))
}
// default user visibility in app.ini
visibility := setting.Service.DefaultUserVisibilityMode
u := &user_model.User{
Name: username,
Email: c.String("email"),
Passwd: password,
IsAdmin: c.Bool("admin"),
MustChangePassword: changePassword,
Visibility: visibility,
}
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolTrue,
IsRestricted: restricted,
}
if err := user_model.CreateUser(u, overwriteDefault); err != nil {
return fmt.Errorf("CreateUser: %w", err)
}
if c.Bool("access-token") {
t := &auth_model.AccessToken{
Name: "gitea-admin",
UID: u.ID,
}
if err := auth_model.NewAccessToken(t); err != nil {
return err
}
fmt.Printf("Access token was successfully created... %s\n", t.Token)
}
fmt.Printf("New user '%s' has been successfully created!\n", username)
return nil
}

78
cmd/admin_user_delete.go Normal file
View File

@ -0,0 +1,78 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"strings"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/storage"
user_service "code.gitea.io/gitea/services/user"
"github.com/urfave/cli"
)
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",
},
cli.BoolFlag{
Name: "purge",
Usage: "Purge user, all their repositories, organizations and comments",
},
},
Action: runDeleteUser,
}
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")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
if err := storage.Init(); err != nil {
return err
}
var err error
var user *user_model.User
if c.IsSet("email") {
user, err = user_model.GetUserByEmail(ctx, c.String("email"))
} else if c.IsSet("username") {
user, err = user_model.GetUserByName(ctx, c.String("username"))
} else {
user, err = user_model.GetUserByID(ctx, 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 user_service.DeleteUser(ctx, user, c.Bool("purge"))
}

View File

@ -0,0 +1,80 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
auth_model "code.gitea.io/gitea/models/auth"
user_model "code.gitea.io/gitea/models/user"
"github.com/urfave/cli"
)
var microcmdUserGenerateAccessToken = cli.Command{
Name: "generate-access-token",
Usage: "Generate an access token for a specific user",
Flags: []cli.Flag{
cli.StringFlag{
Name: "username,u",
Usage: "Username",
},
cli.StringFlag{
Name: "token-name,t",
Usage: "Token name",
Value: "gitea-admin",
},
cli.BoolFlag{
Name: "raw",
Usage: "Display only the token value",
},
cli.StringFlag{
Name: "scopes",
Value: "",
Usage: "Comma separated list of scopes to apply to access token",
},
},
Action: runGenerateAccessToken,
}
func runGenerateAccessToken(c *cli.Context) error {
if !c.IsSet("username") {
return fmt.Errorf("You must provide a username to generate a token for")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
user, err := user_model.GetUserByName(ctx, c.String("username"))
if err != nil {
return err
}
accessTokenScope, err := auth_model.AccessTokenScope(c.String("scopes")).Normalize()
if err != nil {
return err
}
t := &auth_model.AccessToken{
Name: c.String("token-name"),
UID: user.ID,
Scope: accessTokenScope,
}
if err := auth_model.NewAccessToken(t); err != nil {
return err
}
if c.Bool("raw") {
fmt.Printf("%s\n", t.Token)
} else {
fmt.Printf("Access token was successfully created: %s\n", t.Token)
}
return nil
}

60
cmd/admin_user_list.go Normal file
View File

@ -0,0 +1,60 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"os"
"text/tabwriter"
user_model "code.gitea.io/gitea/models/user"
"github.com/urfave/cli"
)
var microcmdUserList = cli.Command{
Name: "list",
Usage: "List users",
Action: runListUsers,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "admin",
Usage: "List only admin users",
},
},
}
func runListUsers(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
users, err := user_model.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 {
twofa := user_model.UserList(users).GetTwoFaStatus()
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n")
for _, u := range users {
fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\t%t\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin, twofa[u.ID])
}
}
w.Flush()
return nil
}

View File

@ -0,0 +1,58 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"errors"
"fmt"
user_model "code.gitea.io/gitea/models/user"
"github.com/urfave/cli"
)
var microcmdUserMustChangePassword = cli.Command{
Name: "must-change-password",
Usage: "Set the must change password flag for the provided users or all users",
Action: runMustChangePassword,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "all,A",
Usage: "All users must change password, except those explicitly excluded with --exclude",
},
cli.StringSliceFlag{
Name: "exclude,e",
Usage: "Do not change the must-change-password flag for these users",
},
cli.BoolFlag{
Name: "unset",
Usage: "Instead of setting the must-change-password flag, unset it",
},
},
}
func runMustChangePassword(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
if c.NArg() == 0 && !c.IsSet("all") {
return errors.New("either usernames or --all must be provided")
}
mustChangePassword := !c.Bool("unset")
all := c.Bool("all")
exclude := c.StringSlice("exclude")
if err := initDB(ctx); err != nil {
return err
}
n, err := user_model.SetMustChangePassword(ctx, all, mustChangePassword, c.Args(), exclude)
if err != nil {
return err
}
fmt.Printf("Updated %d users setting MustChangePassword to %t\n", n, mustChangePassword)
return nil
}

View File

@ -1,8 +1,7 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 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.
// SPDX-License-Identifier: MIT
package cmd

View File

@ -1,6 +1,5 @@
// Copyright 2018 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.
// SPDX-License-Identifier: MIT
// Package cmd provides subcommands to the gitea binary - such as "web" or
// "admin".
@ -58,9 +57,10 @@ func confirm() (bool, error) {
}
func initDB(ctx context.Context) error {
setting.LoadFromExisting()
setting.InitDBConfig()
setting.NewXORMLogService(false)
setting.InitProviderFromExistingFile()
setting.LoadCommonSettings()
setting.LoadDBSetting()
setting.InitSQLLog(false)
if setting.Database.Type == "" {
log.Fatal(`Database settings are missing from the configuration file: %q.
@ -68,7 +68,7 @@ Ensure you are running in the correct environment or set the correct configurati
If this is the intended configuration file complete the [database] section.`, setting.CustomConf)
}
if err := db.InitEngine(ctx); err != nil {
return fmt.Errorf("unable to initialize the database using the configuration in %q. Error: %v", setting.CustomConf, err)
return fmt.Errorf("unable to initialize the database using the configuration in %q. Error: %w", setting.CustomConf, err)
}
return nil
}

View File

@ -1,6 +1,5 @@
// Copyright 2019 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.
// SPDX-License-Identifier: MIT
package cmd
@ -33,10 +32,10 @@ func runConvert(ctx *cli.Context) error {
log.Info("AppPath: %s", setting.AppPath)
log.Info("AppWorkPath: %s", setting.AppWorkPath)
log.Info("Custom path: %s", setting.CustomPath)
log.Info("Log path: %s", setting.LogRootPath)
log.Info("Log path: %s", setting.Log.RootPath)
log.Info("Configuration file: %s", setting.CustomConf)
if !setting.Database.UseMySQL {
if !setting.Database.Type.IsMySQL() {
fmt.Println("This command can only be used with a MySQL database")
return nil
}

View File

@ -1,6 +1,5 @@
// 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.
// SPDX-License-Identifier: MIT
package cmd

View File

@ -1,6 +1,5 @@
// Copyright 2019 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.
// SPDX-License-Identifier: MIT
package cmd
@ -14,6 +13,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/migrations"
migrate_base "code.gitea.io/gitea/models/migrations/base"
"code.gitea.io/gitea/modules/doctor"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@ -87,14 +87,16 @@ func runRecreateTable(ctx *cli.Context) error {
golog.SetPrefix("")
golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT)))
setting.LoadFromExisting()
setting.InitDBConfig()
setting.InitProviderFromExistingFile()
setting.LoadCommonSettings()
setting.LoadDBSetting()
setting.EnableXORMLog = ctx.Bool("debug")
setting.Log.EnableXORMLog = ctx.Bool("debug")
setting.Database.LogSQL = ctx.Bool("debug")
setting.Cfg.Section("log").Key("XORM").SetValue(",")
// FIXME: don't use CfgProvider directly
setting.CfgProvider.Section("log").Key("XORM").SetValue(",")
setting.NewXORMLogService(!ctx.Bool("debug"))
setting.InitSQLLog(!ctx.Bool("debug"))
stdCtx, cancel := installSignals()
defer cancel()
@ -114,7 +116,7 @@ func runRecreateTable(ctx *cli.Context) error {
if err != nil {
return err
}
recreateTables := migrations.RecreateTables(beans...)
recreateTables := migrate_base.RecreateTables(beans...)
return db.InitEngineWithMigration(stdCtx, func(x *xorm.Engine) error {
if err := migrations.EnsureUpToDate(x); err != nil {

View File

@ -1,7 +1,6 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 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.
// SPDX-License-Identifier: MIT
package cmd
@ -146,6 +145,10 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
Name: "skip-package-data",
Usage: "Skip package data",
},
cli.BoolFlag{
Name: "skip-index",
Usage: "Skip bleve index data",
},
cli.GenericFlag{
Name: "type",
Value: outputTypeEnum,
@ -178,20 +181,22 @@ func runDump(ctx *cli.Context) error {
}
fileName += "." + outType
}
setting.LoadFromExisting()
setting.InitProviderFromExistingFile()
setting.LoadCommonSettings()
// make sure we are logging to the console no matter what the configuration tells us do to
if _, err := setting.Cfg.Section("log").NewKey("MODE", "console"); err != nil {
// FIXME: don't use CfgProvider directly
if _, err := setting.CfgProvider.Section("log").NewKey("MODE", "console"); err != nil {
fatal("Setting logging mode to console failed: %v", err)
}
if _, err := setting.Cfg.Section("log.console").NewKey("STDERR", "true"); err != nil {
if _, err := setting.CfgProvider.Section("log.console").NewKey("STDERR", "true"); err != nil {
fatal("Setting console logger to stderr failed: %v", err)
}
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
setting.LoadSettings() // cannot access session settings otherwise
stdCtx, cancel := installSignals()
defer cancel()
@ -245,7 +250,9 @@ func runDump(ctx *cli.Context) error {
if ctx.IsSet("skip-lfs-data") && ctx.Bool("skip-lfs-data") {
log.Info("Skip dumping LFS data")
} else if err := storage.LFS.IterateObjects(func(objPath string, object storage.Object) error {
} else if !setting.LFS.StartServer {
log.Info("LFS isn't enabled. Skip dumping LFS data")
} else if err := storage.LFS.IterateObjects("", func(objPath string, object storage.Object) error {
info, err := object.Stat()
if err != nil {
return err
@ -267,13 +274,14 @@ func runDump(ctx *cli.Context) error {
fatal("Failed to create tmp file: %v", err)
}
defer func() {
_ = dbDump.Close()
if err := util.Remove(dbDump.Name()); err != nil {
log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err)
}
}()
targetDBType := ctx.String("database")
if len(targetDBType) > 0 && targetDBType != setting.Database.Type {
if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() {
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
} else {
log.Info("Dumping database...")
@ -319,7 +327,7 @@ func runDump(ctx *cli.Context) error {
log.Info("Packing data directory...%s", setting.AppDataPath)
var excludes []string
if setting.Cfg.Section("session").Key("PROVIDER").Value() == "file" {
if setting.SessionConfig.OriginalProvider == "file" {
var opts session.Options
if err = json.Unmarshal([]byte(setting.SessionConfig.ProviderConfig), &opts); err != nil {
return err
@ -327,11 +335,16 @@ func runDump(ctx *cli.Context) error {
excludes = append(excludes, opts.ProviderConfig)
}
if ctx.IsSet("skip-index") && ctx.Bool("skip-index") {
excludes = append(excludes, setting.Indexer.RepoPath)
excludes = append(excludes, setting.Indexer.IssuePath)
}
excludes = append(excludes, setting.RepoRootPath)
excludes = append(excludes, setting.LFS.Path)
excludes = append(excludes, setting.Attachment.Path)
excludes = append(excludes, setting.Packages.Path)
excludes = append(excludes, setting.LogRootPath)
excludes = append(excludes, setting.Log.RootPath)
excludes = append(excludes, absFileName)
if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil {
fatal("Failed to include data directory: %v", err)
@ -340,7 +353,7 @@ func runDump(ctx *cli.Context) error {
if ctx.IsSet("skip-attachment-data") && ctx.Bool("skip-attachment-data") {
log.Info("Skip dumping attachment data")
} else if err := storage.Attachments.IterateObjects(func(objPath string, object storage.Object) error {
} else if err := storage.Attachments.IterateObjects("", func(objPath string, object storage.Object) error {
info, err := object.Stat()
if err != nil {
return err
@ -353,7 +366,9 @@ func runDump(ctx *cli.Context) error {
if ctx.IsSet("skip-package-data") && ctx.Bool("skip-package-data") {
log.Info("Skip dumping package data")
} else if err := storage.Packages.IterateObjects(func(objPath string, object storage.Object) error {
} else if !setting.Packages.Enabled {
log.Info("Packages isn't enabled. Skip dumping package data")
} else if err := storage.Packages.IterateObjects("", func(objPath string, object storage.Object) error {
info, err := object.Stat()
if err != nil {
return err
@ -370,12 +385,12 @@ func runDump(ctx *cli.Context) error {
if ctx.IsSet("skip-log") && ctx.Bool("skip-log") {
log.Info("Skip dumping log files")
} else {
isExist, err := util.IsExist(setting.LogRootPath)
isExist, err := util.IsExist(setting.Log.RootPath)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", setting.LogRootPath, err)
log.Error("Unable to check if %s exists. Error: %v", setting.Log.RootPath, err)
}
if isExist {
if err := addRecursiveExclude(w, "log", setting.LogRootPath, []string{absFileName}, verbose); err != nil {
if err := addRecursiveExclude(w, "log", setting.Log.RootPath, []string{absFileName}, verbose); err != nil {
fatal("Failed to include log: %v", err)
}
}
@ -401,15 +416,6 @@ func runDump(ctx *cli.Context) error {
return nil
}
func contains(slice []string, s string) bool {
for _, v := range slice {
if v == s {
return true
}
}
return false
}
// addRecursiveExclude zips absPath to specified insidePath inside writer excluding excludeAbsPath
func addRecursiveExclude(w archiver.Writer, insidePath, absPath string, excludeAbsPath []string, verbose bool) error {
absPath, err := filepath.Abs(absPath)
@ -430,7 +436,7 @@ func addRecursiveExclude(w archiver.Writer, insidePath, absPath string, excludeA
currentAbsPath := path.Join(absPath, file.Name())
currentInsidePath := path.Join(insidePath, file.Name())
if file.IsDir() {
if !contains(excludeAbsPath, currentAbsPath) {
if !util.SliceContainsString(excludeAbsPath, currentAbsPath) {
if err := addFile(w, currentInsidePath, currentAbsPath, false); err != nil {
return err
}

View File

@ -1,6 +1,5 @@
// 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.
// SPDX-License-Identifier: MIT
package cmd
@ -11,13 +10,13 @@ import (
"os"
"strings"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
base "code.gitea.io/gitea/modules/migration"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/convert"
"code.gitea.io/gitea/services/migrations"
"github.com/urfave/cli"
@ -95,7 +94,7 @@ func runDumpRepository(ctx *cli.Context) error {
log.Info("AppPath: %s", setting.AppPath)
log.Info("AppWorkPath: %s", setting.AppWorkPath)
log.Info("Custom path: %s", setting.CustomPath)
log.Info("Log path: %s", setting.LogRootPath)
log.Info("Log path: %s", setting.Log.RootPath)
log.Info("Configuration file: %s", setting.CustomConf)
var (
@ -166,7 +165,7 @@ func runDumpRepository(ctx *cli.Context) error {
// make sure the directory doesn't exist or is empty, prevent from deleting user files
repoDir := ctx.String("repo_dir")
if exists, err := util.IsExist(repoDir); err != nil {
return fmt.Errorf("unable to stat repo_dir %q: %v", repoDir, err)
return fmt.Errorf("unable to stat repo_dir %q: %w", repoDir, err)
} else if exists {
if isDir, _ := util.IsDir(repoDir); !isDir {
return fmt.Errorf("repo_dir %q already exists but it's not a directory", repoDir)

View File

@ -1,6 +1,5 @@
// 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.
// SPDX-License-Identifier: MIT
//go:build bindata
@ -113,7 +112,8 @@ func initEmbeddedExtractor(c *cli.Context) error {
log.DelNamedLogger(log.DEFAULT)
// Read configuration file
setting.LoadAllowEmpty()
setting.InitProviderAllowEmpty()
setting.LoadCommonSettings()
pats, err := getPatterns(c.Args())
if err != nil {
@ -123,7 +123,7 @@ func initEmbeddedExtractor(c *cli.Context) error {
sections["public"] = &section{Path: "public", Names: public.AssetNames, IsDir: public.AssetIsDir, Asset: public.Asset}
sections["options"] = &section{Path: "options", Names: options.AssetNames, IsDir: options.AssetIsDir, Asset: options.Asset}
sections["templates"] = &section{Path: "templates", Names: templates.AssetNames, IsDir: templates.AssetIsDir, Asset: templates.Asset}
sections["templates"] = &section{Path: "templates", Names: templates.BuiltinAssetNames, IsDir: templates.BuiltinAssetIsDir, Asset: templates.BuiltinAsset}
for _, sec := range sections {
assets = append(assets, buildAssetList(sec, pats, c)...)
@ -186,11 +186,11 @@ func runViewDo(c *cli.Context) error {
data, err := assets[0].Section.Asset(assets[0].Name)
if err != nil {
return fmt.Errorf("%s: %v", assets[0].Path, err)
return fmt.Errorf("%s: %w", assets[0].Path, err)
}
if _, err = os.Stdout.Write(data); err != nil {
return fmt.Errorf("%s: %v", assets[0].Path, err)
return fmt.Errorf("%s: %w", assets[0].Path, err)
}
return nil
@ -251,11 +251,11 @@ func extractAsset(d string, a asset, overwrite, rename bool) error {
data, err := a.Section.Asset(a.Name)
if err != nil {
return fmt.Errorf("%s: %v", a.Path, err)
return fmt.Errorf("%s: %w", a.Path, err)
}
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return fmt.Errorf("%s: %v", dir, err)
return fmt.Errorf("%s: %w", dir, err)
}
perms := os.ModePerm & 0o666
@ -263,7 +263,7 @@ func extractAsset(d string, a asset, overwrite, rename bool) error {
fi, err := os.Lstat(dest)
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("%s: %v", dest, err)
return fmt.Errorf("%s: %w", dest, err)
}
} else if !overwrite && !rename {
fmt.Printf("%s already exists; skipped.\n", dest)
@ -272,7 +272,7 @@ func extractAsset(d string, a asset, overwrite, rename bool) error {
return fmt.Errorf("%s already exists, but it's not a regular file", dest)
} else if rename {
if err := util.Rename(dest, dest+".bak"); err != nil {
return fmt.Errorf("Error creating backup for %s: %v", dest, err)
return fmt.Errorf("Error creating backup for %s: %w", dest, err)
}
// Attempt to respect file permissions mask (even if user:group will be set anew)
perms = fi.Mode()
@ -280,12 +280,12 @@ func extractAsset(d string, a asset, overwrite, rename bool) error {
file, err := os.OpenFile(dest, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, perms)
if err != nil {
return fmt.Errorf("%s: %v", dest, err)
return fmt.Errorf("%s: %w", dest, err)
}
defer file.Close()
if _, err = file.Write(data); err != nil {
return fmt.Errorf("%s: %v", dest, err)
return fmt.Errorf("%s: %w", dest, err)
}
fmt.Println(dest)
@ -325,7 +325,7 @@ func getPatterns(args []string) ([]glob.Glob, error) {
pat := make([]glob.Glob, len(args))
for i := range args {
if g, err := glob.Compile(args[i], '/'); err != nil {
return nil, fmt.Errorf("'%s': Invalid glob pattern: %v", args[i], err)
return nil, fmt.Errorf("'%s': Invalid glob pattern: %w", args[i], err)
} else {
pat[i] = g
}

View File

@ -1,6 +1,5 @@
// 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.
// SPDX-License-Identifier: MIT
//go:build !bindata

View File

@ -1,7 +1,6 @@
// Copyright 2016 The Gogs Authors. All rights reserved.
// Copyright 2016 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.
// SPDX-License-Identifier: MIT
package cmd

View File

@ -1,15 +1,14 @@
// Copyright 2017 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.
// SPDX-License-Identifier: MIT
package cmd
import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"net/http"
"os"
"strconv"
"strings"
@ -168,11 +167,11 @@ func runHookPreReceive(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup("hooks/pre-receive.log", c.Bool("debug"))
setup(ctx, c.Bool("debug"))
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
return fail(`Rejecting changes as Gitea environment not set.
return fail(ctx, `Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
}
@ -186,6 +185,7 @@ Gitea or set your environment appropriately.`, "")
userID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64)
deployKeyID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvDeployKeyID), 10, 64)
actionPerm, _ := strconv.ParseInt(os.Getenv(repo_module.EnvActionPerm), 10, 64)
hookOptions := private.HookOptions{
UserID: userID,
@ -195,6 +195,7 @@ Gitea or set your environment appropriately.`, "")
GitPushOptions: pushOptions(),
PullRequestID: prID,
DeployKeyID: deployKeyID,
ActionPerm: int(actionPerm),
}
scanner := bufio.NewScanner(os.Stdin)
@ -218,9 +219,9 @@ Gitea or set your environment appropriately.`, "")
}
}
supportProcRecive := false
supportProcReceive := false
if git.CheckGitVersionAtLeast("2.29") == nil {
supportProcRecive = true
supportProcReceive = true
}
for scanner.Scan() {
@ -241,9 +242,9 @@ Gitea or set your environment appropriately.`, "")
lastline++
// If the ref is a branch or tag, check if it's protected
// if supportProcRecive all ref should be checked because
// if supportProcReceive all ref should be checked because
// permission check was delayed
if supportProcRecive || strings.HasPrefix(refFullName, git.BranchPrefix) || strings.HasPrefix(refFullName, git.TagPrefix) {
if supportProcReceive || strings.HasPrefix(refFullName, git.BranchPrefix) || strings.HasPrefix(refFullName, git.TagPrefix) {
oldCommitIDs[count] = oldCommitID
newCommitIDs[count] = newCommitID
refFullNames[count] = refFullName
@ -256,14 +257,9 @@ Gitea or set your environment appropriately.`, "")
hookOptions.OldCommitIDs = oldCommitIDs
hookOptions.NewCommitIDs = newCommitIDs
hookOptions.RefFullNames = refFullNames
statusCode, msg := private.HookPreReceive(ctx, username, reponame, hookOptions)
switch statusCode {
case http.StatusOK:
// no-op
case http.StatusInternalServerError:
return fail("Internal Server Error", msg)
default:
return fail(msg, "")
extra := private.HookPreReceive(ctx, username, reponame, hookOptions)
if extra.HasError() {
return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error)
}
count = 0
lastline = 0
@ -284,12 +280,9 @@ Gitea or set your environment appropriately.`, "")
fmt.Fprintf(out, " Checking %d references\n", count)
statusCode, msg := private.HookPreReceive(ctx, username, reponame, hookOptions)
switch statusCode {
case http.StatusInternalServerError:
return fail("Internal Server Error", msg)
case http.StatusForbidden:
return fail(msg, "")
extra := private.HookPreReceive(ctx, username, reponame, hookOptions)
if extra.HasError() {
return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error)
}
} else if lastline > 0 {
fmt.Fprintf(out, "\n")
@ -308,11 +301,11 @@ func runHookPostReceive(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup("hooks/post-receive.log", c.Bool("debug"))
setup(ctx, c.Bool("debug"))
// First of all run update-server-info no matter what
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
return fmt.Errorf("Failed to call 'git update-server-info': %v", err)
return fmt.Errorf("Failed to call 'git update-server-info': %w", err)
}
// Now if we're an internal don't do anything else
@ -322,7 +315,7 @@ func runHookPostReceive(c *cli.Context) error {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
return fail(`Rejecting changes as Gitea environment not set.
return fail(ctx, `Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
}
@ -393,11 +386,11 @@ Gitea or set your environment appropriately.`, "")
hookOptions.OldCommitIDs = oldCommitIDs
hookOptions.NewCommitIDs = newCommitIDs
hookOptions.RefFullNames = refFullNames
resp, err := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
if resp == nil {
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
if extra.HasError() {
_ = dWriter.Close()
hookPrintResults(results)
return fail("Internal Server Error", err)
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
}
wasEmpty = wasEmpty || resp.RepoWasEmpty
results = append(results, resp.Results...)
@ -408,9 +401,9 @@ Gitea or set your environment appropriately.`, "")
if count == 0 {
if wasEmpty && masterPushed {
// We need to tell the repo to reset the default branch to master
err := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
if err != nil {
return fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
if extra.HasError() {
return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
}
}
fmt.Fprintf(out, "Processed %d references in total\n", total)
@ -426,11 +419,11 @@ Gitea or set your environment appropriately.`, "")
fmt.Fprintf(out, " Processing %d references\n", count)
resp, err := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
if resp == nil {
_ = dWriter.Close()
hookPrintResults(results)
return fail("Internal Server Error", err)
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
}
wasEmpty = wasEmpty || resp.RepoWasEmpty
results = append(results, resp.Results...)
@ -439,9 +432,9 @@ Gitea or set your environment appropriately.`, "")
if wasEmpty && masterPushed {
// We need to tell the repo to reset the default branch to master
err := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
if err != nil {
return fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
if extra.HasError() {
return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
}
}
_ = dWriter.Close()
@ -484,22 +477,22 @@ func pushOptions() map[string]string {
}
func runHookProcReceive(c *cli.Context) error {
setup("hooks/proc-receive.log", c.Bool("debug"))
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
return fail(`Rejecting changes as Gitea environment not set.
return fail(ctx, `Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
}
return nil
}
ctx, cancel := installSignals()
defer cancel()
if git.CheckGitVersionAtLeast("2.29") != nil {
return fail("Internal Server Error", "git not support proc-receive.")
return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.")
}
reader := bufio.NewReader(os.Stdin)
@ -514,7 +507,7 @@ Gitea or set your environment appropriately.`, "")
// H: PKT-LINE(version=1\0push-options...)
// H: flush-pkt
rs, err := readPktLine(reader, pktLineTypeData)
rs, err := readPktLine(ctx, reader, pktLineTypeData)
if err != nil {
return err
}
@ -529,19 +522,19 @@ Gitea or set your environment appropriately.`, "")
index := bytes.IndexByte(rs.Data, byte(0))
if index >= len(rs.Data) {
return fail("Internal Server Error", "pkt-line: format error "+fmt.Sprint(rs.Data))
return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
}
if index < 0 {
if len(rs.Data) == 10 && rs.Data[9] == '\n' {
index = 9
} else {
return fail("Internal Server Error", "pkt-line: format error "+fmt.Sprint(rs.Data))
return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
}
}
if string(rs.Data[0:index]) != VersionHead {
return fail("Internal Server Error", "Received unsupported version: %s", string(rs.Data[0:index]))
return fail(ctx, "Protocol: version error", "Received unsupported version: %s", string(rs.Data[0:index]))
}
requestOptions = strings.Split(string(rs.Data[index+1:]), " ")
@ -554,17 +547,17 @@ Gitea or set your environment appropriately.`, "")
}
response = append(response, '\n')
_, err = readPktLine(reader, pktLineTypeFlush)
_, err = readPktLine(ctx, reader, pktLineTypeFlush)
if err != nil {
return err
}
err = writeDataPktLine(os.Stdout, response)
err = writeDataPktLine(ctx, os.Stdout, response)
if err != nil {
return err
}
err = writeFlushPktLine(os.Stdout)
err = writeFlushPktLine(ctx, os.Stdout)
if err != nil {
return err
}
@ -587,7 +580,7 @@ Gitea or set your environment appropriately.`, "")
for {
// note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed
rs, err = readPktLine(reader, pktLineTypeUnknow)
rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
if err != nil {
return err
}
@ -608,7 +601,7 @@ Gitea or set your environment appropriately.`, "")
if hasPushOptions {
for {
rs, err = readPktLine(reader, pktLineTypeUnknow)
rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
if err != nil {
return err
}
@ -625,9 +618,9 @@ Gitea or set your environment appropriately.`, "")
}
// 3. run hook
resp, err := private.HookProcReceive(ctx, repoUser, repoName, hookOptions)
if err != nil {
return fail("Internal Server Error", "run proc-receive hook failed :%v", err)
resp, extra := private.HookProcReceive(ctx, repoUser, repoName, hookOptions)
if extra.HasError() {
return fail(ctx, extra.UserMsg, "HookProcReceive failed: %v", extra.Error)
}
// 4. response result to service
@ -648,7 +641,7 @@ Gitea or set your environment appropriately.`, "")
for _, rs := range resp.Results {
if len(rs.Err) > 0 {
err = writeDataPktLine(os.Stdout, []byte("ng "+rs.OriginalRef+" "+rs.Err))
err = writeDataPktLine(ctx, os.Stdout, []byte("ng "+rs.OriginalRef+" "+rs.Err))
if err != nil {
return err
}
@ -656,43 +649,43 @@ Gitea or set your environment appropriately.`, "")
}
if rs.IsNotMatched {
err = writeDataPktLine(os.Stdout, []byte("ok "+rs.OriginalRef))
err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef))
if err != nil {
return err
}
err = writeDataPktLine(os.Stdout, []byte("option fall-through"))
err = writeDataPktLine(ctx, os.Stdout, []byte("option fall-through"))
if err != nil {
return err
}
continue
}
err = writeDataPktLine(os.Stdout, []byte("ok "+rs.OriginalRef))
err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef))
if err != nil {
return err
}
err = writeDataPktLine(os.Stdout, []byte("option refname "+rs.Ref))
err = writeDataPktLine(ctx, os.Stdout, []byte("option refname "+rs.Ref))
if err != nil {
return err
}
if rs.OldOID != git.EmptySHA {
err = writeDataPktLine(os.Stdout, []byte("option old-oid "+rs.OldOID))
err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID))
if err != nil {
return err
}
}
err = writeDataPktLine(os.Stdout, []byte("option new-oid "+rs.NewOID))
err = writeDataPktLine(ctx, os.Stdout, []byte("option new-oid "+rs.NewOID))
if err != nil {
return err
}
if rs.IsForcePush {
err = writeDataPktLine(os.Stdout, []byte("option forced-update"))
err = writeDataPktLine(ctx, os.Stdout, []byte("option forced-update"))
if err != nil {
return err
}
}
}
err = writeFlushPktLine(os.Stdout)
err = writeFlushPktLine(ctx, os.Stdout)
return err
}
@ -717,7 +710,7 @@ type gitPktLine struct {
Data []byte
}
func readPktLine(in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
var (
err error
r *gitPktLine
@ -728,33 +721,33 @@ func readPktLine(in *bufio.Reader, requestType pktLineType) (*gitPktLine, error)
for i := 0; i < 4; i++ {
lengthBytes[i], err = in.ReadByte()
if err != nil {
return nil, fail("Internal Server Error", "Pkt-Line: read stdin failed : %v", err)
return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err)
}
}
r = new(gitPktLine)
r.Length, err = strconv.ParseUint(string(lengthBytes), 16, 32)
if err != nil {
return nil, fail("Internal Server Error", "Pkt-Line format is wrong :%v", err)
return nil, fail(ctx, "Protocol: format parse error", "Pkt-Line format is wrong :%v", err)
}
if r.Length == 0 {
if requestType == pktLineTypeData {
return nil, fail("Internal Server Error", "Pkt-Line format is wrong")
return nil, fail(ctx, "Protocol: format data error", "Pkt-Line format is wrong")
}
r.Type = pktLineTypeFlush
return r, nil
}
if r.Length <= 4 || r.Length > 65520 || requestType == pktLineTypeFlush {
return nil, fail("Internal Server Error", "Pkt-Line format is wrong")
return nil, fail(ctx, "Protocol: format length error", "Pkt-Line format is wrong")
}
r.Data = make([]byte, r.Length-4)
for i := range r.Data {
r.Data[i], err = in.ReadByte()
if err != nil {
return nil, fail("Internal Server Error", "Pkt-Line: read stdin failed : %v", err)
return nil, fail(ctx, "Protocol: data error", "Pkt-Line: read stdin failed : %v", err)
}
}
@ -763,19 +756,15 @@ func readPktLine(in *bufio.Reader, requestType pktLineType) (*gitPktLine, error)
return r, nil
}
func writeFlushPktLine(out io.Writer) error {
func writeFlushPktLine(ctx context.Context, out io.Writer) error {
l, err := out.Write([]byte("0000"))
if err != nil {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
if err != nil || l != 4 {
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
}
if l != 4 {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
}
return nil
}
func writeDataPktLine(out io.Writer, data []byte) error {
func writeDataPktLine(ctx context.Context, out io.Writer, data []byte) error {
hexchar := []byte("0123456789abcdef")
hex := func(n uint64) byte {
return hexchar[(n)&15]
@ -789,19 +778,13 @@ func writeDataPktLine(out io.Writer, data []byte) error {
tmp[3] = hex(length)
lr, err := out.Write(tmp)
if err != nil {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
}
if lr != 4 {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
if err != nil || lr != 4 {
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
}
lr, err = out.Write(data)
if err != nil {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
}
if int(length-4) != lr {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
if err != nil || int(length-4) != lr {
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
}
return nil

View File

@ -1,12 +1,12 @@
// Copyright 2021 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.
// SPDX-License-Identifier: MIT
package cmd
import (
"bufio"
"bytes"
"context"
"strings"
"testing"
@ -15,27 +15,28 @@ import (
func TestPktLine(t *testing.T) {
// test read
ctx := context.Background()
s := strings.NewReader("0000")
r := bufio.NewReader(s)
result, err := readPktLine(r, pktLineTypeFlush)
result, err := readPktLine(ctx, r, pktLineTypeFlush)
assert.NoError(t, err)
assert.Equal(t, pktLineTypeFlush, result.Type)
s = strings.NewReader("0006a\n")
r = bufio.NewReader(s)
result, err = readPktLine(r, pktLineTypeData)
result, err = readPktLine(ctx, r, pktLineTypeData)
assert.NoError(t, err)
assert.Equal(t, pktLineTypeData, result.Type)
assert.Equal(t, []byte("a\n"), result.Data)
// test write
w := bytes.NewBuffer([]byte{})
err = writeFlushPktLine(w)
err = writeFlushPktLine(ctx, w)
assert.NoError(t, err)
assert.Equal(t, []byte("0000"), w.Bytes())
w.Reset()
err = writeDataPktLine(w, []byte("a\nb"))
err = writeDataPktLine(ctx, w, []byte("a\nb"))
assert.NoError(t, err)
assert.Equal(t, []byte("0007a\nb"), w.Bytes())
}

View File

@ -1,6 +1,5 @@
// Copyright 2018 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.
// SPDX-License-Identifier: MIT
package cmd
@ -65,11 +64,12 @@ func runKeys(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup("keys.log", false)
setup(ctx, false)
authorizedString, err := private.AuthorizedPublicKeyByContent(ctx, content)
if err != nil {
return err
authorizedString, extra := private.AuthorizedPublicKeyByContent(ctx, content)
// do not use handleCliResponseExtra or cli.NewExitError, if it exists immediately, it breaks some tests like Test_CmdKeys
if extra.Error != nil {
return extra.Error
}
fmt.Println(strings.TrimSpace(authorizedString))
return nil

View File

@ -1,12 +1,10 @@
// 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.
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"net/http"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
@ -18,7 +16,8 @@ func runSendMail(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setting.LoadFromExisting()
setting.InitProviderFromExistingFile()
setting.LoadCommonSettings()
if err := argsSet(c, "title"); err != nil {
return err
@ -43,13 +42,10 @@ func runSendMail(c *cli.Context) error {
}
}
status, message := private.SendEmail(ctx, subject, body, nil)
if status != http.StatusOK {
fmt.Printf("error: %s\n", message)
return nil
respText, extra := private.SendEmail(ctx, subject, body, nil)
if extra.HasError() {
return handleCliResponseExtra(extra)
}
fmt.Printf("Success: %s\n", message)
_, _ = fmt.Printf("Sent %s email(s) to all users\n", respText)
return nil
}

View File

@ -1,6 +1,5 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT
package cmd
@ -13,7 +12,7 @@ import (
func init() {
setting.SetCustomPathAndConf("", "", "")
setting.LoadForTest()
setting.InitProviderAndLoadCommonSettingsForTest()
}
func TestMain(m *testing.M) {

View File

@ -1,12 +1,9 @@
// 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.
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"net/http"
"os"
"time"
@ -104,57 +101,34 @@ func runShutdown(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup("manager", c.Bool("debug"))
statusCode, msg := private.Shutdown(ctx)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
setup(ctx, c.Bool("debug"))
extra := private.Shutdown(ctx)
return handleCliResponseExtra(extra)
}
func runRestart(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup("manager", c.Bool("debug"))
statusCode, msg := private.Restart(ctx)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
setup(ctx, c.Bool("debug"))
extra := private.Restart(ctx)
return handleCliResponseExtra(extra)
}
func runFlushQueues(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup("manager", c.Bool("debug"))
statusCode, msg := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking"))
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
setup(ctx, c.Bool("debug"))
extra := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking"))
return handleCliResponseExtra(extra)
}
func runProcesses(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup("manager", c.Bool("debug"))
statusCode, msg := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel"))
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
return nil
setup(ctx, c.Bool("debug"))
extra := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel"))
return handleCliResponseExtra(extra)
}

View File

@ -1,12 +1,10 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"net/http"
"os"
"code.gitea.io/gitea/modules/log"
@ -192,27 +190,25 @@ var (
)
func runRemoveLogger(c *cli.Context) error {
setup("manager", c.Bool("debug"))
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
group := c.String("group")
if len(group) == 0 {
group = log.DEFAULT
}
name := c.Args().First()
ctx, cancel := installSignals()
defer cancel()
statusCode, msg := private.RemoveLogger(ctx, group, name)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
extra := private.RemoveLogger(ctx, group, name)
return handleCliResponseExtra(extra)
}
func runAddSMTPLogger(c *cli.Context) error {
setup("manager", c.Bool("debug"))
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
vals := map[string]interface{}{}
mode := "smtp"
if c.IsSet("host") {
@ -243,7 +239,10 @@ func runAddSMTPLogger(c *cli.Context) error {
}
func runAddConnLogger(c *cli.Context) error {
setup("manager", c.Bool("debug"))
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
vals := map[string]interface{}{}
mode := "conn"
vals["net"] = "tcp"
@ -270,7 +269,10 @@ func runAddConnLogger(c *cli.Context) error {
}
func runAddFileLogger(c *cli.Context) error {
setup("manager", c.Bool("debug"))
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
vals := map[string]interface{}{}
mode := "file"
if c.IsSet("filename") {
@ -300,7 +302,10 @@ func runAddFileLogger(c *cli.Context) error {
}
func runAddConsoleLogger(c *cli.Context) error {
setup("manager", c.Bool("debug"))
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
vals := map[string]interface{}{}
mode := "console"
if c.IsSet("stderr") && c.Bool("stderr") {
@ -339,28 +344,17 @@ func commonAddLogger(c *cli.Context, mode string, vals map[string]interface{}) e
ctx, cancel := installSignals()
defer cancel()
statusCode, msg := private.AddLogger(ctx, group, name, mode, vals)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
extra := private.AddLogger(ctx, group, name, mode, vals)
return handleCliResponseExtra(extra)
}
func runPauseLogging(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup("manager", c.Bool("debug"))
statusCode, msg := private.PauseLogging(ctx)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
setup(ctx, c.Bool("debug"))
userMsg := private.PauseLogging(ctx)
_, _ = fmt.Fprintln(os.Stdout, userMsg)
return nil
}
@ -368,14 +362,9 @@ func runResumeLogging(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup("manager", c.Bool("debug"))
statusCode, msg := private.ResumeLogging(ctx)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
setup(ctx, c.Bool("debug"))
userMsg := private.ResumeLogging(ctx)
_, _ = fmt.Fprintln(os.Stdout, userMsg)
return nil
}
@ -383,28 +372,17 @@ func runReleaseReopenLogging(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup("manager", c.Bool("debug"))
statusCode, msg := private.ReleaseReopenLogging(ctx)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
setup(ctx, c.Bool("debug"))
userMsg := private.ReleaseReopenLogging(ctx)
_, _ = fmt.Fprintln(os.Stdout, userMsg)
return nil
}
func runSetLogSQL(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup("manager", c.Bool("debug"))
setup(ctx, c.Bool("debug"))
statusCode, msg := private.SetLogSQL(ctx, !c.Bool("off"))
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
extra := private.SetLogSQL(ctx, !c.Bool("off"))
return handleCliResponseExtra(extra)
}

View File

@ -1,6 +1,5 @@
// Copyright 2018 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.
// SPDX-License-Identifier: MIT
package cmd
@ -34,7 +33,7 @@ func runMigrate(ctx *cli.Context) error {
log.Info("AppPath: %s", setting.AppPath)
log.Info("AppWorkPath: %s", setting.AppWorkPath)
log.Info("Custom path: %s", setting.CustomPath)
log.Info("Log path: %s", setting.LogRootPath)
log.Info("Log path: %s", setting.Log.RootPath)
log.Info("Configuration file: %s", setting.CustomConf)
if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {

View File

@ -1,6 +1,5 @@
// 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.
// SPDX-License-Identifier: MIT
package cmd
@ -73,56 +72,62 @@ var CmdMigrateStorage = cli.Command{
cli.StringFlag{
Name: "minio-base-path",
Value: "",
Usage: "Minio storage basepath on the bucket",
Usage: "Minio storage base path on the bucket",
},
cli.BoolFlag{
Name: "minio-use-ssl",
Usage: "Enable SSL for minio",
},
cli.BoolFlag{
Name: "minio-insecure-skip-verify",
Usage: "Skip SSL verification",
},
cli.StringFlag{
Name: "minio-checksum-algorithm",
Value: "",
Usage: "Minio checksum algorithm (default/md5)",
},
},
}
func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(attach *repo_model.Attachment) error {
return db.Iterate(ctx, nil, func(ctx context.Context, attach *repo_model.Attachment) error {
_, err := storage.Copy(dstStorage, attach.RelativePath(), storage.Attachments, attach.RelativePath())
return err
})
}
func migrateLFS(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(mo *git_model.LFSMetaObject) error {
return db.Iterate(ctx, nil, func(ctx context.Context, mo *git_model.LFSMetaObject) error {
_, err := storage.Copy(dstStorage, mo.RelativePath(), storage.LFS, mo.RelativePath())
return err
})
}
func migrateAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(user *user_model.User) error {
return db.Iterate(ctx, nil, func(ctx context.Context, user *user_model.User) error {
_, err := storage.Copy(dstStorage, user.CustomAvatarRelativePath(), storage.Avatars, user.CustomAvatarRelativePath())
return err
})
}
func migrateRepoAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(repo *repo_model.Repository) error {
return db.Iterate(ctx, nil, func(ctx context.Context, repo *repo_model.Repository) error {
_, err := storage.Copy(dstStorage, repo.CustomAvatarRelativePath(), storage.RepoAvatars, repo.CustomAvatarRelativePath())
return err
})
}
func migrateRepoArchivers(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(archiver *repo_model.RepoArchiver) error {
p, err := archiver.RelativePath()
if err != nil {
return err
}
_, err = storage.Copy(dstStorage, p, storage.RepoArchives, p)
return db.Iterate(ctx, nil, func(ctx context.Context, archiver *repo_model.RepoArchiver) error {
p := archiver.RelativePath()
_, err := storage.Copy(dstStorage, p, storage.RepoArchives, p)
return err
})
}
func migratePackages(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(pb *packages_model.PackageBlob) error {
return db.Iterate(ctx, nil, func(ctx context.Context, pb *packages_model.PackageBlob) error {
p := packages_module.KeyToRelativePath(packages_module.BlobHash256Key(pb.HashSHA256))
_, err := storage.Copy(dstStorage, p, storage.Packages, p)
return err
@ -140,7 +145,7 @@ func runMigrateStorage(ctx *cli.Context) error {
log.Info("AppPath: %s", setting.AppPath)
log.Info("AppWorkPath: %s", setting.AppWorkPath)
log.Info("Custom path: %s", setting.CustomPath)
log.Info("Log path: %s", setting.LogRootPath)
log.Info("Log path: %s", setting.Log.RootPath)
log.Info("Configuration file: %s", setting.CustomConf)
if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
@ -172,13 +177,15 @@ func runMigrateStorage(ctx *cli.Context) error {
dstStorage, err = storage.NewMinioStorage(
stdCtx,
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"),
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"),
InsecureSkipVerify: ctx.Bool("minio-insecure-skip-verify"),
ChecksumAlgorithm: ctx.String("minio-checksum-algorithm"),
})
default:
return fmt.Errorf("unsupported storage type: %s", ctx.String("storage"))

View File

@ -1,6 +1,5 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT
package cmd
@ -44,8 +43,9 @@ func TestMigratePackages(t *testing.T) {
PackageFileInfo: packages_service.PackageFileInfo{
Filename: "a.go",
},
Data: buf,
IsLead: true,
Creator: creator,
Data: buf,
IsLead: true,
})
assert.NoError(t, err)
assert.NotNil(t, v)
@ -53,8 +53,7 @@ func TestMigratePackages(t *testing.T) {
ctx := context.Background()
p, err := os.MkdirTemp(os.TempDir(), "migrated_packages")
assert.NoError(t, err)
p := t.TempDir()
dstStorage, err := storage.NewLocalStorage(
ctx,

View File

@ -1,15 +1,11 @@
// 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.
// SPDX-License-Identifier: MIT
package cmd
import (
"errors"
"net/http"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
@ -55,12 +51,13 @@ func runRestoreRepository(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setting.LoadFromExisting()
setting.InitProviderFromExistingFile()
setting.LoadCommonSettings()
var units []string
if s := c.String("units"); s != "" {
units = strings.Split(s, ",")
}
statusCode, errStr := private.RestoreRepo(
extra := private.RestoreRepo(
ctx,
c.String("repo_dir"),
c.String("owner_name"),
@ -68,10 +65,5 @@ func runRestoreRepository(c *cli.Context) error {
units,
c.Bool("validation"),
)
if statusCode == http.StatusOK {
return nil
}
log.Fatal("Failed to restore repository: %v", errStr)
return errors.New(errStr)
return handleCliResponseExtra(extra)
}

View File

@ -1,21 +1,21 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 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.
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"fmt"
"net/http"
"net/url"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"unicode"
asymkey_model "code.gitea.io/gitea/models/asymkey"
git_model "code.gitea.io/gitea/models/git"
@ -43,7 +43,7 @@ const (
var CmdServ = cli.Command{
Name: "serv",
Usage: "This command should only be called by SSH shell",
Description: `Serv provide access auth for repositories`,
Description: "Serv provides access auth for repositories",
Action: runServ,
Flags: []cli.Flag{
cli.BoolFlag{
@ -55,14 +55,15 @@ var CmdServ = cli.Command{
},
}
func setup(logPath string, debug bool) {
func setup(ctx context.Context, debug bool) {
_ = 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.LoadFromExisting()
setting.InitProviderFromExistingFile()
setting.LoadCommonSettings()
if debug {
setting.RunMode = "dev"
}
@ -71,15 +72,15 @@ func setup(logPath string, debug bool) {
// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
if _, err := os.Stat(setting.RepoRootPath); err != nil {
if os.IsNotExist(err) {
_ = fail("Incorrect configuration, no repository directory.", "Directory `[repository].ROOT` %q was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository].ROOT` an absolute value.", setting.RepoRootPath)
_ = fail(ctx, "Incorrect configuration, no repository directory.", "Directory `[repository].ROOT` %q was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository].ROOT` an absolute value.", setting.RepoRootPath)
} else {
_ = fail("Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err)
_ = fail(ctx, "Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err)
}
return
}
if err := git.InitSimple(context.Background()); err != nil {
_ = fail("Failed to init git", "Failed to init git, err: %v", err)
_ = fail(ctx, "Failed to init git", "Failed to init git, err: %v", err)
}
}
@ -93,32 +94,54 @@ var (
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
)
func fail(userMessage, logMessage string, args ...interface{}) error {
// fail prints message to stdout, it's mainly used for git serv and git hook commands.
// The output will be passed to git client and shown to user.
func fail(ctx context.Context, userMessage, logMsgFmt string, args ...interface{}) error {
if userMessage == "" {
userMessage = "Internal Server Error (no specific error)"
}
// There appears to be a chance to cause a zombie process and failure to read the Exit status
// if nothing is outputted on stdout.
_, _ = fmt.Fprintln(os.Stdout, "")
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", userMessage)
if len(logMessage) > 0 {
if logMsgFmt != "" {
logMsg := fmt.Sprintf(logMsgFmt, args...)
if !setting.IsProd {
_, _ = fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", logMsg)
}
}
ctx, cancel := installSignals()
defer cancel()
if len(logMessage) > 0 {
_ = private.SSHLog(ctx, true, fmt.Sprintf(logMessage+": ", args...))
if userMessage != "" {
if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) {
logMsg = userMessage + " " + logMsg
} else {
logMsg = userMessage + ". " + logMsg
}
}
_ = private.SSHLog(ctx, true, logMsg)
}
return cli.NewExitError("", 1)
}
// handleCliResponseExtra handles the extra response from the cli sub-commands
// If there is a user message it will be printed to stdout
// If the command failed it will return an error (the error will be printed by cli framework)
func handleCliResponseExtra(extra private.ResponseExtra) error {
if extra.UserMsg != "" {
_, _ = fmt.Fprintln(os.Stdout, extra.UserMsg)
}
if extra.HasError() {
return cli.NewExitError(extra.Error, 1)
}
return nil
}
func runServ(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
// FIXME: This needs to internationalised
setup("serv.log", c.Bool("debug"))
setup(ctx, c.Bool("debug"))
if setting.SSH.Disabled {
println("Gitea: SSH has been disabled")
@ -134,18 +157,18 @@ func runServ(c *cli.Context) error {
keys := strings.Split(c.Args()[0], "-")
if len(keys) != 2 || keys[0] != "key" {
return fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args()[0])
}
keyID, err := strconv.ParseInt(keys[1], 10, 64)
if err != nil {
return fail("Key ID format error", "Invalid key argument: %s", c.Args()[1])
return fail(ctx, "Key ID parsing error", "Invalid key argument: %s", c.Args()[1])
}
cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
if len(cmd) == 0 {
key, user, err := private.ServNoCommand(ctx, keyID)
if err != nil {
return fail("Internal error", "Failed to check provided key: %v", err)
return fail(ctx, "Key check failed", "Failed to check provided key: %v", err)
}
switch key.Type {
case asymkey_model.KeyTypeDeploy:
@ -163,7 +186,7 @@ func runServ(c *cli.Context) error {
words, err := shellquote.Split(cmd)
if err != nil {
return fail("Error parsing arguments", "Failed to parse arguments: %v", err)
return fail(ctx, "Error parsing arguments", "Failed to parse arguments: %v", err)
}
if len(words) < 2 {
@ -174,7 +197,7 @@ func runServ(c *cli.Context) error {
return nil
}
}
return fail("Too few arguments", "Too few arguments in cmd: %s", cmd)
return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
}
verb := words[0]
@ -186,7 +209,7 @@ func runServ(c *cli.Context) error {
var lfsVerb string
if verb == lfsAuthenticateVerb {
if !setting.LFS.StartServer {
return fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
}
if len(words) > 2 {
@ -199,37 +222,37 @@ func runServ(c *cli.Context) error {
rr := strings.SplitN(repoPath, "/", 2)
if len(rr) != 2 {
return fail("Invalid repository path", "Invalid repository path: %v", repoPath)
return fail(ctx, "Invalid repository path", "Invalid repository path: %v", repoPath)
}
username := strings.ToLower(rr[0])
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
if alphaDashDotPattern.MatchString(reponame) {
return fail("Invalid repo name", "Invalid repo name: %s", reponame)
return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame)
}
if c.Bool("enable-pprof") {
if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
return fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
return fail(ctx, "Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
}
stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
if err != nil {
return fail("Internal Server Error", "Unable to start CPU profile: %v", err)
return fail(ctx, "Unable to start CPU profiler", "Unable to start CPU profile: %v", err)
}
defer func() {
stopCPUProfiler()
err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
if err != nil {
_ = fail("Internal Server Error", "Unable to dump Mem Profile: %v", err)
_ = fail(ctx, "Unable to dump Mem profile", "Unable to dump Mem Profile: %v", err)
}
}()
}
requestedMode, has := allowedCommands[verb]
if !has {
return fail("Unknown git command", "Unknown git command %s", verb)
return fail(ctx, "Unknown git command", "Unknown git command %s", verb)
}
if verb == lfsAuthenticateVerb {
@ -238,20 +261,13 @@ func runServ(c *cli.Context) error {
} else if lfsVerb == "download" {
requestedMode = perm.AccessModeRead
} else {
return fail("Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
return fail(ctx, "Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
}
}
results, err := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
if err != nil {
if private.IsErrServCommand(err) {
errServCommand := err.(private.ErrServCommand)
if errServCommand.StatusCode != http.StatusInternalServerError {
return fail("Unauthorized", "%s", errServCommand.Error())
}
return fail("Internal Server Error", "%s", errServCommand.Error())
}
return fail("Internal Server Error", "%s", err.Error())
results, extra := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
if extra.HasError() {
return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error)
}
// LFS token authentication
@ -273,7 +289,7 @@ func runServ(c *cli.Context) error {
// Sign and get the complete encoded token as a string using the secret
tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
if err != nil {
return fail("Internal error", "Failed to sign JWT token: %v", err)
return fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
}
tokenAuthentication := &git_model.LFSTokenResponse{
@ -285,22 +301,26 @@ func runServ(c *cli.Context) error {
enc := json.NewEncoder(os.Stdout)
err = enc.Encode(tokenAuthentication)
if err != nil {
return fail("Internal error", "Failed to encode LFS json response: %v", err)
return fail(ctx, "Failed to encode LFS json response", "Failed to encode LFS json response: %v", err)
}
return nil
}
// Special handle for Windows.
if setting.IsWindows {
verb = strings.Replace(verb, "-", " ", 1)
}
var gitcmd *exec.Cmd
verbs := strings.Split(verb, " ")
if len(verbs) == 2 {
gitcmd = exec.CommandContext(ctx, verbs[0], verbs[1], repoPath)
} else {
gitcmd = exec.CommandContext(ctx, verb, repoPath)
gitBinPath := filepath.Dir(git.GitExecutable) // e.g. /usr/bin
gitBinVerb := filepath.Join(gitBinPath, verb) // e.g. /usr/bin/git-upload-pack
if _, err := os.Stat(gitBinVerb); err != nil {
// if the command "git-upload-pack" doesn't exist, try to split "git-upload-pack" to use the sub-command with git
// ps: Windows only has "git.exe" in the bin path, so Windows always uses this way
verbFields := strings.SplitN(verb, "-", 2)
if len(verbFields) == 2 {
// use git binary with the sub-command part: "C:\...\bin\git.exe", "upload-pack", ...
gitcmd = exec.CommandContext(ctx, git.GitExecutable, verbFields[1], repoPath)
}
}
if gitcmd == nil {
// by default, use the verb (it has been checked above by allowedCommands)
gitcmd = exec.CommandContext(ctx, gitBinVerb, repoPath)
}
process.SetSysProcAttribute(gitcmd)
@ -327,13 +347,13 @@ func runServ(c *cli.Context) error {
gitcmd.Env = append(gitcmd.Env, git.CommonCmdServEnvs()...)
if err = gitcmd.Run(); err != nil {
return fail("Internal error", "Failed to execute git command: %v", err)
return fail(ctx, "Failed to execute git command", "Failed to execute git command: %v", err)
}
// Update user key activity.
if results.KeyID > 0 {
if err = private.UpdatePublicKeyInRepo(ctx, results.KeyID, results.RepoID); err != nil {
return fail("Internal error", "UpdatePublicKeyInRepo: %v", err)
return fail(ctx, "Failed to update public key", "UpdatePublicKeyInRepo: %v", err)
}
}

View File

@ -1,6 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT
package cmd
@ -10,6 +9,8 @@ import (
"net"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
_ "net/http/pprof" // Used for debugging if enabled and a web server is running
@ -26,6 +27,9 @@ import (
ini "gopkg.in/ini.v1"
)
// PIDFile could be set from build tag
var PIDFile = "/run/gitea.pid"
// CmdWeb represents the available web sub-command.
var CmdWeb = cli.Command{
Name: "web",
@ -46,7 +50,7 @@ and it takes care of all the other things for you`,
},
cli.StringFlag{
Name: "pid, P",
Value: setting.PIDFile,
Value: PIDFile,
Usage: "Custom pid file path",
},
cli.BoolFlag{
@ -82,6 +86,22 @@ func runHTTPRedirector() {
}
}
func createPIDFile(pidPath string) {
currentPid := os.Getpid()
if err := os.MkdirAll(filepath.Dir(pidPath), os.ModePerm); err != nil {
log.Fatal("Failed to create PID folder: %v", err)
}
file, err := os.Create(pidPath)
if err != nil {
log.Fatal("Failed to create PID file: %v", err)
}
defer file.Close()
if _, err := file.WriteString(strconv.FormatInt(int64(currentPid), 10)); err != nil {
log.Fatal("Failed to write PID information: %v", err)
}
}
func runWeb(ctx *cli.Context) error {
if ctx.Bool("verbose") {
_ = log.DelLogger("console")
@ -108,8 +128,7 @@ func runWeb(ctx *cli.Context) error {
// Set pid file setting
if ctx.IsSet("pid") {
setting.PIDFile = ctx.String("pid")
setting.WritePIDFile = true
createPIDFile(ctx.String("pid"))
}
// Perform pre-initialization
@ -126,8 +145,10 @@ func runWeb(ctx *cli.Context) error {
return err
}
}
c := install.Routes()
installCtx, cancel := context.WithCancel(graceful.GetManager().HammerContext())
c := install.Routes(installCtx)
err := listen(c, false)
cancel()
if err != nil {
log.Critical("Unable to open listener for installer. Is Gitea already running?")
graceful.GetManager().DoGracefulShutdown()
@ -157,7 +178,8 @@ func runWeb(ctx *cli.Context) error {
log.Info("Global init")
// Perform global initialization
setting.LoadFromExisting()
setting.InitProviderFromExistingFile()
setting.LoadCommonSettings()
routers.GlobalInitInstalled(graceful.GetManager().HammerContext())
// We check that AppDataPath exists here (it should have been created during installation)
@ -175,7 +197,7 @@ func runWeb(ctx *cli.Context) error {
}
// Set up Chi routes
c := routers.NormalRoutes()
c := routers.NormalRoutes(graceful.GetManager().HammerContext())
err := listen(c, true)
<-graceful.GetManager().Done()
log.Info("PID: %d Gitea Web Finished", os.Getpid())
@ -201,7 +223,7 @@ func setPort(port string) error {
defaultLocalURL += ":" + setting.HTTPPort + "/"
// Save LOCAL_ROOT_URL if port changed
setting.CreateOrAppendToCustomConf(func(cfg *ini.File) {
setting.CreateOrAppendToCustomConf("server.LOCAL_ROOT_URL", func(cfg *ini.File) {
cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
})
}

View File

@ -1,6 +1,5 @@
// 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.
// SPDX-License-Identifier: MIT
package cmd

View File

@ -1,6 +1,5 @@
// Copyright 2016 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.
// SPDX-License-Identifier: MIT
package cmd

View File

@ -1,6 +1,5 @@
// Copyright 2021 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.
// SPDX-License-Identifier: MIT
package cmd

View File

@ -1,2 +0,0 @@
#!/bin/sh
su git -c "/home/git/gogs/scripts/gogs_supervisord.sh restart"

View File

@ -0,0 +1,17 @@
Bash and Zsh completion
=======================
From within the gitea root run:
```bash
source contrib/autocompletion/bash_autocomplete
```
or for zsh run:
```bash
source contrib/autocompletion/zsh_autocomplete
```
These scripts will check if gitea is on the path and if so add autocompletion for `gitea`. Or if not autocompletion will work for `./gitea`.
If gitea has been installed as a different program pass in the `PROG` environment variable to set the correct program name.

View File

@ -0,0 +1,30 @@
#! /bin/bash
# Heavily inspired by https://github.com/urfave/cli
_cli_bash_autocomplete() {
if [[ "${COMP_WORDS[0]}" != "source" ]]; then
local cur opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ "$cur" == "-"* ]]; then
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion )
else
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
fi
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
}
if [ -z "$PROG" ] && [ ! "$(command -v gitea &> /dev/null)" ] ; then
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete gitea
elif [ -z "$PROG" ]; then
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete ./gitea
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete "$PWD/gitea"
else
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete "$PROG"
unset PROG
fi

View File

@ -0,0 +1,30 @@
#compdef ${PROG:=gitea}
# Heavily inspired by https://github.com/urfave/cli
_cli_zsh_autocomplete() {
local -a opts
local cur
cur=${words[-1]}
if [[ "$cur" == "-"* ]]; then
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
else
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
fi
if [[ "${opts[1]}" != "" ]]; then
_describe 'values' opts
else
_files
fi
return
}
if [ -z $PROG ] ; then
compdef _cli_zsh_autocomplete gitea
else
compdef _cli_zsh_autocomplete $(basename $PROG)
fi

41
contrib/backport/README Normal file
View File

@ -0,0 +1,41 @@
`backport`
==========
`backport` is a command to help create backports of PRs. It backports a
provided PR from main on to a released version.
It will create a backport branch, cherry-pick the PR's merge commit, adjust
the commit message and then push this back up to your fork's remote.
The default version will read from `docs/config.yml`. You can override this
using the option `--version`.
The upstream branches will be fetched, using the remote `origin`. This can
be overrided using `--upstream`, and fetching can be avoided using
`--no-fetch`.
By default the branch created will be called `backport-$PR-$VERSION`. You
can override this using the option `--backport-branch`. This branch will
be created from `--release-branch` which is `release/$(VERSION)`
by default and will be pulled from `$(UPSTREAM)`.
The merge-commit as determined by the github API will be used as the SHA to
cherry-pick. You can override this using `--cherry-pick`.
The commit message will be amended to add the `Backport` header.
`--no-amend-message` can be set to stop this from happening.
If cherry-pick is successful the backported branch will be pushed up to your
fork using your remote. These will be determined using `git remote -v`. You
can set your fork name using `--fork-user` and your remote name using
`--remote`. You can avoid pushing using `--no-push`.
If the push is successful, `xdg-open` will be called to open a backport url.
You can stop this using `--no-xdg-open`.
Installation
============
```bash
go install contrib/backport/backport.go
```

View File

@ -0,0 +1,473 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/exec"
"os/signal"
"path"
"strconv"
"strings"
"syscall"
"github.com/google/go-github/v45/github"
"github.com/urfave/cli"
"gopkg.in/yaml.v3"
)
const defaultVersion = "v1.18" // to backport to
func main() {
app := cli.NewApp()
app.Name = "backport"
app.Usage = "Backport provided PR-number on to the current or previous released version"
app.Description = `Backport will look-up the PR in Gitea's git log and attempt to cherry-pick it on the current version`
app.ArgsUsage = "<PR-to-backport>"
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "version",
Usage: "Version branch to backport on to",
},
cli.StringFlag{
Name: "upstream",
Value: "origin",
Usage: "Upstream remote for the Gitea upstream",
},
cli.StringFlag{
Name: "release-branch",
Value: "",
Usage: "Release branch to backport on. Will default to release/<version>",
},
cli.StringFlag{
Name: "cherry-pick",
Usage: "SHA to cherry-pick as backport",
},
cli.StringFlag{
Name: "backport-branch",
Usage: "Backport branch to backport on to (default: backport-<pr>-<version>",
},
cli.StringFlag{
Name: "remote",
Value: "",
Usage: "Remote for your fork of the Gitea upstream",
},
cli.StringFlag{
Name: "fork-user",
Value: "",
Usage: "Forked user name on Github",
},
cli.BoolFlag{
Name: "no-fetch",
Usage: "Set this flag to prevent fetch of remote branches",
},
cli.BoolFlag{
Name: "no-amend-message",
Usage: "Set this flag to prevent automatic amendment of the commit message",
},
cli.BoolFlag{
Name: "no-push",
Usage: "Set this flag to prevent pushing the backport up to your fork",
},
cli.BoolFlag{
Name: "no-xdg-open",
Usage: "Set this flag to not use xdg-open to open the PR URL",
},
cli.BoolFlag{
Name: "continue",
Usage: "Set this flag to continue from a git cherry-pick that has broken",
},
}
cli.AppHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
USAGE:
{{.HelpName}} {{if .VisibleFlags}}[options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
{{if len .Authors}}
AUTHOR:
{{range .Authors}}{{ . }}{{end}}
{{end}}{{if .Commands}}
OPTIONS:
{{range .VisibleFlags}}{{.}}
{{end}}{{end}}
`
app.Action = runBackport
if err := app.Run(os.Args); err != nil {
fmt.Fprintf(os.Stderr, "Unable to backport: %v\n", err)
}
}
func runBackport(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
continuing := c.Bool("continue")
var pr string
version := c.String("version")
if version == "" && continuing {
// determine version from current branch name
var err error
pr, version, err = readCurrentBranch(ctx)
if err != nil {
return err
}
}
if version == "" {
version = readVersion()
}
if version == "" {
version = defaultVersion
}
upstream := c.String("upstream")
if upstream == "" {
upstream = "origin"
}
forkUser := c.String("fork-user")
remote := c.String("remote")
if remote == "" && !c.Bool("--no-push") {
var err error
remote, forkUser, err = determineRemote(ctx, forkUser)
if err != nil {
return err
}
}
upstreamReleaseBranch := c.String("release-branch")
if upstreamReleaseBranch == "" {
upstreamReleaseBranch = path.Join("release", version)
}
localReleaseBranch := path.Join(upstream, upstreamReleaseBranch)
args := c.Args()
if len(args) == 0 && pr == "" {
return fmt.Errorf("no PR number provided\nProvide a PR number to backport")
} else if len(args) != 1 && pr == "" {
return fmt.Errorf("multiple PRs provided %v\nOnly a single PR can be backported at a time", args)
}
if pr == "" {
pr = args[0]
}
backportBranch := c.String("backport-branch")
if backportBranch == "" {
backportBranch = "backport-" + pr + "-" + version
}
fmt.Printf("* Backporting %s to %s as %s\n", pr, localReleaseBranch, backportBranch)
sha := c.String("cherry-pick")
if sha == "" {
var err error
sha, err = determineSHAforPR(ctx, pr)
if err != nil {
return err
}
}
if sha == "" {
return fmt.Errorf("unable to determine sha for cherry-pick of %s", pr)
}
if !c.Bool("no-fetch") {
if err := fetchRemoteAndMain(ctx, upstream, upstreamReleaseBranch); err != nil {
return err
}
}
if !continuing {
if err := checkoutBackportBranch(ctx, backportBranch, localReleaseBranch); err != nil {
return err
}
}
if err := cherrypick(ctx, sha); err != nil {
return err
}
if !c.Bool("no-amend-message") {
if err := amendCommit(ctx, pr); err != nil {
return err
}
}
if !c.Bool("no-push") {
url := "https://github.com/go-gitea/gitea/compare/" + upstreamReleaseBranch + "..." + forkUser + ":" + backportBranch
if err := gitPushUp(ctx, remote, backportBranch); err != nil {
return err
}
if !c.Bool("no-xdg-open") {
if err := xdgOpen(ctx, url); err != nil {
return err
}
} else {
fmt.Printf("* Navigate to %s to open PR\n", url)
}
}
return nil
}
func xdgOpen(ctx context.Context, url string) error {
fmt.Printf("* `xdg-open %s`\n", url)
out, err := exec.CommandContext(ctx, "xdg-open", url).Output()
if err != nil {
fmt.Fprintf(os.Stderr, "%s", string(out))
return fmt.Errorf("unable to xdg-open to %s: %w", url, err)
}
return nil
}
func gitPushUp(ctx context.Context, remote, backportBranch string) error {
fmt.Printf("* `git push -u %s %s`\n", remote, backportBranch)
out, err := exec.CommandContext(ctx, "git", "push", "-u", remote, backportBranch).Output()
if err != nil {
fmt.Fprintf(os.Stderr, "%s", string(out))
return fmt.Errorf("unable to push up to %s: %w", remote, err)
}
return nil
}
func amendCommit(ctx context.Context, pr string) error {
fmt.Printf("* Amending commit to prepend `Backport #%s` to body\n", pr)
out, err := exec.CommandContext(ctx, "git", "log", "-1", "--pretty=format:%B").Output()
if err != nil {
fmt.Fprintf(os.Stderr, "%s", string(out))
return fmt.Errorf("unable to get last log message: %w", err)
}
parts := strings.SplitN(string(out), "\n", 2)
if len(parts) != 2 {
return fmt.Errorf("unable to interpret log message:\n%s", string(out))
}
subject, body := parts[0], parts[1]
if !strings.HasSuffix(subject, " (#"+pr+")") {
subject = subject + " (#" + pr + ")"
}
out, err = exec.CommandContext(ctx, "git", "commit", "--amend", "-m", subject+"\n\nBackport #"+pr+"\n"+body).Output()
if err != nil {
fmt.Fprintf(os.Stderr, "%s", string(out))
return fmt.Errorf("unable to amend last log message: %w", err)
}
return nil
}
func cherrypick(ctx context.Context, sha string) error {
// Check if a CHERRY_PICK_HEAD exists
if _, err := os.Stat(".git/CHERRY_PICK_HEAD"); err == nil {
// Assume that we are in the middle of cherry-pick - continue it
fmt.Println("* Attempting git cherry-pick --continue")
out, err := exec.CommandContext(ctx, "git", "cherry-pick", "--continue").Output()
if err != nil {
fmt.Fprintf(os.Stderr, "git cherry-pick --continue failed:\n%s\n", string(out))
return fmt.Errorf("unable to continue cherry-pick: %w", err)
}
return nil
}
fmt.Printf("* Attempting git cherry-pick %s\n", sha)
out, err := exec.CommandContext(ctx, "git", "cherry-pick", sha).Output()
if err != nil {
fmt.Fprintf(os.Stderr, "git cherry-pick %s failed:\n%s\n", sha, string(out))
return fmt.Errorf("git cherry-pick %s failed: %w", sha, err)
}
return nil
}
func checkoutBackportBranch(ctx context.Context, backportBranch, releaseBranch string) error {
out, err := exec.CommandContext(ctx, "git", "branch", "--show-current").Output()
if err != nil {
return fmt.Errorf("unable to check current branch %w", err)
}
currentBranch := strings.TrimSpace(string(out))
fmt.Printf("* Current branch is %s\n", currentBranch)
if currentBranch == backportBranch {
fmt.Printf("* Current branch is %s - not checking out\n", currentBranch)
return nil
}
if _, err := exec.CommandContext(ctx, "git", "rev-list", "-1", backportBranch).Output(); err == nil {
fmt.Printf("* Branch %s already exists. Checking it out...\n", backportBranch)
return exec.CommandContext(ctx, "git", "checkout", "-f", backportBranch).Run()
}
fmt.Printf("* `git checkout -b %s %s`\n", backportBranch, releaseBranch)
return exec.CommandContext(ctx, "git", "checkout", "-b", backportBranch, releaseBranch).Run()
}
func fetchRemoteAndMain(ctx context.Context, remote, releaseBranch string) error {
fmt.Printf("* `git fetch %s main`\n", remote)
out, err := exec.CommandContext(ctx, "git", "fetch", remote, "main").Output()
if err != nil {
fmt.Println(string(out))
return fmt.Errorf("unable to fetch %s from %s: %w", "main", remote, err)
}
fmt.Println(string(out))
fmt.Printf("* `git fetch %s %s`\n", remote, releaseBranch)
out, err = exec.CommandContext(ctx, "git", "fetch", remote, releaseBranch).Output()
if err != nil {
fmt.Println(string(out))
return fmt.Errorf("unable to fetch %s from %s: %w", releaseBranch, remote, err)
}
fmt.Println(string(out))
return nil
}
func determineRemote(ctx context.Context, forkUser string) (string, string, error) {
out, err := exec.CommandContext(ctx, "git", "remote", "-v").Output()
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to list git remotes:\n%s\n", string(out))
return "", "", fmt.Errorf("unable to determine forked remote: %w", err)
}
lines := strings.Split(string(out), "\n")
for _, line := range lines {
fields := strings.Split(line, "\t")
name, remote := fields[0], fields[1]
// only look at pushers
if !strings.HasSuffix(remote, " (push)") {
continue
}
// only look at github.com pushes
if !strings.Contains(remote, "github.com") {
continue
}
// ignore go-gitea/gitea
if strings.Contains(remote, "go-gitea/gitea") {
continue
}
if !strings.Contains(remote, forkUser) {
continue
}
if strings.HasPrefix(remote, "git@github.com:") {
forkUser = strings.TrimPrefix(remote, "git@github.com:")
} else if strings.HasPrefix(remote, "https://github.com/") {
forkUser = strings.TrimPrefix(remote, "https://github.com/")
} else if strings.HasPrefix(remote, "https://www.github.com/") {
forkUser = strings.TrimPrefix(remote, "https://www.github.com/")
} else if forkUser == "" {
return "", "", fmt.Errorf("unable to extract forkUser from remote %s: %s", name, remote)
}
idx := strings.Index(forkUser, "/")
if idx >= 0 {
forkUser = forkUser[:idx]
}
return name, forkUser, nil
}
return "", "", fmt.Errorf("unable to find appropriate remote in:\n%s", string(out))
}
func readCurrentBranch(ctx context.Context) (pr, version string, err error) {
out, err := exec.CommandContext(ctx, "git", "branch", "--show-current").Output()
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read current git branch:\n%s\n", string(out))
return "", "", fmt.Errorf("unable to read current git branch: %w", err)
}
parts := strings.Split(strings.TrimSpace(string(out)), "-")
if len(parts) != 3 || parts[0] != "backport" {
fmt.Fprintf(os.Stderr, "Unable to continue from git branch:\n%s\n", string(out))
return "", "", fmt.Errorf("unable to continue from git branch:\n%s", string(out))
}
return parts[1], parts[2], nil
}
func readVersion() string {
bs, err := os.ReadFile("docs/config.yaml")
if err != nil {
if err == os.ErrNotExist {
log.Println("`docs/config.yaml` not present")
return ""
}
fmt.Fprintf(os.Stderr, "Unable to read `docs/config.yaml`: %v\n", err)
return ""
}
type params struct {
Version string
}
type docConfig struct {
Params params
}
dc := &docConfig{}
if err := yaml.Unmarshal(bs, dc); err != nil {
fmt.Fprintf(os.Stderr, "Unable to read `docs/config.yaml`: %v\n", err)
return ""
}
if dc.Params.Version == "" {
fmt.Fprintf(os.Stderr, "No version in `docs/config.yaml`")
return ""
}
version := dc.Params.Version
if version[0] != 'v' {
version = "v" + version
}
split := strings.SplitN(version, ".", 3)
return strings.Join(split[:2], ".")
}
func determineSHAforPR(ctx context.Context, prStr string) (string, error) {
prNum, err := strconv.Atoi(prStr)
if err != nil {
return "", err
}
client := github.NewClient(http.DefaultClient)
pr, _, err := client.PullRequests.Get(ctx, "go-gitea", "gitea", prNum)
if err != nil {
return "", err
}
if pr.Merged == nil || !*pr.Merged {
return "", fmt.Errorf("PR #%d is not yet merged - cannot determine sha to backport", prNum)
}
if pr.MergeCommitSHA != nil {
return *pr.MergeCommitSHA, nil
}
return "", nil
}
func installSignals() (context.Context, context.CancelFunc) {
ctx, cancel := context.WithCancel(context.Background())
go func() {
// install notify
signalChannel := make(chan os.Signal, 1)
signal.Notify(
signalChannel,
syscall.SIGINT,
syscall.SIGTERM,
)
select {
case <-signalChannel:
case <-ctx.Done():
}
cancel()
signal.Reset()
}()
return ctx, cancel
}

View File

@ -1,6 +1,5 @@
// Copyright 2019 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.
// SPDX-License-Identifier: MIT
package main

View File

@ -1,6 +1,5 @@
// 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.
// SPDX-License-Identifier: MIT
package main

View File

@ -29,7 +29,7 @@ local addIssueLabelsOverrides(labels) =
grafanaDashboards+:: {
local giteaSelector = 'job="$job", instance="$instance"',
local giteaSelector = 'job=~"$job", instance=~"$instance"',
local giteaStatsPanel =
grafana.statPanel.new(
'Gitea stats',
@ -399,25 +399,31 @@ local addIssueLabelsOverrides(labels) =
.addTemplate(
{
hide: 0,
label: null,
label: 'job',
name: 'job',
options: [],
datasource: '$datasource',
query: 'label_values(gitea_organizations, job)',
refresh: 1,
regex: '',
type: 'query',
multi: true,
allValue: '.+'
},
)
.addTemplate(
{
hide: 0,
label: null,
label: 'instance',
name: 'instance',
options: [],
datasource: '$datasource',
query: 'label_values(gitea_organizations{job="$job"}, instance)',
refresh: 1,
regex: '',
type: 'query',
multi: true,
allValue: '.+'
},
)
.addTemplate(

View File

@ -2,14 +2,43 @@
DIR=/var/lib/gitea
USER=git
HOME=/home/${USER}
GITEA_WORK_DIR=${DIR}
EXECUTABLE=/usr/local/bin/gitea
export USER
export HOME
export GITEA_WORK_DIR
name=$RC_SVCNAME
cfgfile="/etc/$RC_SVCNAME/app.ini"
command="${EXECUTABLE}"
command_user="${USER}"
command_args="web -c /etc/$RC_SVCNAME/app.ini"
command_background="yes"
pidfile="/run/$RC_SVCNAME/$RC_SVCNAME.pid"
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=/run/gitea.pid
depend()
{
need net
###
# Don't forget to add the database service requirements
###
#after postgresql
#after mysql
#after mariadb
#after memcached
#after redis
}
start_pre()
{
checkpath --directory --owner $command_user:$command_user --mode 0750 \
/run/$RC_SVCNAME /var/log/$RC_SVCNAME
##
# If you want to bind Gitea to a port below 1024, uncomment
# the value below
##
#setcap cap_net_bind_service=+ep "${EXECUTABLE}"
}

84
contrib/init/ubuntu/gitea Normal file
View File

@ -0,0 +1,84 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: gitea
# Required-Start: $syslog $network
# Required-Stop: $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: A self-hosted Git service written in Go.
# Description: A self-hosted Git service written in Go.
### END INIT INFO
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin
DESC="Gitea - Git with a cup of tea"
NAME=gitea
SERVICEVERBOSE=yes
PIDFILE=/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
WORKINGDIR=/var/lib/$NAME
DAEMON=/usr/local/bin/$NAME
DAEMON_ARGS="web -c /etc/$NAME/app.ini"
USER=git
STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/1/KILL/5}"
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
do_start()
{
GITEA_ENVS="USER=$USER GITEA_WORK_DIR=$WORKINGDIR HOME=/home/$USER"
GITEA_EXEC="$DAEMON -- $DAEMON_ARGS"
sh -c "start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile \\
--background --chdir $WORKINGDIR --chuid $USER \\
--exec /bin/bash -- -c '/usr/bin/env $GITEA_ENVS $GITEA_EXEC'"
}
do_stop()
{
start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PIDFILE --name $NAME --oknodo
rm -f $PIDFILE
}
do_status()
{
if [ -f $PIDFILE ]; then
if kill -0 $(cat "$PIDFILE"); then
echo "$NAME is running, PID is $(cat $PIDFILE)"
else
echo "$NAME process is dead, but pidfile exists"
fi
else
echo "$NAME is not running"
fi
}
case "$1" in
start)
echo "Starting $DESC" "$NAME"
do_start
;;
stop)
echo "Stopping $DESC" "$NAME"
do_stop
;;
status)
do_status
;;
restart)
echo "Restarting $DESC" "$NAME"
do_stop
do_start
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
exit 2
;;
esac
exit 0

View File

@ -1,2 +0,0 @@
DROP DATABASE IF EXISTS gitea;
CREATE DATABASE IF NOT EXISTS gitea CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

View File

@ -1,270 +0,0 @@
// 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 main
/*
Checkout a PR and load the tests data into sqlite database
*/
import (
"context"
"flag"
"fmt"
"log"
"net/http"
"net/url"
"os"
"os/exec"
"os/user"
"path"
"path/filepath"
"runtime"
"strconv"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
gitea_git "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/external"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
"xorm.io/xorm"
)
var codeFilePath = "contrib/pr/checkout.go"
func runPR() {
log.Printf("[PR] Starting gitea ...\n")
curDir, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
setting.SetCustomPathAndConf("", "", "")
setting.LoadAllowEmpty()
setting.RepoRootPath, err = os.MkdirTemp(os.TempDir(), "repos")
if err != nil {
log.Fatalf("TempDir: %v\n", err)
}
setting.AppDataPath, err = os.MkdirTemp(os.TempDir(), "appdata")
if err != nil {
log.Fatalf("TempDir: %v\n", err)
}
setting.AppWorkPath = curDir
setting.StaticRootPath = curDir
setting.GravatarSourceURL, err = url.Parse("https://secure.gravatar.com/avatar/")
if err != nil {
log.Fatalf("url.Parse: %v\n", err)
}
setting.AppURL = "http://localhost:8080/"
setting.HTTPPort = "8080"
setting.SSH.Domain = "localhost"
setting.SSH.Port = 3000
setting.InstallLock = true
setting.SecretKey = "9pCviYTWSb"
setting.InternalToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8"
curUser, err := user.Current()
if err != nil {
log.Fatal(err)
}
setting.RunUser = curUser.Username
log.Printf("[PR] Loading fixtures data ...\n")
//models.LoadConfigs()
/*
setting.Database.Type = "sqlite3"
setting.Database.Path = ":memory:"
setting.Database.Timeout = 500
*/
dbCfg := setting.Cfg.Section("database")
dbCfg.NewKey("DB_TYPE", "sqlite3")
dbCfg.NewKey("PATH", ":memory:")
routers.InitGitServices()
setting.Database.LogSQL = true
// x, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared")
db.InitEngineWithMigration(context.Background(), func(_ *xorm.Engine) error {
return nil
})
db.HasEngine = true
// x.ShowSQL(true)
err = unittest.InitFixtures(
unittest.FixturesOptions{
Dir: path.Join(curDir, "models/fixtures/"),
},
)
if err != nil {
fmt.Printf("Error initializing test database: %v\n", err)
os.Exit(1)
}
unittest.LoadFixtures()
util.RemoveAll(setting.RepoRootPath)
util.RemoveAll(repo_module.LocalCopyPath())
unittest.CopyDir(path.Join(curDir, "integrations/gitea-repositories-meta"), setting.RepoRootPath)
log.Printf("[PR] Setting up router\n")
// routers.GlobalInit()
external.RegisterRenderers()
markup.Init()
c := routers.NormalRoutes()
log.Printf("[PR] Ready for testing !\n")
log.Printf("[PR] Login with user1, user2, user3, ... with pass: password\n")
/*
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL)
if setting.LFS.StartServer {
log.Info("LFS server enabled")
}
if setting.EnablePprof {
go func() {
log.Info("Starting pprof server on localhost:6060")
log.Info("%v", http.ListenAndServe("localhost:6060", nil))
}()
}
*/
// Start the server
http.ListenAndServe(":8080", c)
log.Printf("[PR] Cleaning up ...\n")
/*
if err = util.RemoveAll(setting.Indexer.IssuePath); err != nil {
fmt.Printf("util.RemoveAll: %v\n", err)
os.Exit(1)
}
if err = util.RemoveAll(setting.Indexer.RepoPath); err != nil {
fmt.Printf("Unable to remove repo indexer: %v\n", err)
os.Exit(1)
}
*/
if err = util.RemoveAll(setting.RepoRootPath); err != nil {
log.Fatalf("util.RemoveAll: %v\n", err)
}
if err = util.RemoveAll(setting.AppDataPath); err != nil {
log.Fatalf("util.RemoveAll: %v\n", err)
}
}
func main() {
runPRFlag := flag.Bool("run", false, "Run the PR code")
flag.Parse()
if *runPRFlag {
runPR()
return
}
// To force checkout (e.g. Windows complains about unclean work tree) set env variable FORCE=true
force, err := strconv.ParseBool(os.Getenv("FORCE"))
if err != nil {
force = false
}
// Otherwise checkout PR
if len(os.Args) != 2 {
log.Fatal("Need only one arg: the PR number")
}
pr := os.Args[1]
codeFilePath = filepath.FromSlash(codeFilePath) // Convert to running OS
// Copy this file if it will not exist in the PR branch
dat, err := os.ReadFile(codeFilePath)
if err != nil {
log.Fatalf("Failed to cache this code file : %v", err)
}
repo, err := git.PlainOpen(".")
if err != nil {
log.Fatalf("Failed to open the repo : %v", err)
}
// Find remote upstream
remotes, err := repo.Remotes()
if err != nil {
log.Fatalf("Failed to list remotes of repo : %v", err)
}
remoteUpstream := "origin" // Default
for _, r := range remotes {
if r.Config().URLs[0] == "https://github.com/go-gitea/gitea.git" ||
r.Config().URLs[0] == "https://github.com/go-gitea/gitea" ||
r.Config().URLs[0] == "git@github.com:go-gitea/gitea.git" { // fetch at index 0
remoteUpstream = r.Config().Name
break
}
}
branch := fmt.Sprintf("pr-%s-%d", pr, time.Now().Unix())
branchRef := plumbing.NewBranchReferenceName(branch)
log.Printf("Fetching PR #%s in %s\n", pr, branch)
if runtime.GOOS == "windows" {
// Use git cli command for windows
runCmd("git", "fetch", remoteUpstream, fmt.Sprintf("pull/%s/head:%s", pr, branch))
} else {
ref := fmt.Sprintf("%s%s/head:%s", gitea_git.PullPrefix, pr, branchRef)
err = repo.Fetch(&git.FetchOptions{
RemoteName: remoteUpstream,
RefSpecs: []config.RefSpec{
config.RefSpec(ref),
},
})
if err != nil {
log.Fatalf("Failed to fetch %s from %s : %v", ref, remoteUpstream, err)
}
}
tree, err := repo.Worktree()
if err != nil {
log.Fatalf("Failed to parse git tree : %v", err)
}
log.Printf("Checkout PR #%s in %s\n", pr, branch)
err = tree.Checkout(&git.CheckoutOptions{
Branch: branchRef,
Force: force,
})
if err != nil {
log.Fatalf("Failed to checkout %s : %v", branch, err)
}
// Copy this file if not exist
if _, err := os.Stat(codeFilePath); os.IsNotExist(err) {
err = os.MkdirAll(filepath.Dir(codeFilePath), 0o755)
if err != nil {
log.Fatalf("Failed to duplicate this code file in PR : %v", err)
}
err = os.WriteFile(codeFilePath, dat, 0o644)
if err != nil {
log.Fatalf("Failed to duplicate this code file in PR : %v", err)
}
}
// Force build of js, css, bin, ...
runCmd("make", "build")
// Start with integration test
runCmd("go", "run", "-mod", "vendor", "-tags", "sqlite sqlite_unlock_notify", codeFilePath, "-run")
}
func runCmd(cmd ...string) {
log.Printf("Executing : %s ...\n", cmd)
c := exec.Command(cmd[0], cmd[1:]...)
c.Stdout = os.Stdout
c.Stderr = os.Stderr
if err := c.Start(); err != nil {
log.Panicln(err)
}
if err := c.Wait(); err != nil {
log.Panicln(err)
}
}

View File

@ -49,12 +49,8 @@ After=network.target
###
[Service]
# Modify these two values and uncomment them if you have
# repos with lots of files and get an HTTP error 500 because
# of that
###
#LimitMEMLOCK=infinity
#LimitNOFILE=65535
# Uncomment the next line if you have repos with lots of files and get a HTTP 500 error because of that
# LimitNOFILE=524288:524288
RestartSec=2s
Type=simple
User=git

View File

@ -7,6 +7,38 @@
;; see https://docs.gitea.io/en-us/config-cheat-sheet/ for additional documentation.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Default Configuration (non-`app.ini` configuration)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; These values are environment-dependent but form the basis of a lot of values. They will be
;; reported as part of the default configuration when running `gitea --help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up.
;;
;; - _`AppPath`_: This is the absolute path of the running gitea binary.
;; - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy:
;; - The `--work-path` flag passed to the binary
;; - The environment variable `$GITEA_WORK_DIR`
;; - A built-in value set at build time (see building from source)
;; - Otherwise it defaults to the directory of the _`AppPath`_
;; - If any of the above are relative paths then they are made absolute against
;; the directory of the _`AppPath`_
;; - _`CustomPath`_: This is the base directory for custom templates and other options.
;; It is determined by using the first set thing in the following hierarchy:
;; - The `--custom-path` flag passed to the binary
;; - The environment variable `$GITEA_CUSTOM`
;; - A built-in value set at build time (see building from source)
;; - Otherwise it defaults to _`AppWorkPath`_`/custom`
;; - If any of the above are relative paths then they are made absolute against the
;; the directory of the _`AppWorkPath`_
;; - _`CustomConf`_: This is the path to the `app.ini` file.
;; - The `--config` flag passed to the binary
;; - A built-in value set at build time (see building from source)
;; - Otherwise it defaults to _`CustomPath`_`/conf/app.ini`
;; - If any of the above are relative paths then they are made absolute against the
;; the directory of the _`CustomPath`_
;;
;; In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; General Settings
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -26,7 +58,7 @@ RUN_MODE = ; prod
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; The protocol the server listens on. One of 'http', 'https', 'unix' or 'fcgi'. Defaults to 'http'
;; The protocol the server listens on. One of 'http', 'https', 'http+unix', 'fcgi' or 'fcgi+unix'. Defaults to 'http'
;PROTOCOL = http
;;
;; Expect PROXY protocol headers on connections
@ -51,6 +83,8 @@ RUN_MODE = ; prod
;STATIC_URL_PREFIX =
;;
;; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket.
;; If PROTOCOL is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use.
;; Relative paths will be made absolute against the _`AppWorkPath`_.
;HTTP_ADDR = 0.0.0.0
;;
;; The port to listen on. Leave empty when using a unix socket.
@ -64,7 +98,7 @@ RUN_MODE = ; prod
;PORT_TO_REDIRECT = 80
;;
;; expect PROXY protocol header on connections to https redirector.
;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)
;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s
;; Minimum and maximum supported TLS versions
;SSL_MIN_VERSION=TLSv1.2
;SSL_MAX_VERSION=
@ -91,7 +125,7 @@ RUN_MODE = ; prod
;LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/
;;
;; When making local connections pass the PROXY protocol header.
;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)
;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s
;;
;; Disable SSH feature when not available
;DISABLE_SSH = false
@ -145,7 +179,7 @@ RUN_MODE = ; prod
;;
;; For the built-in SSH server, choose the keypair to offer as the host key
;; The private key should be at SSH_SERVER_HOST_KEY and the public SSH_SERVER_HOST_KEY.pub
;; relative paths are made absolute relative to the APP_DATA_PATH
;; relative paths are made absolute relative to the %(APP_DATA_PATH)s
;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa
;;
;; Directory to create temporary files in when testing public keys using ssh-keygen,
@ -241,10 +275,10 @@ RUN_MODE = ; prod
;;
;; Root directory containing templates and static files.
;; default is the path where Gitea is executed
;STATIC_ROOT_PATH =
;STATIC_ROOT_PATH = ; Will default to the built-in value _`StaticRootPath`_
;;
;; Default path for App data
;APP_DATA_PATH = data
;APP_DATA_PATH = data ; relative paths will be made absolute with _`AppWorkPath`_
;;
;; Enable gzip compression for runtime-generated content, static resources excluded
;ENABLE_GZIP = false
@ -255,7 +289,7 @@ RUN_MODE = ; prod
;ENABLE_PPROF = false
;;
;; PPROF_DATA_PATH, use an absolute path when you start gitea as service
;PPROF_DATA_PATH = data/tmp/pprof
;PPROF_DATA_PATH = data/tmp/pprof ; Path is relative to _`AppWorkPath`_
;;
;; Landing page, can be "home", "explore", "organizations", "login", or any URL such as "/org/repo" or even "https://anotherwebsite.com"
;; The "login" choice is not a security measure but just a UI flow change, use REQUIRE_SIGNIN_VIEW to force users to log in.
@ -369,6 +403,9 @@ LOG_SQL = false ; if unset defaults to true
;;
;; Database maximum number of open connections, default is 0 meaning no maximum
;MAX_OPEN_CONNS = 0
;;
;; Whether execute database models migrations automatically
;AUTO_MIGRATION = true
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -379,14 +416,19 @@ LOG_SQL = false ; if unset defaults to true
;; Whether the installer is disabled (set to true to disable the installer)
INSTALL_LOCK = false
;;
;; Global secret key that will be used - if blank will be regenerated.
;; Global secret key that will be used
;; This key is VERY IMPORTANT. If you lose it, the data encrypted by it (like 2FA secret) can't be decrypted anymore.
SECRET_KEY =
;;
;; Alternative location to specify secret key, instead of this file; you cannot specify both this and SECRET_KEY, and must pick one
;; This key is VERY IMPORTANT. If you lose it, the data encrypted by it (like 2FA secret) can't be decrypted anymore.
;SECRET_KEY_URI = file:/etc/gitea/secret_key
;;
;; Secret used to validate communication within Gitea binary.
INTERNAL_TOKEN=
;;
;; 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)
;INTERNAL_TOKEN_URI = ;e.g. /etc/gitea/internal_token
;; Alternative location to specify internal token, instead of this file; you cannot specify both this and INTERNAL_TOKEN, and must pick one
;INTERNAL_TOKEN_URI = file:/etc/gitea/internal_token
;;
;; How long to remember that a user is logged in before requiring relogin (in days)
;LOGIN_REMEMBER_DAYS = 7
@ -534,6 +576,22 @@ ROUTER = console
;; The routing level will default to that of the system but individual router level can be set in
;; [log.<mode>.router] LEVEL
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Print request id which parsed from request headers in access log, when access log is enabled.
;; * E.g:
;; * In request Header: X-Request-ID: test-id-123
;; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID
;; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "test-id-123"
;;
;; If you configure more than one in the .ini file, it will match in the order of configuration,
;; and the first match will be finally printed in the log.
;; * E.g:
;; * In reuqest Header: X-Trace-ID: trace-id-1q2w3e4r
;; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID, X-Trace-ID, X-Req-ID
;; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "trace-id-1q2w3e4r"
;;
;; REQUEST_ID_HEADERS =
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@ -628,7 +686,7 @@ ROUTER = console
;PATH =
;;
;; The HOME directory for Git
;HOME_PATH = %(APP_DATA_PATH)/home
;HOME_PATH = %(APP_DATA_PATH)s/home
;;
;; Disables highlight of added and removed changes
;DISABLE_DIFF_HIGHLIGHT = false
@ -720,7 +778,10 @@ ROUTER = console
;; Enable captcha validation for registration
;ENABLE_CAPTCHA = false
;;
;; Type of captcha you want to use. Options: image, recaptcha, hcaptcha, mcaptcha.
;; Enable this to require captcha validation for login
;REQUIRE_CAPTCHA_FOR_LOGIN = false
;;
;; Type of captcha you want to use. Options: image, recaptcha, hcaptcha, mcaptcha, cfturnstile.
;CAPTCHA_TYPE = image
;;
;; Change this to use recaptcha.net or other recaptcha service
@ -742,6 +803,10 @@ ROUTER = console
;MCAPTCHA_SECRET =
;MCAPTCHA_SITEKEY =
;;
;; Go to https://dash.cloudflare.com/?to=/:account/turnstile to sign up for a key
;CF_TURNSTILE_SITEKEY =
;CF_TURNSTILE_SECRET =
;;
;; Default value for KeepEmailPrivate
;; Each new user will get the value of this setting copied into their profile
;DEFAULT_KEEP_EMAIL_PRIVATE = false
@ -833,8 +898,8 @@ ROUTER = console
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)/gitea-repositories.
;; A relative path is interpreted as %(GITEA_WORK_DIR)/%(ROOT)
;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)s/gitea-repositories.
;; A relative path is interpreted as _`AppWorkPath`_/%(ROOT)s
;ROOT =
;;
;; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available.
@ -882,14 +947,18 @@ ROUTER = console
;USE_COMPAT_SSH_URI = false
;;
;; Close issues as long as a commit on any branch marks it as fixed
;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki
;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages, repo.actions.
;DISABLED_REPO_UNITS =
;;
;; Comma separated list of default repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects.
;; Comma separated list of default new repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects, repo.packages, repo.actions.
;; 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
;DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages
;;
;; Comma separated list of default forked repo units.
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
;DEFAULT_FORK_REPO_UNITS = repo.code,repo.pulls
;;
;; Prefix archive files by placing them in a directory named after the repository
;PREFIX_ARCHIVE_FILES = true
@ -912,6 +981,9 @@ ROUTER = console
;; Don't allow download source archive files from UI
;DISABLE_DOWNLOAD_SOURCE_ARCHIVES = false
;; Allow fork repositories without maximum number limit
;ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT = true
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository.editor]
@ -921,10 +993,6 @@ ROUTER = console
;; 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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -991,6 +1059,9 @@ ROUTER = console
;;
;; Add co-authored-by and co-committed-by trailers if committer does not match author
;ADD_CO_COMMITTER_TRAILERS = true
;;
;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply
;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1099,6 +1170,9 @@ ROUTER = console
;; allow request with credentials
;ALLOW_CREDENTIALS = false
;;
;; headers to permit
;HEADERS = Content-Type,User-Agent
;;
;; set X-FRAME-OPTIONS header
;X_FRAME_OPTIONS = SAMEORIGIN
@ -1164,6 +1238,10 @@ ROUTER = console
;;
;; Whether to enable a Service Worker to cache frontend assets
;USE_SERVICE_WORKER = false
;;
;; Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
;; A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
;ONLY_SHOW_RELEVANT_REPOS = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1258,6 +1336,9 @@ ROUTER = console
;; 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
;;
;; Enables math inline and block detection
;ENABLE_MATH = true
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1280,13 +1361,13 @@ ROUTER = console
;; Issue Indexer settings
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Issue indexer type, currently support: bleve, db or elasticsearch, default is bleve
;; Issue indexer type, currently support: bleve, db, elasticsearch or meilisearch default is bleve
;ISSUE_INDEXER_TYPE = bleve
;;
;; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve
;ISSUE_INDEXER_PATH = indexers/issues.bleve
;ISSUE_INDEXER_PATH = indexers/issues.bleve ; Relative paths will be made absolute against _`AppWorkPath`_.
;;
;; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch
;; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch or meilisearch
;ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
;;
;; Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch
@ -1302,7 +1383,7 @@ ROUTER = console
;; When ISSUE_INDEXER_QUEUE_TYPE is levelqueue, this will be the path where the queue will be saved.
;; This can be overridden by `ISSUE_INDEXER_QUEUE_CONN_STR`.
;; default is queues/common
;ISSUE_INDEXER_QUEUE_DIR = queues/common; **DEPRECATED** use settings in `[queue.issue_indexer]`.
;ISSUE_INDEXER_QUEUE_DIR = queues/common; **DEPRECATED** use settings in `[queue.issue_indexer]`. Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
;;
;; When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string.
;; When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this is a directory or additional options of
@ -1358,7 +1439,7 @@ ROUTER = console
;TYPE = persistable-channel
;;
;; data-dir for storing persistable queues and level queues, individual queues will default to `queues/common` meaning the queue is shared.
;DATADIR = queues/
;DATADIR = queues/ ; Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
;;
;; Default queue length before a channel queue will block
;LENGTH = 20
@ -1538,7 +1619,7 @@ ROUTER = console
;; Prefix displayed before subject in mail
;SUBJECT_PREFIX =
;;
;; Mail server protocol. One of "smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy".
;; Mail server protocol. One of "smtp", "smtps", "smtp+starttls", "smtp+unix", "sendmail", "dummy".
;; - sendmail: use the operating system's `sendmail` command instead of SMTP. This is common on Linux systems.
;; - dummy: send email messages to the log as a testing phase.
;; If your provider does not explicitly say which protocol it uses but does provide a port,
@ -1603,6 +1684,47 @@ ROUTER = console
;; convert \r\n to \n for Sendmail
;SENDMAIL_CONVERT_CRLF = true
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[email.incoming]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Enable handling of incoming emails.
;ENABLED = false
;;
;; The email address including the %{token} placeholder that will be replaced per user/action.
;; Example: incoming+%{token}@example.com
;; The placeholder must appear in the user part of the address (before the @).
;REPLY_TO_ADDRESS =
;;
;; IMAP server host
;HOST =
;;
;; IMAP server port
;PORT =
;;
;; Username of the receiving account
;USERNAME =
;;
;; Password of the receiving account
;PASSWORD =
;;
;; Whether the IMAP server uses TLS.
;USE_TLS = false
;;
;; If set to true, completely ignores server certificate validation errors. This option is unsafe.
;SKIP_TLS_VERIFY = true
;;
;; The mailbox name where incoming mail will end up.
;MAILBOX = INBOX
;;
;; Whether handled messages should be deleted from the mailbox.
;DELETE_HANDLED_MESSAGE = true
;;
;; Maximum size of a message to handle. Bigger messages are ignored. Set to 0 to allow every size.
;MAXIMUM_MESSAGE_SIZE = 10485760
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cache]
@ -1619,7 +1741,7 @@ ROUTER = console
;INTERVAL = 60
;;
;; For "redis" and "memcache", connection host address
;; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
;; memcache: `127.0.0.1:11211`
;; twoqueue: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000`
;HOST =
@ -1658,9 +1780,9 @@ ROUTER = console
;; 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
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
;; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table`
;PROVIDER_CONFIG = data/sessions
;PROVIDER_CONFIG = data/sessions ; Relative paths will be made absolute against _`AppWorkPath`_.
;;
;; Session cookie name
;COOKIE_NAME = i_like_gitea
@ -1726,7 +1848,7 @@ ROUTER = console
;ENABLED = true
;;
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
;ALLOWED_TYPES = .csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip
;ALLOWED_TYPES = .csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip
;;
;; Max size of each file. Defaults to 4MB
;MAX_SIZE = 4
@ -1765,6 +1887,12 @@ ROUTER = console
;;
;; Minio enabled ssl only available when STORAGE_TYPE is `minio`
;MINIO_USE_SSL = false
;;
;; Minio skip SSL verification available when STORAGE_TYPE is `minio`
;MINIO_INSECURE_SKIP_VERIFY = false
;;
;; Minio checksum algorithm: default (for MinIO or AWS S3) or md5 (for Cloudflare or Backblaze)
;MINIO_CHECKSUM_ALGORITHM = default
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2092,7 +2220,7 @@ ROUTER = console
;[cron.update_checker]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = false
;ENABLED = true
;RUN_AT_START = false
;ENABLE_SUCCESS_NOTICE = false
;SCHEDULE = @every 168h
@ -2111,6 +2239,28 @@ ROUTER = console
;SCHEDULE = @every 168h
;OLDER_THAN = 8760h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Garbage collect LFS pointers in repositories
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cron.gc_lfs]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = false
;; Garbage collect LFS pointers in repositories (default false)
;RUN_AT_START = false
;; Interval as a duration between each gc run (default every 24h)
;SCHEDULE = @every 24h
;; Only attempt to garbage collect LFSMetaObjects older than this (default 7 days)
;OLDER_THAN = 168h
;; Only attempt to garbage collect LFSMetaObjects that have not been attempted to be garbage collected for this long (default 3 days)
;LAST_UPDATED_MORE_THAN_AGO = 72h
; Minimum number of stale LFSMetaObjects to check per repo. Set to `0` to always check all.
;NUMBER_TO_CHECK_PER_REPO = 100
;Check at least this proportion of LFSMetaObjects per repo. (This may cause all stale LFSMetaObjects to be checked.)
;PROPORTION_TO_CHECK_PER_REPO = 0.6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Git Operation timeout in seconds
@ -2125,6 +2275,17 @@ ROUTER = console
;PULL = 300
;GC = 60
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Git Reflog timeout in days
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[git.reflog]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = true
;EXPIRATION = 90
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[mirror]
@ -2146,7 +2307,7 @@ ROUTER = console
;[api]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Enables Swagger. True or false; default is true.
;; Enables the API documentation endpoints (/api/swagger, /api/v1/swagger, …). True or false.
;ENABLE_SWAGGER = true
;; Max number of items in a page
;MAX_RESPONSE_ITEMS = 50
@ -2154,7 +2315,7 @@ ROUTER = console
;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 size of a blob returned by the blobs API (default is 10MiB)
;DEFAULT_MAX_BLOB_SIZE = 10485760
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2184,7 +2345,10 @@ ROUTER = console
;SHOW_FOOTER_VERSION = true
;; Show template execution time in the footer
;SHOW_FOOTER_TEMPLATE_LOAD_TIME = true
;; Generate sitemap. Defaults to `true`.
;ENABLE_SITEMAP = true
;; Enable/Disable RSS/Atom feed
;ENABLE_FEED = true
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2253,8 +2417,8 @@ ROUTER = console
;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"
;; If there is a password of redis, use `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`.
;QUEUE_CONN_STR = "redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2322,6 +2486,43 @@ ROUTER = console
;;
;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload`
;CHUNKED_UPLOAD_PATH = tmp/package-upload
;;
;; Maximum count of package versions a single owner can have (`-1` means no limits)
;LIMIT_TOTAL_OWNER_COUNT = -1
;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_TOTAL_OWNER_SIZE = -1
;; Maximum size of a Cargo upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_CARGO = -1
;; Maximum size of a Chef upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_CHEF = -1
;; Maximum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_COMPOSER = -1
;; Maximum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_CONAN = -1
;; Maximum size of a Conda upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_CONDA = -1
;; Maximum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_CONTAINER = -1
;; Maximum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_GENERIC = -1
;; Maximum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_HELM = -1
;; Maximum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_MAVEN = -1
;; Maximum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_NPM = -1
;; Maximum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_NUGET = -1
;; Maximum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_PUB = -1
;; Maximum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_PYPI = -1
;; Maximum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_RUBYGEMS = -1
;; Maximum size of a Swift upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_SWIFT = -1
;; Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_VAGRANT = -1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2386,6 +2587,9 @@ ROUTER = console
;;
;; Minio enabled ssl only available when STORAGE_TYPE is `minio`
;MINIO_USE_SSL = false
;;
;; Minio skip SSL verification available when STORAGE_TYPE is `minio`
;MINIO_INSECURE_SKIP_VERIFY = false
;[proxy]
;; Enable the proxy, all requests to external via HTTP will be affected
@ -2394,3 +2598,19 @@ ROUTER = console
;PROXY_URL =
;; Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts.
;PROXY_HOSTS =
; [actions]
;; Enable/Disable actions capabilities
;ENABLED = false
;; Default address to get action plugins, e.g. the default value means downloading from "https://gitea.com/actions/checkout" for "uses: actions/checkout@v3"
;DEFAULT_ACTIONS_URL = https://gitea.com
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; settings for action logs, will override storage setting
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[storage.actions_log]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; storage type
;STORAGE_TYPE = local

View File

@ -1,10 +1,12 @@
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-rootless
{{#if build.tags}}
{{#unless (contains "-rc" build.tag)}}
tags:
{{#each build.tags}}
- {{this}}-rootless
{{/each}}
- "latest-rootless"
{{/unless}}
{{/if}}
manifests:
-

View File

@ -1,10 +1,12 @@
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}
{{#if build.tags}}
{{#unless (contains "-rc" build.tag)}}
tags:
{{#each build.tags}}
- {{this}}
{{/each}}
- "latest"
{{/unless}}
{{/if}}
manifests:
-

View File

@ -14,11 +14,6 @@ if [ ! -f /data/ssh/ssh_host_rsa_key ]; then
ssh-keygen -t rsa -b 2048 -f /data/ssh/ssh_host_rsa_key -N "" > /dev/null
fi
if [ ! -f /data/ssh/ssh_host_dsa_key ]; then
echo "Generating /data/ssh/ssh_host_dsa_key..."
ssh-keygen -t dsa -f /data/ssh/ssh_host_dsa_key -N "" > /dev/null
fi
if [ ! -f /data/ssh/ssh_host_ecdsa_key ]; then
echo "Generating /data/ssh/ssh_host_ecdsa_key..."
ssh-keygen -t ecdsa -b 256 -f /data/ssh/ssh_host_ecdsa_key -N "" > /dev/null
@ -36,17 +31,12 @@ if [ -e /data/ssh/ssh_host_ecdsa_cert ]; then
SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa_cert"}
fi
if [ -e /data/ssh/ssh_host_dsa_cert ]; then
SSH_DSA_CERT=${SSH_DSA_CERT:-"/data/ssh/ssh_host_dsa_cert"}
fi
if [ -d /etc/ssh ]; then
SSH_PORT=${SSH_PORT:-"22"} \
SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-"${SSH_PORT}"} \
SSH_ED25519_CERT="${SSH_ED25519_CERT:+"HostCertificate "}${SSH_ED25519_CERT}" \
SSH_RSA_CERT="${SSH_RSA_CERT:+"HostCertificate "}${SSH_RSA_CERT}" \
SSH_ECDSA_CERT="${SSH_ECDSA_CERT:+"HostCertificate "}${SSH_ECDSA_CERT}" \
SSH_DSA_CERT="${SSH_DSA_CERT:+"HostCertificate "}${SSH_DSA_CERT}" \
SSH_MAX_STARTUPS="${SSH_MAX_STARTUPS:+"MaxStartups "}${SSH_MAX_STARTUPS}" \
SSH_MAX_SESSIONS="${SSH_MAX_SESSIONS:+"MaxSessions "}${SSH_MAX_SESSIONS}" \
SSH_INCLUDE_FILE="${SSH_INCLUDE_FILE:+"Include "}${SSH_INCLUDE_FILE}" \

View File

@ -16,8 +16,6 @@ HostKey /data/ssh/ssh_host_rsa_key
${SSH_RSA_CERT}
HostKey /data/ssh/ssh_host_ecdsa_key
${SSH_ECDSA_CERT}
HostKey /data/ssh/ssh_host_dsa_key
${SSH_DSA_CERT}
AuthorizedKeysFile .ssh/authorized_keys
AuthorizedPrincipalsFile .ssh/authorized_principals

View File

@ -37,7 +37,7 @@ 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
REPOSITORY_AVATAR_UPLOAD_PATH = $GITEA_WORK_DIR/data/repo-avatars
[attachment]
PATH = $GITEA_WORK_DIR/data/attachments

3
docs/.gitignore vendored
View File

@ -2,3 +2,6 @@ public/
templates/swagger/v1_json.tmpl
themes/
resources/
# Temporary lock file while building
/.hugo_build.lock

View File

@ -1,6 +1,8 @@
THEME := themes/gitea
PUBLIC := public
ARCHIVE := https://dl.gitea.io/theme/master.tar.gz
ARCHIVE := https://dl.gitea.com/theme/main.tar.gz
HUGO_PACKAGE := github.com/gohugoio/hugo@v0.111.3
.PHONY: all
all: build
@ -11,19 +13,19 @@ clean:
.PHONY: trans-copy
trans-copy:
@bash scripts/trans-copy
bash scripts/trans-copy.sh
.PHONY: server
server: $(THEME)
hugo server
go run $(HUGO_PACKAGE) server
.PHONY: build
build: $(THEME)
hugo --cleanDestinationDir
go run $(HUGO_PACKAGE) --cleanDestinationDir
.PHONY: build-offline
build-offline: $(THEME)
hugo --baseURL="/" --cleanDestinationDir
go run $(HUGO_PACKAGE) --baseURL="/" --cleanDestinationDir
.PHONY: update
update: $(THEME)

View File

@ -18,11 +18,18 @@ params:
description: Git with a cup of tea
author: The Gitea Authors
website: https://docs.gitea.io
version: 1.17.1
minGoVersion: 1.18
goVersion: 1.19
minNodeVersion: 14
version: 1.19.0
minGoVersion: 1.19
goVersion: 1.20
minNodeVersion: 16
search: nav
repo: "https://github.com/go-gitea/gitea"
docContentPath: "docs/content"
markup:
tableOfContents:
startLevel: 1
endLevel: 9
outputs:
home:

View File

@ -0,0 +1,14 @@
---
date: "2016-12-01T16:00:00+02:00"
title: "Administration"
slug: "administration"
weight: 30
toc: false
draft: false
menu:
sidebar:
name: "Administration"
weight: 20
collapse: true
identifier: "administration"
---

View File

@ -1,13 +1,13 @@
---
date: "2017-08-23T09:00:00+02:00"
title: "Avancé"
slug: "advanced"
slug: "administration"
weight: 30
toc: false
draft: false
menu:
sidebar:
name: "Avancé"
weight: 40
identifier: "advanced"
weight: 20
identifier: "administration"
---

View File

@ -0,0 +1,13 @@
---
date: "2016-12-01T16:00:00+02:00"
title: "运维"
slug: "administration"
weight: 30
toc: false
draft: false
menu:
sidebar:
name: "运维"
weight: 20
identifier: "administration"
---

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