Compare commits

..

65 Commits

Author SHA1 Message Date
John Olheiser
9f33aa61bd Proposed changelog for 1.7.4 (#6316)
* Proposed changelog for 1.7.4

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Updated security fix description with @zeripath suggestion.

* Added 6292

* Update CHANGELOG.md

* Update CHANGELOG.md
2019-03-13 09:02:58 +08:00
Lunny Xiao
d0bbfd835f update git vendor to fix wrong release commit id and add migrations (#6224) (#6300) 2019-03-12 13:39:20 -04:00
techknowlogick
c7bbfd8f5e backport 6306 (#6308) 2019-03-12 18:58:49 +08:00
Muhammed TİFTİKÇİ
59a64c0e1d Fix #5580 : Make organization dropdown scrollable when using mouse wh… (#6246)
* Fix #5580 : Make organization dropdown scrollable when using mouse wheel.

* build less file with old makefile
2019-03-05 13:27:50 -05:00
Lunny Xiao
6a86a82368 fix display dashboard even if require to change password (#6214) (#6215)
* fix display dashboard even if require to change password

* fix comments
2019-02-28 19:36:57 +08:00
zeripath
8ab107c2dd Add Changelog for 1.7.3 (#6202)
* Add Changelog for 1.7.3
2019-02-27 20:13:13 +00:00
Lunny Xiao
cbfc7f52b9 fix bug when migrate repository 500 when repo is existed (#6188) (#6197) 2019-02-26 22:32:25 -05:00
John Olheiser
d602ba564f Load Issue attributes for API call (#6122) (#6185)
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2019-02-25 21:05:45 -05:00
Lunny Xiao
55063f2524 fix bug user could change private repository to public when force private enabled. (#6156) (#6165) 2019-02-23 05:53:52 +00:00
Lunny Xiao
585dd13cce fix bug when update owner team then visit team's repo return 404 (#6119) (#6166) 2019-02-22 22:55:32 -05:00
Lauris BH
12d883412f Fix heatmap and repository menu display in Internet Explorer 9+ (#6117) (#6137) 2019-02-20 22:11:58 +08:00
Lunny Xiao
597a30b727 Fix prohibit login check on authorization (#6106) (#6115)
* Fix prohibit login check on authorization (#6106)

* fix bug prohibit login not applied on dashboard

* fix tests

* fix bug user status leak

* fix typo

* return after render

* remove unused tests
2019-02-19 11:38:04 +02:00
zeripath
b5ae8945e5 Move to ldap.v3 to fix #5928 (#6105) (#6107)
Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-02-18 14:24:25 +00:00
zeripath
5cca840bb8 Fix deadlock in webhook PullRequest (#6102) (#6104)
Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-02-17 22:38:26 -05:00
xdch47
f4c7e87fc9 modules/context/auth.go: fix redirect loop (#5965) (#6101)
Closes #5815
2019-02-17 12:51:37 +00:00
zeripath
fe99c9901d Issue 5924 fix compare button (#5929) (#6098)
* Revert #5877

This unfortunately was not the solution.

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Change permission check to create pull requests to CanReadIssuesOrPulls

Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-02-16 20:11:07 +02:00
zeripath
2e1540e827 Recover panic in orgmode.Render if bad orgfile (#4982) (#5903) (#6097)
This PR protects against the panic referred to in chaseadmsio/goorgeous#82
by recovering from the panic and just returning the raw bytes if
there is an error.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-02-16 12:39:52 -05:00
Lauris BH
3b612ce42e Changelog for release v1.7.2 (#6084) 2019-02-15 10:19:51 +02:00
Lauris BH
1d8e56e6bb In basic auth check for tokens before call UserSignIn (#5725) (#6083)
* Check first if user/password is a token

* In basic auth check if user/password is a token

* Remove unnecessary else statement

* Changes of fmt
2019-02-15 10:01:53 +02:00
techknowlogick
57ab65d922 1.7.2 changelog (#6079) 2019-02-15 02:14:00 -05:00
techknowlogick
3ac4a7fab8 Switch to more recent build of xgo (#6070) (#6072) 2019-02-14 13:35:27 -05:00
Lanre Adelowo
253efbcb51 Make sure labels are actually returned (#6053) (#6059) 2019-02-13 17:51:18 +00:00
zeripath
c8f061e15b Create repository on organisation by default on its dashboard (#6026) (#6048)
* Create repository on organisation by default on its dashboard
* Only show owners the add new repositories to an organisation button.

Fix #3253

Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-02-12 22:04:48 -05:00
Paul
7f7c451de4 Fix metrics auth token detection (#6006) (#6017)
Backport of #6006 

Signed-off-by: Pauls Barkans <paulsb@gmail.com>
2019-02-09 14:35:51 +00:00
zeripath
b0b574f805 Fix empty ssh key importing in ldap (#5984) (#6009) 2019-02-09 14:44:53 +02:00
Lunny Xiao
d269179523 fix bug when deleting a linked account will removed all (#5989) (#5990) 2019-02-07 07:11:51 +00:00
zeripath
6416f06508 Fix ssh deploy and user key constraints (#1357) (#5939) (#5966)
Backport of #5939 

1. A key can either be an ssh user key or a deploy key. It cannot be both.
2. If a key is a user key - it can only be associated with one user.
3. If a key is a deploy key - it can be used in multiple repositories and the permissions it has on those repositories can be different.
4. If a repository is deleted, its deploy keys must be deleted too.

We currently don't enforce any of this and multiple repositories access with different permissions doesn't work at all. This PR enforces the following constraints:

- [x] You should not be able to add the same user key as another user
- [x] You should not be able to add a ssh user key which is being used as a deploy key
- [x] You should not be able to add a ssh deploy key which is being used as a user key
- [x] If you add an ssh deploy key to another repository you should be able to use it in different modes without losing the ability to use it in the other mode.
- [x] If you delete a repository you must delete all its deploy keys.

Fix #1357
2019-02-04 21:41:03 +00:00
Lanre Adelowo
1a8ab63dda show user who created the repository instead of the organization in action feed (#5948) (#5956) 2019-02-04 11:20:36 +02:00
Lanre Adelowo
477b4de0d1 handle milestone events for issues and PR (#5947) (#5955)
Backport of #5947
2019-02-04 08:33:56 +00:00
zeripath
849c85a2ec Fix #5866: Silence console logger in gitea serv (#5887) (#5943)
By default, if `setting.NewContext()` prints out any warning logs, these are printed to the stdout breaking `git receive-pack` etc. meaning that even if there is a warning because of a minor problem in your app.ini but gitea starts despite this - you **CANNOT** push or pull over SSH.

This PR disables the console logger whilst in `serv.go`

Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-02-03 13:50:41 -05:00
zeripath
731275247d Fix notifications on pushing with deploy keys by setting hook environment variables (#5935) (#5944)
The gitea prerecieve and postrecieve hooks and the gitea PushUpdate function require that the PusherID and PusherName are real users. Previously, these environment variables were not being set when using a deploy key - the main result being that pushing to empty repositories meant that is_empty status was not changed.

I've also added an integration test to ensure that the is_empty status is updated on pushing with a deploy key.

There is a slight issue in that the deploy key is now considered a proxy for the owner - we don't have a way of separating out the deploy key from the owner at present. This can be fixed in another PR.

Fix #3795 

Signed-off-by: Andrew Thornton art27@cantab.net
2019-02-03 13:04:09 -05:00
John Olheiser
022634aa75 Remove all CommitStatus when a repo is deleted (#5941)
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2019-02-03 00:55:33 -05:00
techknowlogick
dfad569e40 1.7.1 changelog (#5918) 2019-01-31 11:11:25 -05:00
techknowlogick
c3b67ff2f6 Disable redirect for i18n (#5910) (#5916) 2019-01-31 10:07:57 -05:00
Lanre Adelowo
5c30817b5f fix compare button on upstream repo leading to 404 (#5877) (#5914) 2019-01-31 09:55:39 -05:00
Lanre Adelowo
438848a2ca respect value of REQUIRE_SIGNIN_VIEW (#5901) (#5915) 2019-01-31 09:38:01 -05:00
Lunny Xiao
9d4aa78113 Fix bug when read public repo lfs file (#5913)
* fix bug when read public repo lfs file

* add comment on lfs permission check
2019-01-31 13:36:10 +00:00
zeripath
e5af93af20 Only allow local login if password is non-empty (#5906) (#5908) 2019-01-30 23:46:19 +02:00
Lauris BH
3f802a2846 Fix go-get URL generation (#5905) (#5907) 2019-01-30 23:29:44 +02:00
zeripath
0190d3c243 Prevent nil dereference in mailIssueCommentToParticipants (#5891, #5895) (#5894)
* Ensure issue.Poster is loaded in mailIssueCommentToParticipants (#5891)

Previous code could potentially dereference nil - this PR ensures
that the poster is loaded before dereferencing it.

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Also ensure the repo is loaded

Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-01-29 22:44:00 +00:00
Lauris BH
4fe1a3050e When creating new repository fsck option should be enabled (#5817) (#5885) 2019-01-29 09:42:47 +08:00
zeripath
29799537a7 API: Fix null pointer in attempt to Sudo if not logged in (#5872) (#5884)
Backport of #5872 to v1.7

Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-01-28 20:26:55 +00:00
Harshit Bansal
d3a334d99a Fix an error while adding a dependency via UI. (Backport #5862) (#5876)
Fixes: #5783.
2019-01-28 12:51:30 +00:00
yasuokav
28d9305ea3 Fix delete correct temp directory (#5840) 2019-01-25 02:33:15 -05:00
kolaente
8a9f5b3b50 Added docs for the tree api (#5835)
* Added docs for the tree api

* Updated swagger docs

* Added missing response definition

* Updated swagger docs

* Fixed swagger docs
2019-01-24 20:40:54 +02:00
Antoine GIRARD
f28e17473c Backport #5830 : Include Go toolchain to --version (#5832)
* Include Go version

* fix import order
2019-01-24 10:33:28 -05:00
Lauris BH
2c26521579 Request for public keys only if LDAP attribute is set (#5816) (#5819)
* Update go-ldap dependency

* Request for public keys only if attribute is set
2019-01-24 12:21:36 +02:00
Joona Hoikkala
f635041c98 Fix TLS errors when using acme/autocert for local connections (#5820) (#5826) 2019-01-24 09:48:02 +02:00
techknowlogick
3fa49f3780 1.7.0 changelog (#5802) 2019-01-22 21:21:46 +02:00
Lanre Adelowo
4577cddd28 Disallow empty titles (#5785) (#5794)
* add util method and tests

* make sure the title of an issue cannot be empty

* wiki title cannot be empty

* pull request title cannot be empty

* update to make use of the new util methof
2019-01-21 17:55:12 +02:00
techknowlogick
8da5237107 1.7.0-rc3 changelog (#5756) 2019-01-18 01:08:41 -05:00
techknowlogick
8006b1bc7a backport 1.6.4 changelog to 1.7 branch (#5741) 2019-01-16 14:43:06 +02:00
Julian Tölle
8d400320c6 fix: use correct value for "MSpan Structures Obtained" #4742 (#5706) (#5716)
Signed-off-by: Julian Tölle <julian.toelle97@gmail.com>
2019-01-13 16:32:55 +02:00
zeripath
e9c4609410 Do not display the raw OpenID error in the UI (#5705) (#5712)
* Do not display the raw OpenID error in the UI

If there are no `WHITELIST_URIS` or `BLACKLIST_URIS` set in the openid
section of the app.ini, it is possible that gitea can leak sensitive
information about the local network through the error provided by the
UI. This PR hides the error information and logs it.

Fix #4973

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Update auth_openid.go

Place error log within the `err != nil` branch.
2019-01-13 08:05:20 -05:00
Zsombor
176a6048b4 Update xorm to fix issue #5659 and #5651 (#5680) (#5692) 2019-01-10 21:43:29 +02:00
Lunny Xiao
483aa06b07 fix public will not be reused as public key after deleting as deploy key (#5671) (#5684) 2019-01-10 09:23:33 -05:00
zeripath
551dc58a4d When redirecting clean the path to avoid redirecting to //www.othersite.com (#5669) (#5679)
Fix #5627

Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-01-09 17:32:49 -05:00
Julian
41a2bfe3ae Only count users own actions for heatmap contributions (#5647) (#5655)
Signed-off-by: Julian Tölle <julian.toelle97@gmail.com>
2019-01-06 22:16:55 +02:00
Julian
652e09fc3e fix commit page showing status for current default branch (#5650) (#5653)
Signed-off-by: Julian Tölle <julian.toelle97@gmail.com>
2019-01-06 19:11:49 +01:00
Harshit Bansal
c9b57a5135 Don't close issues via commits on non-default branch. (#5622) (#5643)
Adds a small check to close the issues only if the referencing commits
are on the default branch.

Fixes: #2314.
2019-01-05 22:04:02 +02:00
zeripath
2904d8d6aa Fix sqlite deadlock when assigning to a PR (#5640) (#5642)
* Fix sqlite deadlock when assigning to a PR

Fix 5639

Signed-off-by: Andrew Thornton <art27@cantab.net>

* More possible deadlocks found and fixed

Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-01-05 10:18:17 -05:00
Jonas Franz
109fc7975b Add changelog for 1.6.3 and 1.7.0-rc2 (#5638)
Signed-off-by: Jonas Franz <info@jonasfranz.software>
2019-01-04 19:17:32 +01:00
zeripath
3ee3a4b595 SECURITY: protect DeleteFilePost et al with cleanUploadFileName (#5631) (#5635)
This commit wraps more of the TreePaths with cleanUploadFileName

Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-01-04 17:41:30 +01:00
Lauris BH
14e218cbd1 Backport latest translation changes 2019-01-04 11:26:23 +02:00
0x5c
b5f4911afa Documentation: Clarity for HTTPS setups (#5626)
[https-setup]
- Made it clearer that HTTP redirection is possible
[config-cheat-sheet]
- Clarified the behavihour of the redirection-related config keys

Signed-off-by: Matti Ranta <matti@mdranta.net>
2019-01-03 18:53:51 -05:00
8274 changed files with 339242 additions and 1229193 deletions

View File

@@ -1,57 +1,44 @@
# The full repository name
repo: go-gitea/gitea
# Service type (gitea or github)
service: github
# Base URL for Gitea instance if using gitea service type (optional)
# Default: https://gitea.com
base-url:
# Changelog groups and which labeled PRs to add to each group
groups:
-
-
name: BREAKING
labels:
- kind/breaking
-
name: FEATURES
-
name: FEATURE
labels:
- kind/feature
-
name: SECURITY
labels:
- kind/security
-
name: BUGFIXES
labels:
- kind/bug
-
name: ENHANCEMENTS
-
name: ENHANCEMENT
labels:
- kind/enhancement
- kind/refactor
- kind/ui
-
name: SECURITY
labels:
- kind/security
-
name: TESTING
labels:
- kind/testing
-
-
name: TRANSLATION
labels:
- kind/translation
-
-
name: BUILD
labels:
- kind/build
- kind/lint
-
-
name: DOCS
labels:
- kind/docs
-
-
name: MISC
default: true
# regex indicating which labels to skip for the changelog
skip-labels: skip-changelog|backport\/.+
default: true

1166
.drone.yml

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +1,31 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
[*.md]
trim_trailing_whitespace = false
[*.go]
indent_style = tab
indent_size = 8
[*.{go,tmpl,html}]
[*.{tmpl,html}]
indent_style = tab
indent_size = 4
[*.{less,css}]
[*.{less}]
indent_style = space
indent_size = 4
[*.{js,json,yml}]
[*.{yml}]
indent_style = space
indent_size = 2
[*.js]
indent_style = space
indent_size = 4
[Makefile]
indent_style = tab

View File

@@ -1,74 +0,0 @@
root: true
extends:
- eslint-config-airbnb-base
- eslint:recommended
ignorePatterns:
- /web_src/js/vendor
parserOptions:
ecmaVersion: 2020
env:
browser: true
es6: true
jquery: true
node: true
globals:
__webpack_public_path__: true
CodeMirror: false
Dropzone: false
SimpleMDE: false
u2fApi: false
Tribute: false
overrides:
- files: ["web_src/**/*worker.js"]
env:
worker: true
rules:
no-restricted-globals: [0]
rules:
arrow-body-style: [0]
arrow-parens: [2, always]
camelcase: [0]
comma-dangle: [2, only-multiline]
consistent-return: [0]
default-case: [0]
func-names: [0]
import/extensions: [2, always, {ignorePackages: true}]
import/prefer-default-export: [0]
max-len: [0]
multiline-comment-style: [2, separate-lines]
newline-per-chained-call: [0]
no-alert: [0]
no-cond-assign: [2, except-parens]
no-console: [1, {allow: [info, warn, error]}]
no-continue: [0]
no-empty: [2, {allowEmptyCatch: true}]
no-eq-null: [2]
no-mixed-operators: [0]
no-multi-assign: [0]
no-new: [0]
no-param-reassign: [0]
no-plusplus: [0]
no-restricted-syntax: [0]
no-return-await: [0]
no-shadow: [0]
no-underscore-dangle: [0]
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}]
no-use-before-define: [0]
no-var: [2]
object-curly-newline: [0]
object-curly-spacing: [2, never]
one-var-declaration-per-line: [0]
one-var: [0]
operator-linebreak: [2, after]
prefer-const: [2, {destructuring: all}]
prefer-destructuring: [0]
quotes: [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
radix: [2, as-needed]
semi: [2, always, {omitLastInOneLineBlock: true}]

8
.gitattributes vendored
View File

@@ -1,10 +1,6 @@
* text=auto eol=lf
/vendor/** -text -eol
/public/vendor/** -text -eol
conf/* linguist-vendored
docker/* linguist-vendored
options/* linguist-vendored
public/* linguist-vendored
build/* linguist-vendored
templates/* linguist-vendored
scripts/* linguist-vendored
templates/* linguist-vendored

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
open_collective: gitea

View File

@@ -1,9 +1,7 @@
<!-- NOTE: If your issue is a security concern, please send an email to security@gitea.io instead of opening a public issue -->
<!--
1. Please speak English, this is the language all maintainers can speak and write.
1. Please speak English, this is the language all of us can speak and write.
2. Please ask questions or configuration/deploy problems on our Discord
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
server (https://discord.gg/NsatcWJ) or forum (https://discourse.gitea.io).
3. Please take a moment to check that your issue doesn't already exist.
4. Please give all relevant information below for bug reports, because
incomplete details will be handled as an invalid report.

10
.github/stale.yml vendored
View File

@@ -27,11 +27,9 @@ staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had recent activity.
I am here to help clear issues left open even if solved or waiting for more insight.
This issue will be closed if no further activity occurs during the next 2 weeks.
If the issue is still valid just add a comment to keep it alive.
Thank you for your contributions.
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs during the next 2 weeks. Thank you
for your contributions.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
@@ -44,7 +42,6 @@ limitPerRun: 1
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
pulls:
daysUntilStale: 60
daysUntilClose: 60
markComment: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs during the next 2 months. Thank you
@@ -52,3 +49,4 @@ pulls:
closeComment: >
This pull request has been automatically closed because of inactivity.
You can re-open it if needed.

27
.gitignore vendored
View File

@@ -12,7 +12,6 @@ _test
# MS VSCode
.vscode
__debug_bin
# Architecture specific extensions/prefixes
*.[568vq]
@@ -34,54 +33,36 @@ _testmain.go
coverage.all
/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.ini.sample
/custom
/data
/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
/node_modules
/yarn.lock
/public/js
/public/serviceworker.js
/public/css
/public/fonts
/public/fomantic
/public/img/svg
/VERSION
# Snapcraft
snap/.snapcraft/
@@ -91,7 +72,3 @@ prime/
*.snap
*.snap-build
*_source.tar.bz2
.DS_Store
# Make evidence files
/.make_evidence

View File

@@ -1,100 +0,0 @@
linters:
enable:
- gosimple
- deadcode
- typecheck
- govet
- errcheck
- staticcheck
- unused
- structcheck
- varcheck
- golint
- dupl
#- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- misspell
- gocritic
enable-all: false
disable-all: true
fast: false
run:
timeout: 3m
linters-settings:
gocritic:
disabled-checks:
- ifElseChain
- singleCaseSwitch # Every time this occured in the code, there was no other way.
issues:
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- gocyclo
- errcheck
- dupl
- gosec
- unparam
- staticcheck
- path: models/migrations/v
linters:
- gocyclo
- errcheck
- dupl
- gosec
- linters:
- dupl
text: "webhook"
- linters:
- gocritic
text: "`ID' should not be capitalized"
- path: modules/templates/helper.go
linters:
- gocritic
- linters:
- unused
- deadcode
text: "swagger"
- path: contrib/pr/checkout.go
linters:
- errcheck
- path: models/issue.go
linters:
- errcheck
- path: models/migrations/
linters:
- errcheck
- path: modules/log/
linters:
- errcheck
- path: routers/routes/routes.go
linters:
- dupl
- path: routers/api/v1/repo/issue_subscription.go
linters:
- dupl
- path: routers/repo/view.go
linters:
- dupl
- path: models/migrations/
linters:
- unused
- linters:
- staticcheck
text: "argument x is overwritten before first use"
- path: modules/httplib/httplib.go
linters:
- staticcheck
# Enabling this would require refactoring the methods and how they are called.
- path: models/issue_comment_list.go
linters:
- dupl
- linters:
- misspell
text: '`Unknwon` is a misspelling of `Unknown`'
- path: models/update.go
linters:
- unused

View File

@@ -1,6 +0,0 @@
/vendor
/public/vendor/plugins
/public/vendor/assets
/modules/options/bindata.go
/modules/public/bindata.go
/modules/templates/bindata.go

2
.npmrc
View File

@@ -1,2 +0,0 @@
package-lock=true
save-exact=true

View File

@@ -1,16 +0,0 @@
extends: stylelint-config-standard
ignoreFiles:
- web_src/less/vendor/**/*
rules:
at-rule-empty-line-before: null
block-closing-brace-empty-line-before: null
color-hex-length: null
comment-empty-line-before: null
declaration-empty-line-before: null
indentation: 4
no-descending-specificity: null
number-leading-zero: never
rule-empty-line-before: null
selector-pseudo-element-colon-notation: null

File diff suppressed because it is too large Load Diff

View File

@@ -11,9 +11,7 @@
- [Translation](#translation)
- [Code review](#code-review)
- [Styleguide](#styleguide)
- [Design guideline](#design-guideline)
- [API v1](#api-v1)
- [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
- [Sign-off your work](#sign-off-your-work)
- [Release Cycle](#release-cycle)
- [Maintainers](#maintainers)
- [Owners](#owners)
@@ -66,31 +64,20 @@ high-level discussions.
## Testing redux
Before submitting a pull request, run all the tests for the whole tree
to make sure your changes don't cause regression elsewhere.
Here's how to run the test suite:
- code lint
| | |
| :-------------------- | :---------------------------------------------------------------- |
|``make lint`` | lint everything (not suggest if you only change one type code) |
|``make lint-frontend`` | lint frontend files |
|``make lint-backend`` | lint backend files |
- run test code (Suggest run in linux)
| | |
| :------------------------------------- | :----------------------------------------------- |
|``make test[\#TestSpecificName]`` | run unit test |
|``make test-sqlite[\#TestSpecificName]``| run [integration](integrations) test for sqlite |
|[More detail message about integrations](integrations/README.md) |
Before sending code out for review, run all the tests for the
whole tree to make sure the changes don't break other usage
and keep the compatibility on upgrade. To make sure you are
running the test suite exactly like we do, you should install
the CLI for [Drone CI](https://github.com/drone/drone), as
we are using the server for continuous testing, following [these
instructions](http://docs.drone.io/cli-installation/). After that,
you can simply call `drone exec --local --build-event "pull_request"` within
your working directory and it will try to run the test suite locally.
## Vendoring
We keep a cached copy of dependencies within the `vendor/` directory,
managing updates via [Modules](https://golang.org/cmd/go/#hdr-Module_maintenance).
managing updates via [dep](https://github.com/golang/dep).
Pull requests should only include `vendor/` updates if they are part of
the same change, be it a bugfix or a feature addition.
@@ -99,7 +86,7 @@ The `vendor/` update needs to be justified as part of the PR description,
and must be verified by the reviewers and/or merger to always reference
an existing upstream commit.
You can find more information on how to get started with it on the [Modules Wiki](https://github.com/golang/go/wiki/Modules).
You can find more information on how to get started with it on the [dep project website](https://golang.github.io/dep/docs/introduction.html).
## Translation
@@ -112,7 +99,13 @@ included in the next released version.
## Building Gitea
See the [hacking instructions](https://docs.gitea.io/en-us/hacking-on-gitea/).
Generally, the go build tools are installed as-needed in the `Makefile`.
An exception are the tools to build the CSS and images.
- To build CSS: Install [Node.js](https://nodejs.org/en/download/package-manager)
with `npm` and then run `npm install` and `make generate-stylesheets`.
- To build Images: ImageMagick, inkscape and zopflipng binaries must be
available in your `PATH` to run `make generate-images`.
## Code review
@@ -153,74 +146,22 @@ import (
)
```
## Design guideline
## Sign-off your work
To maintain understandable code and avoid circular dependencies it is important to have a good structure of the code. The gitea code is divided into the following parts:
- **integration:** Integrations tests
- **models:** Contains the data structures used by xorm to construct database tables. It also contains supporting functions to query and update the database. Dependecies to other code in Gitea should be avoided although some modules might be needed (for example for logging).
- **models/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.
- **public:** Frontend files (javascript, images, css, etc.)
- **routers:** Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) shall not depend on routers
- **services:** Support functions for common routing operations. Uses models and modules to handle the request.
- **templates:** Golang templates for generating the html output.
- **vendor:** External code that Gitea depends on.
## API v1
The API is documented by [swagger](http://try.gitea.io/api/swagger) and is based on [GitHub API v3](https://developer.github.com/v3/).
Thus, Gitea´s API should use the same endpoints and fields as GitHub´s API as far as possible, unless there are good reasons to deviate.
If Gitea provides functionality that GitHub does not, a new endpoint can be created.
If information is provided by Gitea that is not provided by the GitHub API, a new field can be used that doesn't collide with any GitHub fields.
Updating an existing API should not remove existing fields unless there is a really good reason to do so.
The same applies to status responses. If you notice a problem, feel free to leave a comment in the code for future refactoring to APIv2 (which is currently not planned).
All expected results (errors, success, fail messages) should be documented
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L319-L327)).
All JSON input types must be defined as a struct in `models/structs/`
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L76-L91))
and referenced in
[routers/api/v1/swagger/options.go](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/options.go).
They can then be used like the following:
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L318)).
All JSON responses must be defined as a struct in `models/structs/`
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L36-L68))
and referenced in its category in `routers/api/v1/swagger/`
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/issue.go#L11-L16))
They can be used like the following:
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L277-L279))
In general, HTTP methods are chosen as follows:
* **GET** endpoints return requested object and status **OK (200)**
* **DELETE** endpoints return status **No Content (204)**
* **POST** endpoints return status **Created (201)**, used to **create** new objects (e.g. a User)
* **PUT** endpoints return status **No Content (204)**, used to **add/assign** existing Obejcts (e.g. User) to something (e.g. Org-Team)
* **PATCH** endpoints return changed object and status **OK (200)**, used to **edit/change** an existing object
An endpoint which changes/edits an object expects all fields to be optional (except ones to identify the object, which are required).
## Developer Certificate of Origin (DCO)
We consider the act of contributing to the code by submitting a Pull
Request as the "Sign off" or agreement to the certifications and terms
of the [DCO](DCO) and [MIT license](LICENSE). No further action is required.
Additionally you could add a line at the end of your commit message.
The sign-off is a simple line at the end of the explanation for the
patch. Your signature certifies that you wrote the patch or otherwise
have the right to pass it on as an open-source patch. The rules are
pretty simple: If you can certify [DCO](DCO), then you just add a line
to every git commit message:
```
Signed-off-by: Joe Smith <joe.smith@email.com>
```
If you set your `user.name` and `user.email` git configs, you can add the
line to the end of your commit automatically with `git commit -s`.
We assume in good faith that the information you provide is legally binding.
Please use your real name; we really dislike pseudonyms or anonymous
contributions. We are in the open-source world without secrets. If you
set your `user.name` and `user.email` git configs, you can sign-off your
commit automatically with `git commit -s`.
## Release Cycle
@@ -262,7 +203,7 @@ to the maintainers team. If a maintainer is inactive for more than 3
months and forgets to leave the maintainers team, the owners may move
him or her from the maintainers team to the advisors team.
For security reasons, Maintainers should use 2FA for their accounts and
if possible provide gpg signed commits.
if possible provide gpg signed commits.
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
https://help.github.com/articles/signing-commits-with-gpg/
@@ -306,12 +247,7 @@ they served:
* 2019-01-01 ~ 2019-12-31
* [Lunny Xiao](https://github.com/lunny) <xiaolunwen@gmail.com>
* [Lauris Bukšis-Haberkorns](https://github.com/lafriks) <lauris@nix.lv>
* [Matti Ranta](https://github.com/techknowlogick) <techknowlogick@gitea.io>
* 2020-01-01 ~ 2020-12-31
* [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
* [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) <lauris@nix.lv>
* [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.io>
* [Matti Ranta](https://github.com/techknowlogick) <matti@mdranta.net>
## Versions
@@ -334,17 +270,17 @@ be reviewed by two maintainers and must pass the automatic tests.
* Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`.
* When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin`
* If it is bugfix version create PR for changelog on branch `release/v$vmaj.$vmin` and wait till it is reviewed and merged.
* Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`.
* Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`.
* And then push the tag as `git push origin v$vmaj.$vmin.$`. Drone CI will automatically created a release and upload all the compiled binary. (But currently it didn't add the release notes automatically. Maybe we should fix that.)
* If needed send PR for changelog on branch `master`.
* Send PR to [blog repository](https://gitea.com/gitea/blog) announcing the release.
* Send PR to [blog repository](https://github.com/go-gitea/blog) announcing the release.
## Copyright
Code that you contribute should use the standard copyright header:
```
// Copyright 2020 The Gitea Authors. All rights reserved.
// 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.
```

View File

@@ -1,18 +1,14 @@
###################################
#Build stage
FROM golang:1.14-alpine3.11 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}
FROM golang:1.11-alpine3.8 AS build-env
ARG GITEA_VERSION
ARG TAGS="sqlite sqlite_unlock_notify"
ENV TAGS "bindata $TAGS"
ARG CGO_EXTRA_CFLAGS
#Build deps
RUN apk --no-cache add build-base git nodejs npm
RUN apk --no-cache add build-base git
#Setup repo
COPY . ${GOPATH}/src/code.gitea.io/gitea
@@ -20,9 +16,9 @@ WORKDIR ${GOPATH}/src/code.gitea.io/gitea
#Checkout version if set
RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
&& make clean-all build
&& make clean generate build
FROM alpine:3.11
FROM alpine:3.8
LABEL maintainer="maintainers@gitea.io"
EXPOSE 22 3000
@@ -38,8 +34,7 @@ RUN apk --no-cache add \
s6 \
sqlite \
su-exec \
tzdata \
gnupg
tzdata
RUN addgroup \
-S -g 1000 \
@@ -61,6 +56,6 @@ VOLUME ["/data"]
ENTRYPOINT ["/usr/bin/entrypoint"]
CMD ["/bin/s6-svscan", "/etc/s6"]
COPY docker/root /
COPY docker /
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
RUN ln -s /app/gitea/gitea /usr/local/bin/gitea

1223
Gopkg.lock generated Normal file

File diff suppressed because it is too large Load Diff

122
Gopkg.toml Normal file
View File

@@ -0,0 +1,122 @@
ignored = ["google.golang.org/appengine*"]
[prune]
go-tests = true
unused-packages = true
non-go = true
[[constraint]]
branch = "master"
name = "code.gitea.io/git"
[[constraint]]
branch = "master"
name = "code.gitea.io/sdk"
[[constraint]]
# branch = "master"
revision = "c74e08f039e56cef576e4336382b2a2d12d9e026"
name = "github.com/blevesearch/bleve"
#Not targetting v0.7.0 since standard where use only just after this tag
[[constraint]]
revision = "12dd70caea0268ac0d6c2707d0611ef601e7c64e"
name = "golang.org/x/crypto"
[[constraint]]
branch = "master"
name = "golang.org/x/sys"
[[constraint]]
revision = "2bf8f2a19ec09c670e931282edfe6567f6be21c9"
name = "golang.org/x/text"
[[constraint]]
branch = "master"
name = "golang.org/x/net"
[[override]]
name = "github.com/go-xorm/xorm"
revision = "1cd2662be938bfee0e34af92fe448513e0560fb1"
[[override]]
name = "github.com/go-xorm/builder"
version = "0.3.3"
[[override]]
name = "github.com/go-sql-driver/mysql"
revision = "d523deb1b23d913de5bdada721a6071e71283618"
[[override]]
name = "github.com/mattn/go-sqlite3"
revision = "c7c4067b79cc51e6dfdcef5c702e74b1e0fa7c75"
[[override]]
name = "github.com/gorilla/mux"
revision = "757bef944d0f21880861c2dd9c871ca543023cba"
[[constraint]]
name = "github.com/gorilla/context"
version = "1.1.1"
[[constraint]]
name = "github.com/lafriks/xormstore"
version = "1.0.0"
[[constraint]]
branch = "master"
name = "github.com/lunny/dingtalk_webhook"
[[constraint]]
name = "github.com/markbates/goth"
version = "1.47.2"
[[constraint]]
branch = "master"
name = "github.com/mcuadros/go-version"
[[constraint]]
branch = "master"
name = "github.com/russross/blackfriday"
[[constraint]]
branch = "master"
name = "github.com/tstranex/u2f"
[[constraint]]
name = "gopkg.in/editorconfig/editorconfig-core-go.v1"
version = "1.2.0"
[[constraint]]
branch = "v2"
name = "gopkg.in/gomail.v2"
[[constraint]]
name = "gopkg.in/ini.v1"
version = "1.31.1"
[[constraint]]
name = "gopkg.in/ldap.v3"
version = "3.0.1"
[[constraint]]
name = "gopkg.in/macaron.v1"
version = "1.2.4"
[[constraint]]
name = "gopkg.in/testfixtures.v2"
version = "2.0.0"
[[override]]
name = "github.com/boltdb/bolt"
revision = "ccd680d8c1a0179ac3d68f692b01e1a1589cbfc7"
source = "github.com/go-gitea/bolt"
[[override]]
branch = "master"
name = "golang.org/x/oauth2"
[[constraint]]
name = "github.com/prometheus/client_golang"
version = "0.9.0"

View File

@@ -19,20 +19,10 @@ Lauris Bukšis-Haberkorns <lauris@nix.lv> (@lafriks)
Jonas Östanbäck <jonas.ostanback@gmail.com> (@cez81)
David Schneiderbauer <dschneiderbauer@gmail.com> (@daviian)
Peter Žeby <morlinest@gmail.com> (@morlinest)
Matti Ranta <techknowlogick@gitea.io> (@techknowlogick)
Matti Ranta <matti@mdranta.net> (@techknowlogick)
Jonas Franz <info@jonasfranz.software> (@jonasfranz)
Alexey Terentyev <axifnx@gmail.com> (@axifive)
Lanre Adelowo <yo@lanre.wtf> (@adelowo)
Konrad Langenberg <k@knt.li> (@kolaente)
He-Long Zhang <outman99@hotmail.com> (@BetaCat0)
Andrew Thornton <art27@cantab.net> (@zeripath)
John Olheiser <john.olheiser@gmail.com> (@jolheiser)
Richard Mahn <rich.mahn@unfoldingword.org> (@richmahn)
Mrsdizzie <info@mrsdizzie.com> (@mrsdizzie)
silverwind <me@silverwind.io> (@silverwind)
Gary Kim <gary@garykim.dev> (@gary-kim)
Guillermo Prandi <gitea.maint@mailfilter.com.ar> (@guillep2k)
Mura Li <typeless@ctli.io> (@typeless)
6543 <6543@obermui.de> (@6543)
jaqra <jaqra@hotmail.com> (@jaqra)
David Svantesson <davidsvantesson@gmail.com> (@davidsvantesson)

573
Makefile
View File

@@ -1,239 +1,109 @@
ifeq ($(USE_REPO_TEST_DIR),1)
# This rule replaces the whole Makefile when we're trying to use /tmp repository temporary files
location = $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
self := $(location)
%:
@tmpdir=`mktemp --tmpdir -d` ; \
echo Using temporary directory $$tmpdir for test repositories ; \
USE_REPO_TEST_DIR= $(MAKE) -f $(self) --no-print-directory REPO_TEST_DIR=$$tmpdir/ $@ ; \
STATUS=$$? ; rm -r "$$tmpdir" ; exit $$STATUS
else
# This is the "normal" part of the Makefile
DIST := dist
DIST_DIRS := $(DIST)/binaries $(DIST)/release
IMPORT := code.gitea.io/gitea
export GO111MODULE=on
GO ?= go
SED_INPLACE := sed -i
SHASUM ?= shasum -a 256
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
COMMA := ,
XGO_VERSION := go-1.14.x
MIN_GO_VERSION := 001012000
MIN_NODE_VERSION := 010013000
ifeq ($(HAS_GO), GO)
GOPATH ?= $(shell $(GO) env GOPATH)
export PATH := $(GOPATH)/bin:$(PATH)
CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
endif
ifeq ($(OS), Windows_NT)
EXECUTABLE ?= gitea.exe
EXECUTABLE := gitea.exe
else
EXECUTABLE ?= gitea
EXECUTABLE := gitea
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
SED_INPLACE := sed -i ''
endif
ifeq ($(UNAME_S),FreeBSD)
SED_INPLACE := sed -i ''
endif
endif
BINDATA := modules/{options,public,templates}/bindata.go
GOFILES := $(shell find . -name "*.go" -type f ! -path "./vendor/*" ! -path "*/bindata.go")
GOFMT ?= gofmt -s
GOFLAGS := -v
GOFLAGS := -i -v
EXTRA_GOFLAGS ?=
MAKE_VERSION := $(shell $(MAKE) -v | head -n 1)
MAKE_EVIDENCE_DIR := .make_evidence
ifneq ($(RACE_ENABLED),)
GOTESTFLAGS ?= -race
endif
STORED_VERSION_FILE := VERSION
ifneq ($(DRONE_TAG),)
VERSION ?= $(subst v,,$(DRONE_TAG))
GITEA_VERSION ?= $(VERSION)
GITEA_VERSION := $(VERSION)
else
ifneq ($(DRONE_BRANCH),)
VERSION ?= $(subst release/v,,$(DRONE_BRANCH))
else
VERSION ?= master
endif
STORED_VERSION=$(shell cat $(STORED_VERSION_FILE) 2>/dev/null)
ifneq ($(STORED_VERSION),)
GITEA_VERSION ?= $(STORED_VERSION)
else
GITEA_VERSION ?= $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')
endif
GITEA_VERSION := $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')
endif
LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
LDFLAGS := -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/integrations/migration-test,$(filter-out code.gitea.io/gitea/integrations,$(shell $(GO) list -mod=vendor ./... | grep -v /vendor/)))
WEBPACK_SOURCES := $(shell find web_src/js web_src/less -type f)
WEBPACK_CONFIGS := webpack.config.js
WEBPACK_DEST := public/js/index.js public/css/index.css
WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/serviceworker.js
BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
PACKAGES ?= $(filter-out code.gitea.io/gitea/integrations,$(shell $(GO) list ./... | grep -v /vendor/))
SOURCES ?= $(shell find . -name "*.go" -type f)
TAGS ?=
TAGS_SPLIT := $(subst $(COMMA), ,$(TAGS))
TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags
GO_DIRS := cmd integrations models modules routers build services vendor
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)
TMPDIR := $(shell mktemp -d 2>/dev/null || mktemp -d -t 'gitea-temp')
ifeq ($(filter $(TAGS_SPLIT),bindata),bindata)
GO_SOURCES += $(BINDATA_DEST)
endif
GO_SOURCES_OWN := $(filter-out vendor/% %/bindata.go, $(GO_SOURCES))
FOMANTIC_CONFIGS := semantic.json web_src/fomantic/theme.config.less web_src/fomantic/_site/globals/site.variables web_src/fomantic/css.js
FOMANTIC_DEST := public/fomantic/semantic.min.js public/fomantic/semantic.min.css
FOMANTIC_DEST_DIR := public/fomantic
#To update swagger use: GO111MODULE=on go get -u github.com/go-swagger/go-swagger/cmd/swagger@v0.20.1
SWAGGER := $(GO) run -mod=vendor github.com/go-swagger/go-swagger/cmd/swagger
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl}}/api/v1"|g
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl}}/api/v1"|"basePath": "/api/v1"|g
SWAGGER_NEWLINE_COMMAND := -e '$$a\'
SWAGGER_SPEC_S_TMPL := s|"basePath":\s*"/api/v1"|"basePath": "{{AppSubUrl}}/api/v1"|g
SWAGGER_SPEC_S_JSON := s|"basePath":\s*"{{AppSubUrl}}/api/v1"|"basePath": "/api/v1"|g
TEST_MYSQL_HOST ?= mysql:3306
TEST_MYSQL_DBNAME ?= testgitea
TEST_MYSQL_USERNAME ?= root
TEST_MYSQL_PASSWORD ?=
TEST_MYSQL8_HOST ?= mysql8:3306
TEST_MYSQL8_DBNAME ?= testgitea
TEST_MYSQL8_USERNAME ?= root
TEST_MYSQL8_PASSWORD ?=
TEST_PGSQL_HOST ?= pgsql:5432
TEST_PGSQL_DBNAME ?= testgitea
TEST_PGSQL_USERNAME ?= postgres
TEST_PGSQL_PASSWORD ?= postgres
TEST_PGSQL_SCHEMA ?= gtestschema
TEST_MSSQL_HOST ?= mssql:1433
TEST_MSSQL_DBNAME ?= gitea
TEST_MSSQL_USERNAME ?= sa
TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
ifeq ($(OS), Windows_NT)
EXECUTABLE := gitea.exe
else
EXECUTABLE := gitea
endif
# $(call strip-suffix,filename)
strip-suffix = $(firstword $(subst ., ,$(1)))
.PHONY: all
all: build
include docker/Makefile
.PHONY: help
help:
@echo "Make Routines:"
@echo " - \"\" equivalent to \"build\""
@echo " - build build everything"
@echo " - frontend build frontend files"
@echo " - backend build backend files"
@echo " - clean delete backend and integration files"
@echo " - clean-all delete backend, frontend and integration files"
@echo " - lint lint everything"
@echo " - lint-frontend lint frontend files"
@echo " - lint-backend lint backend files"
@echo " - watch-frontend watch frontend files and continuously rebuild"
@echo " - webpack build webpack files"
@echo " - fomantic build fomantic files"
@echo " - generate run \"go generate\""
@echo " - fmt format the Go code"
@echo " - generate-swagger generate the swagger spec from code comments"
@echo " - swagger-validate check if the swagger spec is valid"
@echo " - golangci-lint run golangci-lint linter"
@echo " - revive run revive linter"
@echo " - misspell check for misspellings"
@echo " - vet examines Go source code and reports suspicious constructs"
@echo " - test[\#TestSpecificName] run unit test"
@echo " - test-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:
$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell go version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
@if [ "$(GO_VERSION)" -lt "$(MIN_GO_VERSION)" ]; then \
echo "Gitea requires Go 1.12 or greater to build. You can get it at https://golang.org/dl/"; \
exit 1; \
fi
.PHONY: git-check
git-check:
@if git lfs >/dev/null 2>&1 ; then : ; else \
echo "Gitea requires git with lfs support to run tests." ; \
exit 1; \
fi
.PHONY: node-check
node-check:
$(eval NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell node -v | cut -c2- | tr '.' ' ');))
$(eval NPM_MISSING := $(shell hash npm > /dev/null 2>&1 || echo 1))
@if [ "$(NODE_VERSION)" -lt "$(MIN_NODE_VERSION)" -o "$(NPM_MISSING)" = "1" ]; then \
echo "Gitea requires Node.js 10 or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \
exit 1; \
fi
.PHONY: clean-all
clean-all: clean
rm -rf $(WEBPACK_DEST_ENTRIES) $(FOMANTIC_DEST_DIR)
.PHONY: clean
clean:
$(GO) clean -i ./...
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA) \
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
integrations/gitea-integration-pgsql/ integrations/gitea-integration-mysql/ integrations/gitea-integration-sqlite/ integrations/gitea-integration-mssql/ \
integrations/indexers-mysql/ integrations/indexers-pgsql integrations/indexers-sqlite integrations/indexers-mssql \
integrations/mysql.ini integrations/pgsql.ini integrations/mssql.ini
.PHONY: fmt
fmt:
$(GOFMT) -w $(GO_SOURCES_OWN)
$(GOFMT) -w $(GOFILES)
.PHONY: vet
vet:
# Default vet
$(GO) vet $(GO_PACKAGES)
# Custom vet
$(GO) build -mod=vendor gitea.com/jolheiser/gitea-vet
$(GO) vet -vettool=gitea-vet $(GO_PACKAGES)
$(GO) vet $(PACKAGES)
.PHONY: $(TAGS_EVIDENCE)
$(TAGS_EVIDENCE):
@mkdir -p $(MAKE_EVIDENCE_DIR)
@echo "$(TAGS)" > $(TAGS_EVIDENCE)
ifneq "$(TAGS)" "$(shell cat $(TAGS_EVIDENCE) 2>/dev/null)"
TAGS_PREREQ := $(TAGS_EVIDENCE)
endif
.PHONY: generate
generate:
@hash go-bindata > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/jteeuwen/go-bindata/go-bindata; \
fi
$(GO) generate $(PACKAGES)
.PHONY: generate-swagger
generate-swagger:
$(SWAGGER) generate spec -o './$(SWAGGER_SPEC)'
@hash swagger > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/go-swagger/go-swagger/cmd/swagger; \
fi
swagger generate spec -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
@@ -246,92 +116,72 @@ swagger-check: generate-swagger
.PHONY: swagger-validate
swagger-validate:
@hash swagger > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/go-swagger/go-swagger/cmd/swagger; \
fi
$(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)'
$(SWAGGER) validate './$(SWAGGER_SPEC)'
swagger validate './$(SWAGGER_SPEC)'
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
.PHONY: errcheck
errcheck:
@hash errcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
GO111MODULE=off $(GO) get -u github.com/kisielk/errcheck; \
$(GO) get -u github.com/kisielk/errcheck; \
fi
errcheck $(GO_PACKAGES)
errcheck $(PACKAGES)
.PHONY: revive
revive:
GO111MODULE=on $(GO) run -mod=vendor build/lint.go -config .revive.toml -exclude=./vendor/... ./... || exit 1
.PHONY: lint
lint:
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/mgechev/revive; \
fi
revive -config .revive.toml -exclude=./vendor/... ./... || exit 1
.PHONY: misspell-check
misspell-check:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
GO111MODULE=off $(GO) get -u github.com/client9/misspell/cmd/misspell; \
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -error -i unknwon,destory $(GO_SOURCES_OWN)
misspell -error -i unknwon $(GOFILES)
.PHONY: misspell
misspell:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
GO111MODULE=off $(GO) get -u github.com/client9/misspell/cmd/misspell; \
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -w -i unknwon $(GO_SOURCES_OWN)
misspell -w -i unknwon $(GOFILES)
.PHONY: fmt-check
fmt-check:
# get all go files and run go fmt on them
@diff=$$($(GOFMT) -d $(GO_SOURCES_OWN)); \
@diff=$$($(GOFMT) -d $(GOFILES)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
.PHONY: lint
lint: lint-backend lint-frontend
.PHONY: lint-backend
lint-backend: golangci-lint revive vet swagger-check swagger-validate test-vendor
.PHONY: lint-frontend
lint-frontend: node_modules
npx eslint web_src/js webpack.config.js
npx stylelint web_src/less
.PHONY: watch-frontend
watch-frontend: node_modules
rm -rf $(WEBPACK_DEST_ENTRIES)
NODE_ENV=development npx webpack --hide-modules --display-entrypoints=false --watch --progress
.PHONY: test
test:
$(GO) test $(GOTESTFLAGS) -mod=vendor -tags='sqlite sqlite_unlock_notify' $(GO_PACKAGES)
.PHONY: test-check
test-check:
@echo "Checking if tests have changed the source tree...";
@diff=$$(git status -s); \
if [ -n "$$diff" ]; then \
echo "make test has changed files in the source tree:"; \
echo "$${diff}"; \
echo "You should change the tests to create these files in a temporary directory."; \
echo "Do not simply add these files to .gitignore"; \
exit 1; \
fi;
.PHONY: test\#%
test\#%:
$(GO) test -mod=vendor -tags='sqlite sqlite_unlock_notify' -run $(subst .,/,$*) $(GO_PACKAGES)
$(GO) test -tags='sqlite sqlite_unlock_notify' $(PACKAGES)
.PHONY: coverage
coverage:
GO111MODULE=on $(GO) run -mod=vendor build/gocovmerge.go integration.coverage.out $(shell find . -type f -name "coverage.out") > coverage.all
@hash gocovmerge > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/wadey/gocovmerge; \
fi
gocovmerge integration.coverage.out $(shell find . -type f -name "coverage.out") > coverage.all;\
.PHONY: unit-test-coverage
unit-test-coverage:
$(GO) test $(GOTESTFLAGS) -mod=vendor -tags='sqlite sqlite_unlock_notify' -cover -coverprofile coverage.out $(GO_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
for PKG in $(PACKAGES); do $(GO) test -tags='sqlite sqlite_unlock_notify' -cover -coverprofile $$GOPATH/src/$$PKG/coverage.out $$PKG || exit 1; done;
.PHONY: vendor
vendor:
$(GO) mod tidy && $(GO) mod vendor
@hash dep > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/golang/dep/cmd/dep; \
fi
dep ensure -vendor-only
.PHONY: test-vendor
test-vendor: vendor
@@ -341,270 +191,160 @@ test-vendor: vendor
echo "$${diff}"; \
exit 1; \
fi;
generate-ini-sqlite:
sed -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
integrations/sqlite.ini.tmpl > integrations/sqlite.ini
#TODO add dep status -missing when implemented
.PHONY: test-sqlite
test-sqlite: integrations.sqlite.test generate-ini-sqlite
test-sqlite: integrations.sqlite.test
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test
.PHONY: test-sqlite\#%
test-sqlite\#%: integrations.sqlite.test generate-ini-sqlite
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*)
.PHONY: test-sqlite-migration
test-sqlite-migration: migrations.sqlite.test generate-ini-sqlite
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./migrations.sqlite.test
generate-ini-mysql:
generate-ini:
sed -e 's|{{TEST_MYSQL_HOST}}|${TEST_MYSQL_HOST}|g' \
-e 's|{{TEST_MYSQL_DBNAME}}|${TEST_MYSQL_DBNAME}|g' \
-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
.PHONY: test-mysql
test-mysql: integrations.mysql.test generate-ini-mysql
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./integrations.mysql.test
.PHONY: test-mysql\#%
test-mysql\#%: integrations.mysql.test generate-ini-mysql
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*)
.PHONY: test-mysql-migration
test-mysql-migration: migrations.mysql.test generate-ini-mysql
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./migrations.mysql.test
generate-ini-mysql8:
sed -e 's|{{TEST_MYSQL8_HOST}}|${TEST_MYSQL8_HOST}|g' \
-e 's|{{TEST_MYSQL8_DBNAME}}|${TEST_MYSQL8_DBNAME}|g' \
-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
.PHONY: test-mysql8
test-mysql8: integrations.mysql8.test generate-ini-mysql8
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql8.ini ./integrations.mysql8.test
.PHONY: test-mysql8\#%
test-mysql8\#%: integrations.mysql8.test generate-ini-mysql8
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql8.ini ./integrations.mysql8.test -test.run $(subst .,/,$*)
.PHONY: test-mysql8-migration
test-mysql8-migration: migrations.mysql8.test generate-ini-mysql8
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql8.ini ./migrations.mysql8.test
generate-ini-pgsql:
sed -e 's|{{TEST_PGSQL_HOST}}|${TEST_PGSQL_HOST}|g' \
-e 's|{{TEST_PGSQL_DBNAME}}|${TEST_PGSQL_DBNAME}|g' \
-e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
-e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
integrations/pgsql.ini.tmpl > integrations/pgsql.ini
.PHONY: test-pgsql
test-pgsql: integrations.pgsql.test generate-ini-pgsql
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./integrations.pgsql.test
.PHONY: test-pgsql\#%
test-pgsql\#%: integrations.pgsql.test generate-ini-pgsql
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*)
.PHONY: test-pgsql-migration
test-pgsql-migration: migrations.pgsql.test generate-ini-pgsql
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./migrations.pgsql.test
generate-ini-mssql:
sed -e 's|{{TEST_MSSQL_HOST}}|${TEST_MSSQL_HOST}|g' \
-e 's|{{TEST_MSSQL_DBNAME}}|${TEST_MSSQL_DBNAME}|g' \
-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
.PHONY: test-mysql
test-mysql: integrations.test generate-ini
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./integrations.test
.PHONY: test-pgsql
test-pgsql: integrations.test generate-ini
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./integrations.test
.PHONY: test-mssql
test-mssql: integrations.mssql.test generate-ini-mssql
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./integrations.mssql.test
.PHONY: test-mssql\#%
test-mssql\#%: integrations.mssql.test generate-ini-mssql
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*)
.PHONY: test-mssql-migration
test-mssql-migration: migrations.mssql.test generate-ini-mssql
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./migrations.mssql.test
test-mssql: integrations.test generate-ini
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./integrations.test
.PHONY: bench-sqlite
bench-sqlite: integrations.sqlite.test generate-ini-sqlite
bench-sqlite: integrations.sqlite.test
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
.PHONY: bench-mysql
bench-mysql: integrations.mysql.test generate-ini-mysql
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
.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 .
bench-mysql: integrations.test generate-ini
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./integrations.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 .
bench-pgsql: integrations.test generate-ini
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./integrations.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
.PHONY: integration-test-coverage
integration-test-coverage: integrations.cover.test generate-ini-mysql
integration-test-coverage: integrations.cover.test generate-ini
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mysql.ini ./integrations.cover.test -test.coverprofile=integration.coverage.out
integrations.mysql.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -mod=vendor -c code.gitea.io/gitea/integrations -o integrations.mysql.test
integrations.test: $(SOURCES)
$(GO) test -c code.gitea.io/gitea/integrations -o integrations.test
integrations.mysql8.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -mod=vendor -c code.gitea.io/gitea/integrations -o integrations.mysql8.test
integrations.sqlite.test: $(SOURCES)
$(GO) test -c code.gitea.io/gitea/integrations -o integrations.sqlite.test -tags 'sqlite sqlite_unlock_notify'
integrations.pgsql.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -mod=vendor -c code.gitea.io/gitea/integrations -o integrations.pgsql.test
integrations.mssql.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -mod=vendor -c code.gitea.io/gitea/integrations -o integrations.mssql.test
integrations.sqlite.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -mod=vendor -c code.gitea.io/gitea/integrations -o integrations.sqlite.test -tags 'sqlite sqlite_unlock_notify'
integrations.cover.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -mod=vendor -c code.gitea.io/gitea/integrations -coverpkg $(shell echo $(GO_PACKAGES) | tr ' ' ',') -o integrations.cover.test
.PHONY: migrations.mysql.test
migrations.mysql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations/migration-test -o 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
.PHONY: migrations.pgsql.test
migrations.pgsql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations/migration-test -o 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
.PHONY: migrations.sqlite.test
migrations.sqlite.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/integrations/migration-test -o migrations.sqlite.test -tags 'sqlite sqlite_unlock_notify'
integrations.cover.test: $(SOURCES)
$(GO) test -c code.gitea.io/gitea/integrations -coverpkg $(shell echo $(PACKAGES) | tr ' ' ',') -o integrations.cover.test
.PHONY: check
check: test
.PHONY: install $(TAGS_PREREQ)
.PHONY: install
install: $(wildcard *.go)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)'
$(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)'
.PHONY: build
build: frontend backend
build: $(EXECUTABLE)
.PHONY: frontend
frontend: node-check $(FOMANTIC_DEST) $(WEBPACK_DEST)
.PHONY: backend
backend: go-check generate $(EXECUTABLE)
.PHONY: generate
generate: $(TAGS_PREREQ)
CC= GOOS= GOARCH= $(GO) generate -mod=vendor -tags '$(TAGS)' $(GO_PACKAGES)
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build -mod=vendor $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
$(EXECUTABLE): $(SOURCES)
$(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 release-sources release-check
release: release-dirs release-windows release-linux release-darwin release-copy release-compress release-check
$(DIST_DIRS):
mkdir -p $(DIST_DIRS)
.PHONY: release-dirs
release-dirs:
mkdir -p $(DIST)/binaries $(DIST)/release
.PHONY: release-windows
release-windows: | $(DIST_DIRS)
release-windows:
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \
$(GO) get -u github.com/karalabe/xgo; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
xgo -dest $(DIST)/binaries -tags 'netgo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
mv /build/* $(DIST)/binaries
endif
.PHONY: release-linux
release-linux: | $(DIST_DIRS)
release-linux:
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \
$(GO) get -u github.com/karalabe/xgo; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/mips64le,linux/mips,linux/mipsle' -out gitea-$(VERSION) .
xgo -dest $(DIST)/binaries -tags 'netgo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/*' -out gitea-$(VERSION) .
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
mv /build/* $(DIST)/binaries
endif
.PHONY: release-darwin
release-darwin: | $(DIST_DIRS)
release-darwin:
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \
$(GO) get -u github.com/karalabe/xgo; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out gitea-$(VERSION) .
xgo -dest $(DIST)/binaries -tags 'netgo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out gitea-$(VERSION) .
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
mv /build/* $(DIST)/binaries
endif
.PHONY: release-copy
release-copy: | $(DIST_DIRS)
cd $(DIST); for file in `find /build -type f -name "*"`; do cp $${file} ./release/; done;
release-copy:
$(foreach file,$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*),cp $(file) $(DIST)/release/$(notdir $(file));)
.PHONY: release-check
release-check: | $(DIST_DIRS)
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "checksumming $${file}" && $(SHASUM) `echo $${file} | sed 's/^..//'` > $${file}.sha256; done;
release-check:
cd $(DIST)/release; $(foreach file,$(wildcard $(DIST)/release/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
.PHONY: release-compress
release-compress: | $(DIST_DIRS)
release-compress:
@hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
GO111MODULE=off $(GO) get -u github.com/ulikunitz/xz/cmd/gxz; \
$(GO) get -u github.com/ulikunitz/xz/cmd/gxz; \
fi
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
cd $(DIST)/release; $(foreach file,$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*),gxz -k -9 $(notdir $(file));)
.PHONY: release-sources
release-sources: | $(DIST_DIRS) node_modules
echo $(VERSION) > $(STORED_VERSION_FILE)
tar --exclude=./$(DIST) --exclude=./.git --exclude=./$(MAKE_EVIDENCE_DIR) --exclude=./node_modules/.cache -czf $(DIST)/release/gitea-src-$(VERSION).tar.gz .
rm -f $(STORED_VERSION_FILE)
.PHONY: javascripts
javascripts: public/js/index.js
node_modules: package-lock.json
npm install --no-save
@touch node_modules
.IGNORE: public/js/index.js
public/js/index.js: $(JAVASCRIPTS)
cat $< >| $@
.PHONY: npm-update
npm-update: node-check | node_modules
npx updates -cu
rm -rf node_modules package-lock.json
npm install --package-lock
.PHONY: stylesheets-check
stylesheets-check: generate-stylesheets
@diff=$$(git diff public/css/*); \
if [ -n "$$diff" ]; then \
echo "Please run 'make generate-stylesheets' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
.PHONY: fomantic
fomantic: $(FOMANTIC_DEST)
.PHONY: generate-stylesheets
generate-stylesheets:
node_modules/.bin/lessc --clean-css public/less/index.less public/css/index.css
$(foreach file, $(filter-out public/less/themes/_base.less, $(wildcard public/less/themes/*)),node_modules/.bin/lessc --clean-css public/less/themes/$(notdir $(file)) > public/css/theme-$(notdir $(call strip-suffix,$(file))).css;)
$(FOMANTIC_DEST): $(FOMANTIC_CONFIGS) package-lock.json | node_modules
rm -rf $(FOMANTIC_DEST_DIR)
cp web_src/fomantic/theme.config.less node_modules/fomantic-ui/src/theme.config
cp -r web_src/fomantic/_site/* node_modules/fomantic-ui/src/_site/
cp web_src/fomantic/css.js node_modules/fomantic-ui/tasks/build/css.js
npx gulp -f node_modules/fomantic-ui/gulpfile.js build
@touch $(FOMANTIC_DEST)
.PHONY: webpack
webpack: $(WEBPACK_DEST)
$(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json | node_modules
rm -rf $(WEBPACK_DEST_ENTRIES)
npx webpack --hide-modules --display-entrypoints=false
@touch $(WEBPACK_DEST)
.PHONY: swagger-ui
swagger-ui:
rm -Rf public/vendor/assets/swagger-ui
git clone --depth=10 -b v3.13.4 --single-branch https://github.com/swagger-api/swagger-ui.git $(TMPDIR)/swagger-ui
mv $(TMPDIR)/swagger-ui/dist public/vendor/assets/swagger-ui
rm -Rf $(TMPDIR)/swagger-ui
$(SED_INPLACE) "s;http://petstore.swagger.io/v2/swagger.json;../../../swagger.v1.json;g" public/vendor/assets/swagger-ui/index.html
.PHONY: update-translations
update-translations:
@@ -618,7 +358,6 @@ update-translations:
.PHONY: generate-images
generate-images:
$(eval TMPDIR := $(shell mktemp -d 2>/dev/null || mktemp -d -t 'gitea-temp'))
mkdir -p $(TMPDIR)/images
inkscape -f $(PWD)/assets/logo.svg -w 880 -h 880 -e $(PWD)/public/img/gitea-lg.png
inkscape -f $(PWD)/assets/logo.svg -w 512 -h 512 -e $(PWD)/public/img/gitea-512.png
@@ -634,30 +373,12 @@ generate-images:
inkscape -f $(PWD)/assets/logo.svg -w 32 -h 32 -jC -i layer2 -e $(TMPDIR)/images/32-2.png
composite -compose atop $(TMPDIR)/images/32-2.png $(TMPDIR)/images/32-1.png $(TMPDIR)/images/32-raw.png
inkscape -f $(PWD)/assets/logo.svg -w 16 -h 16 -jC -i layer1 -e $(TMPDIR)/images/16-raw.png
zopflipng -m -y $(TMPDIR)/images/128-raw.png $(TMPDIR)/images/128.png
zopflipng -m -y $(TMPDIR)/images/64-raw.png $(TMPDIR)/images/64.png
zopflipng -m -y $(TMPDIR)/images/32-raw.png $(TMPDIR)/images/32.png
zopflipng -m -y $(TMPDIR)/images/16-raw.png $(TMPDIR)/images/16.png
zopflipng $(TMPDIR)/images/128-raw.png $(TMPDIR)/images/128.png
zopflipng $(TMPDIR)/images/64-raw.png $(TMPDIR)/images/64.png
zopflipng $(TMPDIR)/images/32-raw.png $(TMPDIR)/images/32.png
zopflipng $(TMPDIR)/images/16-raw.png $(TMPDIR)/images/16.png
rm -f $(TMPDIR)/images/*-*.png
convert $(TMPDIR)/images/16.png $(TMPDIR)/images/32.png \
$(TMPDIR)/images/64.png $(TMPDIR)/images/128.png \
$(PWD)/public/img/favicon.ico
convert -flatten $(PWD)/public/img/favicon.png $(PWD)/public/img/apple-touch-icon.png
rm -rf $(TMPDIR)/images
$(foreach file, $(shell find public/img -type f -name '*.png' ! -name 'loading.png'),zopflipng -m -y $(file) $(file);)
.PHONY: pr\#%
pr\#%: clean-all
$(GO) run contrib/pr/checkout.go $*
.PHONY: golangci-lint
golangci-lint:
@hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
export BINARY="golangci-lint"; \
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.24.0; \
fi
golangci-lint run --timeout 5m
# This endif closes the if at the top of the file
endif

View File

@@ -1,18 +1,16 @@
[简体中文](README_ZH.md)
[简体中文](https://github.com/go-gitea/gitea/blob/master/README_ZH.md)
<h1> <img src="https://raw.githubusercontent.com/go-gitea/gitea/master/public/img/gitea-192.png" alt="logo" width="30" height="30"> Gitea - Git with a cup of tea</h1>
# Gitea - Git with a cup of tea
[![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](https://drone.gitea.io/go-gitea/gitea)
[![Join the Discord chat at https://discord.gg/Gitea](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/Gitea)
[![Join the Discord chat at https://discord.gg/NsatcWJ](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/NsatcWJ)
[![](https://images.microbadger.com/badges/image/gitea/gitea.svg)](https://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com")
[![codecov](https://codecov.io/gh/go-gitea/gitea/branch/master/graph/badge.svg)](https://codecov.io/gh/go-gitea/gitea)
[![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea)
[![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea)
[![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest)
[![Help Contribute to Open Source](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea)
[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea)
[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backer/badge.svg?label=backer&color=brightgreen)](https://opencollective.com/gitea)
## Purpose
@@ -31,20 +29,7 @@ This project has been
From the root of the source tree, run:
TAGS="bindata" make build
or if sqlite support is required:
TAGS="bindata sqlite sqlite_unlock_notify" make build
The `build` target is split into two sub-targets:
- `make backend` which requires [Go 1.12](https://golang.org/dl/) or greater.
- `make frontend` which requires [Node.js 10.13](https://nodejs.org/en/download/) or greater.
If pre-built frontend files are present it is possible to only build the backend:
TAGS="bindata" make backend
TAGS="bindata" make generate all
More info: https://docs.gitea.io/en-us/install-from-source/
@@ -69,7 +54,7 @@ NOTES:
For more information and instructions about how to install Gitea, please look
at our [documentation](https://docs.gitea.io/en-us/). If you have questions
that are not covered by the documentation, you can get in contact with us on
our [Discord server](https://discord.gg/Gitea),
our [Discord server](https://discord.gg/NsatcWJ),
or [forum](https://discourse.gitea.io/)!
## Authors
@@ -118,8 +103,9 @@ for the full license text.
## Screenshots
Looking for an overview of the interface? Check it out!
|![Dashboard](https://dl.gitea.io/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.io/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.io/screenshots/global_issues.png)|
| | | |
|:---:|:---:|:---:|
|![Branches](https://dl.gitea.io/screenshots/branches.png)|![Web Editor](https://dl.gitea.io/screenshots/web_editor.png)|![Activity](https://dl.gitea.io/screenshots/activity.png)|
|![New Migration](https://dl.gitea.io/screenshots/migration.png)|![Migrating](https://dl.gitea.io/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)
![Pull Request Dark](https://dl.gitea.io/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.io/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.io/screenshots/diff_dark.png)|
|![Dashboard](https://image.ibb.co/dms6DG/1.png)|![Repository](https://image.ibb.co/m6MSLw/2.png)|![Commits History](https://image.ibb.co/cjrSLw/3.png)|
|![Branches](https://image.ibb.co/e6vbDG/4.png)|![Issues](https://image.ibb.co/bJTJSb/5.png)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)|
|![Releases](https://image.ibb.co/cUzgfw/7.png)|![Activity](https://image.ibb.co/eZgGDG/8.png)|![Wiki](https://image.ibb.co/dYV9YG/9.png)|
|![Diff](https://image.ibb.co/ewA9YG/10.png)|![Organization](https://image.ibb.co/ceOwDG/11.png)|![Profile](https://image.ibb.co/c44Q7b/12.png)|

View File

@@ -1,18 +1,15 @@
[English](README.md)
[English](https://github.com/go-gitea/gitea/blob/master/README.md)
<h1> <img src="https://raw.githubusercontent.com/go-gitea/gitea/master/public/img/gitea-192.png" alt="logo" width="30" height="30"> Gitea - Git with a cup of tea</h1>
# Gitea - Git with a cup of tea
[![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](https://drone.gitea.io/go-gitea/gitea)
[![Join the Discord chat at https://discord.gg/Gitea](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/Gitea)
[![Join the chat at https://img.shields.io/discord/322538954119184384.svg](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/NsatcWJ)
[![](https://images.microbadger.com/badges/image/gitea/gitea.svg)](https://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com")
[![codecov](https://codecov.io/gh/go-gitea/gitea/branch/master/graph/badge.svg)](https://codecov.io/gh/go-gitea/gitea)
[![Coverage Status](https://coverage.gitea.io/badges/go-gitea/gitea/coverage.svg)](https://coverage.gitea.io/go-gitea/gitea)
[![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea)
[![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea)
[![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest)
[![Help Contribute to Open Source](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea)
[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea)
[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backer/badge.svg?label=backer&color=brightgreen)](https://opencollective.com/gitea)
## 目标
@@ -28,7 +25,7 @@ Gitea 的首要目标是创建一个极易安装,运行非常快速,安装
## 文档
关于如何安装请访问我们的 [文档站](https://docs.gitea.io/zh-cn/),如果没有找到对应的文档,你也可以通过 [Discord - 英文](https://discord.gg/gitea) 和 QQ群 328432459 来和我们交流。
关于如何安装请访问我们的 [文档站](https://docs.gitea.io/zh-cn/),如果没有找到对应的文档,你也可以通过 [Discord - 英文](https://discord.gg/NsatcWJ) 和 QQ群 328432459 来和我们交流。
## 贡献流程
@@ -46,8 +43,9 @@ Fork -> Patch -> Push -> Pull Request
## 截图
|![Dashboard](https://dl.gitea.io/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.io/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.io/screenshots/global_issues.png)|
| | | |
|:---:|:---:|:---:|
|![Branches](https://dl.gitea.io/screenshots/branches.png)|![Web Editor](https://dl.gitea.io/screenshots/web_editor.png)|![Activity](https://dl.gitea.io/screenshots/activity.png)|
|![New Migration](https://dl.gitea.io/screenshots/migration.png)|![Migrating](https://dl.gitea.io/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)
![Pull Request Dark](https://dl.gitea.io/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.io/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.io/screenshots/diff_dark.png)|
|![Dashboard](https://image.ibb.co/dms6DG/1.png)|![Repository](https://image.ibb.co/m6MSLw/2.png)|![Commits History](https://image.ibb.co/cjrSLw/3.png)|
|![Branches](https://image.ibb.co/e6vbDG/4.png)|![Issues](https://image.ibb.co/bJTJSb/5.png)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)|
|![Releases](https://image.ibb.co/cUzgfw/7.png)|![Activity](https://image.ibb.co/eZgGDG/8.png)|![Wiki](https://image.ibb.co/dYV9YG/9.png)|
|![Diff](https://image.ibb.co/ewA9YG/10.png)|![Organization](https://image.ibb.co/ceOwDG/11.png)|![Profile](https://image.ibb.co/c44Q7b/12.png)|

File diff suppressed because one or more lines are too long

View File

@@ -1,32 +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.
//+build vendor
package main
// Libraries that are included to vendor utilities used during build.
// These libraries will not be included in a normal compilation.
import (
// for lint
_ "github.com/BurntSushi/toml"
_ "github.com/mgechev/dots"
_ "github.com/mgechev/revive/formatter"
_ "github.com/mgechev/revive/lint"
_ "github.com/mgechev/revive/rule"
_ "github.com/mitchellh/go-homedir"
// for embed
_ "github.com/shurcooL/vfsgen"
// for cover merge
_ "golang.org/x/tools/cover"
// for vet
_ "gitea.com/jolheiser/gitea-vet"
// for swagger
_ "github.com/go-swagger/go-swagger/cmd/swagger"
)

View File

@@ -1,86 +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.
// +build ignore
package main
import (
"bytes"
"crypto/sha1"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"strconv"
"github.com/shurcooL/vfsgen"
)
func needsUpdate(dir string, filename string) (bool, []byte) {
needRegen := false
_, err := os.Stat(filename)
if err != nil {
needRegen = true
}
oldHash, err := ioutil.ReadFile(filename + ".hash")
if err != nil {
oldHash = []byte{}
}
hasher := sha1.New()
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
_, _ = hasher.Write([]byte(info.Name()))
_, _ = hasher.Write([]byte(info.ModTime().String()))
_, _ = hasher.Write([]byte(strconv.FormatInt(info.Size(), 16)))
return nil
})
if err != nil {
return true, oldHash
}
newHash := hasher.Sum([]byte{})
if bytes.Compare(oldHash, newHash) != 0 {
return true, newHash
}
return needRegen, newHash
}
func main() {
if len(os.Args) != 4 {
log.Fatal("Insufficient number of arguments. Need: directory packageName filename")
}
dir, packageName, filename := os.Args[1], os.Args[2], os.Args[3]
update, newHash := needsUpdate(dir, filename)
if !update {
fmt.Printf("bindata for %s already up-to-date\n", packageName)
return
}
fmt.Printf("generating bindata for %s\n", packageName)
var fsTemplates http.FileSystem = http.Dir(dir)
err := vfsgen.Generate(fsTemplates, vfsgen.Options{
PackageName: packageName,
BuildTags: "bindata",
VariableName: "Assets",
Filename: filename,
})
if err != nil {
log.Fatalf("%v\n", err)
}
_ = ioutil.WriteFile(filename+".hash", newHash, 0666)
}

View File

@@ -1,221 +0,0 @@
// 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.
// +build ignore
package main
import (
"encoding/json"
"flag"
"fmt"
"go/format"
"io/ioutil"
"log"
"net/http"
"regexp"
"sort"
"strconv"
"strings"
"unicode/utf8"
)
const (
gemojiURL = "https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json"
maxUnicodeVersion = 12
)
var (
flagOut = flag.String("o", "modules/emoji/emoji_data.go", "out")
)
// Gemoji is a set of emoji data.
type Gemoji []Emoji
// Emoji represents a single emoji and associated data.
type Emoji struct {
Emoji string `json:"emoji"`
Description string `json:"description,omitempty"`
Aliases []string `json:"aliases"`
UnicodeVersion string `json:"unicode_version,omitempty"`
SkinTones bool `json:"skin_tones,omitempty"`
}
// Don't include some fields in JSON
func (e Emoji) MarshalJSON() ([]byte, error) {
type emoji Emoji
x := emoji(e)
x.UnicodeVersion = ""
x.Description = ""
x.SkinTones = false
return json.Marshal(x)
}
func main() {
var err error
flag.Parse()
// generate data
buf, err := generate()
if err != nil {
log.Fatal(err)
}
// write
err = ioutil.WriteFile(*flagOut, buf, 0644)
if err != nil {
log.Fatal(err)
}
}
var replacer = strings.NewReplacer(
"main.Gemoji", "Gemoji",
"main.Emoji", "\n",
"}}", "},\n}",
", Description:", ", ",
", Aliases:", ", ",
", UnicodeVersion:", ", ",
", SkinTones:", ", ",
)
var emojiRE = regexp.MustCompile(`\{Emoji:"([^"]*)"`)
func generate() ([]byte, error) {
var err error
// load gemoji data
res, err := http.Get(gemojiURL)
if err != nil {
return nil, err
}
defer res.Body.Close()
// read all
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
// unmarshal
var data Gemoji
err = json.Unmarshal(body, &data)
if err != nil {
return nil, err
}
var skinTones = make(map[string]string)
skinTones["\U0001f3fb"] = "Light Skin Tone"
skinTones["\U0001f3fc"] = "Medium-Light Skin Tone"
skinTones["\U0001f3fd"] = "Medium Skin Tone"
skinTones["\U0001f3fe"] = "Medium-Dark Skin Tone"
skinTones["\U0001f3ff"] = "Dark Skin Tone"
var tmp Gemoji
//filter out emoji that require greater than max unicode version
for i := range data {
val, _ := strconv.ParseFloat(data[i].UnicodeVersion, 64)
if int(val) <= maxUnicodeVersion {
tmp = append(tmp, data[i])
}
}
data = tmp
sort.Slice(data, func(i, j int) bool {
return data[i].Aliases[0] < data[j].Aliases[0]
})
aliasMap := make(map[string]int, len(data))
for i, e := range data {
if e.Emoji == "" || len(e.Aliases) == 0 {
continue
}
for _, a := range e.Aliases {
if a == "" {
continue
}
aliasMap[a] = i
}
}
// gitea customizations
i, ok := aliasMap["tada"]
if ok {
data[i].Aliases = append(data[i].Aliases, "hooray")
}
i, ok = aliasMap["laughing"]
if ok {
data[i].Aliases = append(data[i].Aliases, "laugh")
}
// write a JSON file to use with tribute (write before adding skin tones since we can't support them there yet)
file, _ := json.Marshal(data)
_ = ioutil.WriteFile("assets/emoji.json", file, 0644)
// Add skin tones to emoji that support it
var (
s []string
newEmoji string
newDescription string
newData Emoji
)
for i := range data {
if data[i].SkinTones {
for k, v := range skinTones {
s = strings.Split(data[i].Emoji, "")
if utf8.RuneCountInString(data[i].Emoji) == 1 {
s = append(s, k)
} else {
// insert into slice after first element because all emoji that support skin tones
// have that modifer placed at this spot
s = append(s, "")
copy(s[2:], s[1:])
s[1] = k
}
newEmoji = strings.Join(s, "")
newDescription = data[i].Description + ": " + v
newAlias := data[i].Aliases[0] + "_" + strings.ReplaceAll(v, " ", "_")
newData = Emoji{newEmoji, newDescription, []string{newAlias}, "12.0", false}
data = append(data, newData)
}
}
}
// add header
str := replacer.Replace(fmt.Sprintf(hdr, gemojiURL, data))
// change the format of the unicode string
str = emojiRE.ReplaceAllStringFunc(str, func(s string) string {
var err error
s, err = strconv.Unquote(s[len("{Emoji:"):])
if err != nil {
panic(err)
}
return "{" + strconv.QuoteToASCII(s)
})
// format
return format.Source([]byte(str))
}
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.
package emoji
// Code generated by gen.go. DO NOT EDIT.
// Sourced from %s
//
var GemojiData = %#v
`

View File

@@ -1,119 +0,0 @@
// 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.
// gocovmerge takes the results from multiple `go test -coverprofile` runs and
// merges them into one profile
// +build ignore
package main
import (
"flag"
"fmt"
"io"
"log"
"os"
"sort"
"golang.org/x/tools/cover"
)
func mergeProfiles(p *cover.Profile, merge *cover.Profile) {
if p.Mode != merge.Mode {
log.Fatalf("cannot merge profiles with different modes")
}
// Since the blocks are sorted, we can keep track of where the last block
// was inserted and only look at the blocks after that as targets for merge
startIndex := 0
for _, b := range merge.Blocks {
startIndex = mergeProfileBlock(p, b, startIndex)
}
}
func mergeProfileBlock(p *cover.Profile, pb cover.ProfileBlock, startIndex int) int {
sortFunc := func(i int) bool {
pi := p.Blocks[i+startIndex]
return pi.StartLine >= pb.StartLine && (pi.StartLine != pb.StartLine || pi.StartCol >= pb.StartCol)
}
i := 0
if sortFunc(i) != true {
i = sort.Search(len(p.Blocks)-startIndex, sortFunc)
}
i += startIndex
if i < len(p.Blocks) && p.Blocks[i].StartLine == pb.StartLine && p.Blocks[i].StartCol == pb.StartCol {
if p.Blocks[i].EndLine != pb.EndLine || p.Blocks[i].EndCol != pb.EndCol {
log.Fatalf("OVERLAP MERGE: %v %v %v", p.FileName, p.Blocks[i], pb)
}
switch p.Mode {
case "set":
p.Blocks[i].Count |= pb.Count
case "count", "atomic":
p.Blocks[i].Count += pb.Count
default:
log.Fatalf("unsupported covermode: '%s'", p.Mode)
}
} else {
if i > 0 {
pa := p.Blocks[i-1]
if pa.EndLine >= pb.EndLine && (pa.EndLine != pb.EndLine || pa.EndCol > pb.EndCol) {
log.Fatalf("OVERLAP BEFORE: %v %v %v", p.FileName, pa, pb)
}
}
if i < len(p.Blocks)-1 {
pa := p.Blocks[i+1]
if pa.StartLine <= pb.StartLine && (pa.StartLine != pb.StartLine || pa.StartCol < pb.StartCol) {
log.Fatalf("OVERLAP AFTER: %v %v %v", p.FileName, pa, pb)
}
}
p.Blocks = append(p.Blocks, cover.ProfileBlock{})
copy(p.Blocks[i+1:], p.Blocks[i:])
p.Blocks[i] = pb
}
return i + 1
}
func addProfile(profiles []*cover.Profile, p *cover.Profile) []*cover.Profile {
i := sort.Search(len(profiles), func(i int) bool { return profiles[i].FileName >= p.FileName })
if i < len(profiles) && profiles[i].FileName == p.FileName {
mergeProfiles(profiles[i], p)
} else {
profiles = append(profiles, nil)
copy(profiles[i+1:], profiles[i:])
profiles[i] = p
}
return profiles
}
func dumpProfiles(profiles []*cover.Profile, out io.Writer) {
if len(profiles) == 0 {
return
}
fmt.Fprintf(out, "mode: %s\n", profiles[0].Mode)
for _, p := range profiles {
for _, b := range p.Blocks {
fmt.Fprintf(out, "%s:%d.%d,%d.%d %d %d\n", p.FileName, b.StartLine, b.StartCol, b.EndLine, b.EndCol, b.NumStmt, b.Count)
}
}
}
func main() {
flag.Parse()
var merged []*cover.Profile
for _, file := range flag.Args() {
profiles, err := cover.ParseProfiles(file)
if err != nil {
log.Fatalf("failed to parse profiles: %v", err)
}
for _, p := range profiles {
merged = addProfile(merged, p)
}
}
dumpProfiles(merged, os.Stdout)
}

View File

@@ -1,325 +0,0 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Copyright (c) 2018 Minko Gechev. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// +build ignore
package main
import (
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/BurntSushi/toml"
"github.com/mgechev/dots"
"github.com/mgechev/revive/formatter"
"github.com/mgechev/revive/lint"
"github.com/mgechev/revive/rule"
"github.com/mitchellh/go-homedir"
)
func fail(err string) {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
var defaultRules = []lint.Rule{
&rule.VarDeclarationsRule{},
&rule.PackageCommentsRule{},
&rule.DotImportsRule{},
&rule.BlankImportsRule{},
&rule.ExportedRule{},
&rule.VarNamingRule{},
&rule.IndentErrorFlowRule{},
&rule.IfReturnRule{},
&rule.RangeRule{},
&rule.ErrorfRule{},
&rule.ErrorNamingRule{},
&rule.ErrorStringsRule{},
&rule.ReceiverNamingRule{},
&rule.IncrementDecrementRule{},
&rule.ErrorReturnRule{},
&rule.UnexportedReturnRule{},
&rule.TimeNamingRule{},
&rule.ContextKeysType{},
&rule.ContextAsArgumentRule{},
}
var allRules = append([]lint.Rule{
&rule.ArgumentsLimitRule{},
&rule.CyclomaticRule{},
&rule.FileHeaderRule{},
&rule.EmptyBlockRule{},
&rule.SuperfluousElseRule{},
&rule.ConfusingNamingRule{},
&rule.GetReturnRule{},
&rule.ModifiesParamRule{},
&rule.ConfusingResultsRule{},
&rule.DeepExitRule{},
&rule.UnusedParamRule{},
&rule.UnreachableCodeRule{},
&rule.AddConstantRule{},
&rule.FlagParamRule{},
&rule.UnnecessaryStmtRule{},
&rule.StructTagRule{},
&rule.ModifiesValRecRule{},
&rule.ConstantLogicalExprRule{},
&rule.BoolLiteralRule{},
&rule.RedefinesBuiltinIDRule{},
&rule.ImportsBlacklistRule{},
&rule.FunctionResultsLimitRule{},
&rule.MaxPublicStructsRule{},
&rule.RangeValInClosureRule{},
&rule.RangeValAddress{},
&rule.WaitGroupByValueRule{},
&rule.AtomicRule{},
&rule.EmptyLinesRule{},
&rule.LineLengthLimitRule{},
&rule.CallToGCRule{},
&rule.DuplicatedImportsRule{},
&rule.ImportShadowingRule{},
&rule.BareReturnRule{},
&rule.UnusedReceiverRule{},
&rule.UnhandledErrorRule{},
&rule.CognitiveComplexityRule{},
&rule.StringOfIntRule{},
}, defaultRules...)
var allFormatters = []lint.Formatter{
&formatter.Stylish{},
&formatter.Friendly{},
&formatter.JSON{},
&formatter.NDJSON{},
&formatter.Default{},
&formatter.Unix{},
&formatter.Checkstyle{},
&formatter.Plain{},
}
func getFormatters() map[string]lint.Formatter {
result := map[string]lint.Formatter{}
for _, f := range allFormatters {
result[f.Name()] = f
}
return result
}
func getLintingRules(config *lint.Config) []lint.Rule {
rulesMap := map[string]lint.Rule{}
for _, r := range allRules {
rulesMap[r.Name()] = r
}
lintingRules := []lint.Rule{}
for name := range config.Rules {
rule, ok := rulesMap[name]
if !ok {
fail("cannot find rule: " + name)
}
lintingRules = append(lintingRules, rule)
}
return lintingRules
}
func parseConfig(path string) *lint.Config {
config := &lint.Config{}
file, err := ioutil.ReadFile(path)
if err != nil {
fail("cannot read the config file")
}
_, err = toml.Decode(string(file), config)
if err != nil {
fail("cannot parse the config file: " + err.Error())
}
return config
}
func normalizeConfig(config *lint.Config) {
if config.Confidence == 0 {
config.Confidence = 0.8
}
severity := config.Severity
if severity != "" {
for k, v := range config.Rules {
if v.Severity == "" {
v.Severity = severity
}
config.Rules[k] = v
}
for k, v := range config.Directives {
if v.Severity == "" {
v.Severity = severity
}
config.Directives[k] = v
}
}
}
func getConfig() *lint.Config {
config := defaultConfig()
if configPath != "" {
config = parseConfig(configPath)
}
normalizeConfig(config)
return config
}
func getFormatter() lint.Formatter {
formatters := getFormatters()
formatter := formatters["default"]
if formatterName != "" {
f, ok := formatters[formatterName]
if !ok {
fail("unknown formatter " + formatterName)
}
formatter = f
}
return formatter
}
func buildDefaultConfigPath() string {
var result string
if homeDir, err := homedir.Dir(); err == nil {
result = filepath.Join(homeDir, "revive.toml")
if _, err := os.Stat(result); err != nil {
result = ""
}
}
return result
}
func defaultConfig() *lint.Config {
defaultConfig := lint.Config{
Confidence: 0.0,
Severity: lint.SeverityWarning,
Rules: map[string]lint.RuleConfig{},
}
for _, r := range defaultRules {
defaultConfig.Rules[r.Name()] = lint.RuleConfig{}
}
return &defaultConfig
}
func normalizeSplit(strs []string) []string {
res := []string{}
for _, s := range strs {
t := strings.Trim(s, " \t")
if len(t) > 0 {
res = append(res, t)
}
}
return res
}
func getPackages() [][]string {
globs := normalizeSplit(flag.Args())
if len(globs) == 0 {
globs = append(globs, ".")
}
packages, err := dots.ResolvePackages(globs, normalizeSplit(excludePaths))
if err != nil {
fail(err.Error())
}
return packages
}
type arrayFlags []string
func (i *arrayFlags) String() string {
return strings.Join([]string(*i), " ")
}
func (i *arrayFlags) Set(value string) error {
*i = append(*i, value)
return nil
}
var configPath string
var excludePaths arrayFlags
var formatterName string
var help bool
var originalUsage = flag.Usage
func init() {
flag.Usage = func() {
originalUsage()
}
// command line help strings
const (
configUsage = "path to the configuration TOML file, defaults to $HOME/revive.toml, if present (i.e. -config myconf.toml)"
excludeUsage = "list of globs which specify files to be excluded (i.e. -exclude foo/...)"
formatterUsage = "formatter to be used for the output (i.e. -formatter stylish)"
)
defaultConfigPath := buildDefaultConfigPath()
flag.StringVar(&configPath, "config", defaultConfigPath, configUsage)
flag.Var(&excludePaths, "exclude", excludeUsage)
flag.StringVar(&formatterName, "formatter", "", formatterUsage)
flag.Parse()
}
func main() {
config := getConfig()
formatter := getFormatter()
packages := getPackages()
revive := lint.New(func(file string) ([]byte, error) {
return ioutil.ReadFile(file)
})
lintingRules := getLintingRules(config)
failures, err := revive.Lint(packages, lintingRules, *config)
if err != nil {
fail(err.Error())
}
formatChan := make(chan lint.Failure)
exitChan := make(chan bool)
var output string
go (func() {
output, err = formatter.Format(formatChan, *config)
if err != nil {
fail(err.Error())
}
exitChan <- true
})()
exitCode := 0
for f := range failures {
if f.Confidence < config.Confidence {
continue
}
if exitCode == 0 {
exitCode = config.WarningCode
}
if c, ok := config.Rules[f.RuleName]; ok && c.Severity == lint.SeverityError {
exitCode = config.ErrorCode
}
if c, ok := config.Directives[f.RuleName]; ok && c.Severity == lint.SeverityError {
exitCode = config.ErrorCode
}
formatChan <- f
}
close(formatChan)
<-exitChan
if output != "" {
fmt.Println(output)
}
os.Exit(exitCode)
}

View File

@@ -1,23 +0,0 @@
#!/bin/sh
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
s/"$//
}' ./options/locale/*.ini
# Remove translation under 25% of en_us
baselines=`wc -l "./options/locale_en-US.ini" | cut -d" " -f1`
baselines=$((baselines / 4))
for filename in ./options/locale/*.ini; do
lines=`wc -l "$filename" | cut -d" " -f1`
if [ $lines -lt $baselines ]; then
echo "Removing $filename: $lines/$baselines"
rm "$filename"
fi
done
mv ./options/locale_en-US.ini ./options/locale/

View File

@@ -11,13 +11,11 @@ import (
"os"
"text/tabwriter"
"code.gitea.io/git"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth/oauth2"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/generate"
"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"
"github.com/urfave/cli"
@@ -44,10 +42,6 @@ var (
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Usage: "Username. DEPRECATED: use username instead",
},
cli.StringFlag{
Name: "username",
Usage: "Username",
},
cli.StringFlag{
@@ -62,23 +56,24 @@ var (
Name: "admin",
Usage: "User is an admin",
},
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
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)",
Usage: "Force the user to change his/her password after initial login",
},
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",
},
},
}
@@ -97,6 +92,11 @@ var (
Value: "",
Usage: "New password to set for user",
},
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
@@ -119,12 +119,26 @@ var (
Name: "hooks",
Usage: "Regenerate git-hooks",
Action: runRegenerateHooks,
Flags: []cli.Flag{
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
microcmdRegenKeys = cli.Command{
Name: "keys",
Usage: "Regenerate authorized_keys file",
Action: runRegenerateKeys,
Flags: []cli.Flag{
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
subcmdAuth = cli.Command{
@@ -133,10 +147,6 @@ var (
Subcommands: []cli.Command{
microcmdAuthAddOauth,
microcmdAuthUpdateOauth,
cmdAuthAddLdapBindDn,
cmdAuthUpdateLdapBindDn,
cmdAuthAddLdapSimpleAuth,
cmdAuthUpdateLdapSimpleAuth,
microcmdAuthList,
microcmdAuthDelete,
},
@@ -147,46 +157,39 @@ var (
Usage: "List auth sources",
Action: runListAuth,
Flags: []cli.Flag{
cli.IntFlag{
Name: "min-width",
Usage: "Minimal cell width including any padding for the formatted table",
Value: 0,
},
cli.IntFlag{
Name: "tab-width",
Usage: "width of tab characters in formatted table (equivalent number of spaces)",
Value: 8,
},
cli.IntFlag{
Name: "padding",
Usage: "padding added to a cell before computing its width",
Value: 1,
},
cli.StringFlag{
Name: "pad-char",
Usage: `ASCII char used for padding if padchar == '\\t', the Writer will assume that the width of a '\\t' in the formatted output is tabwidth, and cells are left-aligned independent of align_left (for correct-looking results, tabwidth must correspond to the tab width in the viewer displaying the result)`,
Value: "\t",
},
cli.BoolFlag{
Name: "vertical-bars",
Usage: "Set to true to print vertical bars between columns",
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
idFlag = cli.Int64Flag{
Name: "id",
Usage: "ID of authentication source",
Usage: "ID of OAuth authentication source",
}
microcmdAuthDelete = cli.Command{
Name: "delete",
Usage: "Delete specific auth source",
Flags: []cli.Flag{idFlag},
Action: runDeleteAuth,
Flags: []cli.Flag{
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
idFlag,
},
}
oauthCLIFlags = []cli.Flag{
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
cli.StringFlag{
Name: "name",
Value: "",
@@ -259,12 +262,14 @@ func runChangePassword(c *cli.Context) error {
return err
}
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
if err := initDB(); err != nil {
return err
}
if !pwd.IsComplexEnough(c.String("password")) {
return errors.New("Password does not meet complexity requirements")
}
uname := c.String("username")
user, err := models.GetUserByName(uname)
if err != nil {
@@ -274,7 +279,6 @@ func runChangePassword(c *cli.Context) error {
return err
}
user.HashPassword(c.String("password"))
if err := models.UpdateUserCols(user, "passwd", "salt"); err != nil {
return err
}
@@ -284,47 +288,38 @@ func runChangePassword(c *cli.Context) error {
}
func runCreateUser(c *cli.Context) error {
if err := argsSet(c, "email"); err != nil {
if err := argsSet(c, "name", "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")
}
if err := initDB(); 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"))
password, err = generate.GetRandomString(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")
}
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
if err := initDB(); err != nil {
return err
}
// always default to true
var changePassword = true
@@ -338,34 +333,18 @@ func runCreateUser(c *cli.Context) error {
changePassword = c.Bool("must-change-password")
}
u := &models.User{
Name: username,
if err := models.CreateUser(&models.User{
Name: c.String("name"),
Email: c.String("email"),
Passwd: password,
IsActive: true,
IsAdmin: c.Bool("admin"),
MustChangePassword: changePassword,
Theme: setting.UI.DefaultTheme,
}
if err := models.CreateUser(u); err != nil {
}); 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)
fmt.Printf("New user '%s' has been successfully created!\n", c.String("name"))
return nil
}
@@ -377,11 +356,9 @@ func runRepoSyncReleases(c *cli.Context) error {
log.Trace("Synchronizing repository releases (this may take a while)")
for page := 1; ; page++ {
repos, count, err := models.SearchRepositoryByName(&models.SearchRepoOptions{
ListOptions: models.ListOptions{
PageSize: models.RepositoryListDefaultPageSize,
Page: page,
},
Private: true,
Page: page,
PageSize: models.RepositoryListDefaultPageSize,
Private: true,
})
if err != nil {
return fmt.Errorf("SearchRepositoryByName: %v", err)
@@ -404,22 +381,19 @@ func runRepoSyncReleases(c *cli.Context) error {
}
log.Trace(" currentNumReleases is %d, running SyncReleasesWithTags", oldnum)
if err = repo_module.SyncReleasesWithTags(repo, gitRepo); err != nil {
if err = models.SyncReleasesWithTags(repo, gitRepo); err != nil {
log.Warn(" SyncReleasesWithTags: %v", err)
gitRepo.Close()
continue
}
count, err = getReleaseCount(repo.ID)
if err != nil {
log.Warn(" GetReleaseCountByRepoID: %v", err)
gitRepo.Close()
continue
}
log.Trace(" repo %s releases synchronized to tags: from %d to %d",
repo.FullName(), oldnum, count)
gitRepo.Close()
}
}
@@ -436,13 +410,21 @@ func getReleaseCount(id int64) (int64, error) {
}
func runRegenerateHooks(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
if err := initDB(); err != nil {
return err
}
return repo_module.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
return models.SyncRepositoryHooks()
}
func runRegenerateKeys(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
if err := initDB(); err != nil {
return err
}
@@ -471,6 +453,10 @@ func parseOAuth2Config(c *cli.Context) *models.OAuth2Config {
}
func runAddOauth(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
if err := initDB(); err != nil {
return err
}
@@ -484,6 +470,10 @@ func runAddOauth(c *cli.Context) error {
}
func runUpdateOauth(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
if !c.IsSet("id") {
return fmt.Errorf("--id flag is missing")
}
@@ -520,7 +510,7 @@ func runUpdateOauth(c *cli.Context) error {
}
// update custom URL mapping
var customURLMapping = &oauth2.CustomURLMapping{}
var customURLMapping *oauth2.CustomURLMapping
if oAuth2Config.CustomURLMapping != nil {
customURLMapping.TokenURL = oAuth2Config.CustomURLMapping.TokenURL
@@ -551,6 +541,10 @@ func runUpdateOauth(c *cli.Context) error {
}
func runListAuth(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
if err := initDB(); err != nil {
return err
}
@@ -561,21 +555,11 @@ func runListAuth(c *cli.Context) error {
return err
}
flags := tabwriter.AlignRight
if c.Bool("vertical-bars") {
flags |= tabwriter.Debug
}
padChar := byte('\t')
if len(c.String("pad-char")) > 0 {
padChar = c.String("pad-char")[0]
}
// loop through each source and print
w := tabwriter.NewWriter(os.Stdout, c.Int("min-width"), c.Int("tab-width"), c.Int("padding"), padChar, flags)
fmt.Fprintf(w, "ID\tName\tType\tEnabled\n")
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.AlignRight)
fmt.Fprintf(w, "ID\tName\tType\tEnabled")
for _, source := range loginSources {
fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", source.ID, source.Name, models.LoginNames[source.Type], source.IsActived)
fmt.Fprintf(w, "%d\t%s\t%s\t%t", source.ID, source.Name, models.LoginNames[source.Type], source.IsActived)
}
w.Flush()
@@ -583,6 +567,10 @@ func runListAuth(c *cli.Context) error {
}
func runDeleteAuth(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
if !c.IsSet("id") {
return fmt.Errorf("--id flag is missing")
}

View File

@@ -1,373 +0,0 @@
// 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.
package cmd
import (
"fmt"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth/ldap"
"github.com/urfave/cli"
)
type (
authService struct {
initDB func() error
createLoginSource func(loginSource *models.LoginSource) error
updateLoginSource func(loginSource *models.LoginSource) error
getLoginSourceByID func(id int64) (*models.LoginSource, error)
}
)
var (
commonLdapCLIFlags = []cli.Flag{
cli.StringFlag{
Name: "name",
Usage: "Authentication name.",
},
cli.BoolFlag{
Name: "not-active",
Usage: "Deactivate the authentication source.",
},
cli.StringFlag{
Name: "security-protocol",
Usage: "Security protocol name.",
},
cli.BoolFlag{
Name: "skip-tls-verify",
Usage: "Disable TLS verification.",
},
cli.StringFlag{
Name: "host",
Usage: "The address where the LDAP server can be reached.",
},
cli.IntFlag{
Name: "port",
Usage: "The port to use when connecting to the LDAP server.",
},
cli.StringFlag{
Name: "user-search-base",
Usage: "The LDAP base at which user accounts will be searched for.",
},
cli.StringFlag{
Name: "user-filter",
Usage: "An LDAP filter declaring how to find the user record that is attempting to authenticate.",
},
cli.StringFlag{
Name: "admin-filter",
Usage: "An LDAP filter specifying if a user should be given administrator privileges.",
},
cli.StringFlag{
Name: "restricted-filter",
Usage: "An LDAP filter specifying if a user should be given restricted status.",
},
cli.BoolFlag{
Name: "allow-deactivate-all",
Usage: "Allow empty search results to deactivate all users.",
},
cli.StringFlag{
Name: "username-attribute",
Usage: "The attribute of the users LDAP record containing the user name.",
},
cli.StringFlag{
Name: "firstname-attribute",
Usage: "The attribute of the users LDAP record containing the users first name.",
},
cli.StringFlag{
Name: "surname-attribute",
Usage: "The attribute of the users LDAP record containing the users surname.",
},
cli.StringFlag{
Name: "email-attribute",
Usage: "The attribute of the users LDAP record containing the users email address.",
},
cli.StringFlag{
Name: "public-ssh-key-attribute",
Usage: "The attribute of the users LDAP record containing the users public ssh key.",
},
}
ldapBindDnCLIFlags = append(commonLdapCLIFlags,
cli.StringFlag{
Name: "bind-dn",
Usage: "The DN to bind to the LDAP server with when searching for the user.",
},
cli.StringFlag{
Name: "bind-password",
Usage: "The password for the Bind DN, if any.",
},
cli.BoolFlag{
Name: "attributes-in-bind",
Usage: "Fetch attributes in bind DN context.",
},
cli.BoolFlag{
Name: "synchronize-users",
Usage: "Enable user synchronization.",
},
cli.UintFlag{
Name: "page-size",
Usage: "Search page size.",
})
ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags,
cli.StringFlag{
Name: "user-dn",
Usage: "The users DN.",
})
cmdAuthAddLdapBindDn = cli.Command{
Name: "add-ldap",
Usage: "Add new LDAP (via Bind DN) authentication source",
Action: func(c *cli.Context) error {
return newAuthService().addLdapBindDn(c)
},
Flags: ldapBindDnCLIFlags,
}
cmdAuthUpdateLdapBindDn = cli.Command{
Name: "update-ldap",
Usage: "Update existing LDAP (via Bind DN) authentication source",
Action: func(c *cli.Context) error {
return newAuthService().updateLdapBindDn(c)
},
Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...),
}
cmdAuthAddLdapSimpleAuth = cli.Command{
Name: "add-ldap-simple",
Usage: "Add new LDAP (simple auth) authentication source",
Action: func(c *cli.Context) error {
return newAuthService().addLdapSimpleAuth(c)
},
Flags: ldapSimpleAuthCLIFlags,
}
cmdAuthUpdateLdapSimpleAuth = cli.Command{
Name: "update-ldap-simple",
Usage: "Update existing LDAP (simple auth) authentication source",
Action: func(c *cli.Context) error {
return newAuthService().updateLdapSimpleAuth(c)
},
Flags: append([]cli.Flag{idFlag}, ldapSimpleAuthCLIFlags...),
}
)
// newAuthService creates a service with default functions.
func newAuthService() *authService {
return &authService{
initDB: initDB,
createLoginSource: models.CreateLoginSource,
updateLoginSource: models.UpdateSource,
getLoginSourceByID: models.GetLoginSourceByID,
}
}
// parseLoginSource assigns values on loginSource according to command line flags.
func parseLoginSource(c *cli.Context, loginSource *models.LoginSource) {
if c.IsSet("name") {
loginSource.Name = c.String("name")
}
if c.IsSet("not-active") {
loginSource.IsActived = !c.Bool("not-active")
}
if c.IsSet("synchronize-users") {
loginSource.IsSyncEnabled = c.Bool("synchronize-users")
}
}
// parseLdapConfig assigns values on config according to command line flags.
func parseLdapConfig(c *cli.Context, config *models.LDAPConfig) error {
if c.IsSet("name") {
config.Source.Name = c.String("name")
}
if c.IsSet("host") {
config.Source.Host = c.String("host")
}
if c.IsSet("port") {
config.Source.Port = c.Int("port")
}
if c.IsSet("security-protocol") {
p, ok := findLdapSecurityProtocolByName(c.String("security-protocol"))
if !ok {
return fmt.Errorf("Unknown security protocol name: %s", c.String("security-protocol"))
}
config.Source.SecurityProtocol = p
}
if c.IsSet("skip-tls-verify") {
config.Source.SkipVerify = c.Bool("skip-tls-verify")
}
if c.IsSet("bind-dn") {
config.Source.BindDN = c.String("bind-dn")
}
if c.IsSet("user-dn") {
config.Source.UserDN = c.String("user-dn")
}
if c.IsSet("bind-password") {
config.Source.BindPassword = c.String("bind-password")
}
if c.IsSet("user-search-base") {
config.Source.UserBase = c.String("user-search-base")
}
if c.IsSet("username-attribute") {
config.Source.AttributeUsername = c.String("username-attribute")
}
if c.IsSet("firstname-attribute") {
config.Source.AttributeName = c.String("firstname-attribute")
}
if c.IsSet("surname-attribute") {
config.Source.AttributeSurname = c.String("surname-attribute")
}
if c.IsSet("email-attribute") {
config.Source.AttributeMail = c.String("email-attribute")
}
if c.IsSet("attributes-in-bind") {
config.Source.AttributesInBind = c.Bool("attributes-in-bind")
}
if c.IsSet("public-ssh-key-attribute") {
config.Source.AttributeSSHPublicKey = c.String("public-ssh-key-attribute")
}
if c.IsSet("page-size") {
config.Source.SearchPageSize = uint32(c.Uint("page-size"))
}
if c.IsSet("user-filter") {
config.Source.Filter = c.String("user-filter")
}
if c.IsSet("admin-filter") {
config.Source.AdminFilter = c.String("admin-filter")
}
if c.IsSet("restricted-filter") {
config.Source.RestrictedFilter = c.String("restricted-filter")
}
if c.IsSet("allow-deactivate-all") {
config.Source.AllowDeactivateAll = c.Bool("allow-deactivate-all")
}
return nil
}
// findLdapSecurityProtocolByName finds security protocol by its name ignoring case.
// It returns the value of the security protocol and if it was found.
func findLdapSecurityProtocolByName(name string) (ldap.SecurityProtocol, bool) {
for i, n := range models.SecurityProtocolNames {
if strings.EqualFold(name, n) {
return i, true
}
}
return 0, false
}
// getLoginSource gets the login source by its id defined in the command line flags.
// It returns an error if the id is not set, does not match any source or if the source is not of expected type.
func (a *authService) getLoginSource(c *cli.Context, loginType models.LoginType) (*models.LoginSource, error) {
if err := argsSet(c, "id"); err != nil {
return nil, err
}
loginSource, err := a.getLoginSourceByID(c.Int64("id"))
if err != nil {
return nil, err
}
if loginSource.Type != loginType {
return nil, fmt.Errorf("Invalid authentication type. expected: %s, actual: %s", models.LoginNames[loginType], models.LoginNames[loginSource.Type])
}
return loginSource, nil
}
// addLdapBindDn adds a new LDAP via Bind DN authentication source.
func (a *authService) addLdapBindDn(c *cli.Context) error {
if err := argsSet(c, "name", "security-protocol", "host", "port", "user-search-base", "user-filter", "email-attribute"); err != nil {
return err
}
if err := a.initDB(); err != nil {
return err
}
loginSource := &models.LoginSource{
Type: models.LoginLDAP,
IsActived: true, // active by default
Cfg: &models.LDAPConfig{
Source: &ldap.Source{
Enabled: true, // always true
},
},
}
parseLoginSource(c, loginSource)
if err := parseLdapConfig(c, loginSource.LDAP()); err != nil {
return err
}
return a.createLoginSource(loginSource)
}
// updateLdapBindDn updates a new LDAP via Bind DN authentication source.
func (a *authService) updateLdapBindDn(c *cli.Context) error {
if err := a.initDB(); err != nil {
return err
}
loginSource, err := a.getLoginSource(c, models.LoginLDAP)
if err != nil {
return err
}
parseLoginSource(c, loginSource)
if err := parseLdapConfig(c, loginSource.LDAP()); err != nil {
return err
}
return a.updateLoginSource(loginSource)
}
// addLdapSimpleAuth adds a new LDAP (simple auth) authentication source.
func (a *authService) addLdapSimpleAuth(c *cli.Context) error {
if err := argsSet(c, "name", "security-protocol", "host", "port", "user-dn", "user-filter", "email-attribute"); err != nil {
return err
}
if err := a.initDB(); err != nil {
return err
}
loginSource := &models.LoginSource{
Type: models.LoginDLDAP,
IsActived: true, // active by default
Cfg: &models.LDAPConfig{
Source: &ldap.Source{
Enabled: true, // always true
},
},
}
parseLoginSource(c, loginSource)
if err := parseLdapConfig(c, loginSource.LDAP()); err != nil {
return err
}
return a.createLoginSource(loginSource)
}
// updateLdapBindDn updates a new LDAP (simple auth) authentication source.
func (a *authService) updateLdapSimpleAuth(c *cli.Context) error {
if err := a.initDB(); err != nil {
return err
}
loginSource, err := a.getLoginSource(c, models.LoginDLDAP)
if err != nil {
return err
}
parseLoginSource(c, loginSource)
if err := parseLdapConfig(c, loginSource.LDAP()); err != nil {
return err
}
return a.updateLoginSource(loginSource)
}

File diff suppressed because it is too large Load Diff

View File

@@ -170,28 +170,17 @@ func runCert(c *cli.Context) error {
if err != nil {
log.Fatalf("Failed to open cert.pem for writing: %v", err)
}
err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
if err != nil {
log.Fatalf("Failed to encode certificate: %v", err)
}
err = certOut.Close()
if err != nil {
log.Fatalf("Failed to write cert: %v", err)
}
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
certOut.Close()
log.Println("Written cert.pem")
keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
log.Fatalf("Failed to open key.pem for writing: %v", err)
}
err = pem.Encode(keyOut, pemBlockForKey(priv))
if err != nil {
log.Fatalf("Failed to encode key: %v", err)
}
err = keyOut.Close()
if err != nil {
log.Fatalf("Failed to write key: %v", err)
}
pem.Encode(keyOut, pemBlockForKey(priv))
keyOut.Close()
log.Println("Written key.pem")
return nil
}

View File

@@ -38,7 +38,7 @@ func initDB() error {
func initDBDisableConsole(disableConsole bool) error {
setting.NewContext()
setting.InitDBConfig()
models.LoadConfigs()
setting.NewXORMLogService(disableConsole)
if err := models.SetEngine(); err != nil {

View File

@@ -1,49 +0,0 @@
// 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.
package cmd
import (
"fmt"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli"
)
// CmdConvert represents the available convert sub-command.
var CmdConvert = cli.Command{
Name: "convert",
Usage: "Convert the database",
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
Action: runConvert,
}
func runConvert(ctx *cli.Context) error {
if err := initDB(); err != nil {
return err
}
log.Trace("AppPath: %s", setting.AppPath)
log.Trace("AppWorkPath: %s", setting.AppWorkPath)
log.Trace("Custom path: %s", setting.CustomPath)
log.Trace("Log path: %s", setting.LogRootPath)
setting.InitDBConfig()
if !setting.Database.UseMySQL {
fmt.Println("This command can only be used with a MySQL database")
return nil
}
if err := models.ConvertUtf8ToUtf8mb4(); err != nil {
log.Fatal("Failed to convert database from utf8 to utf8mb4: %v", err)
return err
}
fmt.Println("Converted successfully, please confirm your database's character set is now utf8mb4")
return nil
}

View File

@@ -1,606 +0,0 @@
// 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.
package cmd
import (
"bufio"
"bytes"
"context"
"fmt"
"io/ioutil"
golog "log"
"os"
"os/exec"
"path/filepath"
"strings"
"text/tabwriter"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/migrations"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/options"
"code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"xorm.io/builder"
"github.com/urfave/cli"
)
// CmdDoctor represents the available doctor sub-command.
var CmdDoctor = cli.Command{
Name: "doctor",
Usage: "Diagnose problems",
Description: "A command to diagnose problems with the current Gitea instance according to the given configuration.",
Action: runDoctor,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "list",
Usage: "List the available checks",
},
cli.BoolFlag{
Name: "default",
Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)",
},
cli.StringSliceFlag{
Name: "run",
Usage: "Run the provided checks - (if --default is set, the default checks will also run)",
},
cli.BoolFlag{
Name: "all",
Usage: "Run all the available checks",
},
cli.BoolFlag{
Name: "fix",
Usage: "Automatically fix what we can",
},
cli.StringFlag{
Name: "log-file",
Usage: `Name of the log file (default: "doctor.log"). Set to "-" to output to stdout, set to "" to disable`,
},
},
}
type check struct {
title string
name string
isDefault bool
f func(ctx *cli.Context) ([]string, error)
abortIfFailed bool
skipDatabaseInit bool
}
// checklist represents list for all checks
var checklist = []check{
{
// NOTE: this check should be the first in the list
title: "Check paths and basic configuration",
name: "paths",
isDefault: true,
f: runDoctorPathInfo,
abortIfFailed: true,
skipDatabaseInit: true,
},
{
title: "Check Database Version",
name: "check-db-version",
isDefault: true,
f: runDoctorCheckDBVersion,
abortIfFailed: false,
},
{
title: "Check consistency of database",
name: "check-db-consistency",
isDefault: false,
f: runDoctorCheckDBConsistency,
},
{
title: "Check if OpenSSH authorized_keys file is up-to-date",
name: "authorized_keys",
isDefault: true,
f: runDoctorAuthorizedKeys,
},
{
title: "Check if SCRIPT_TYPE is available",
name: "script-type",
isDefault: false,
f: runDoctorScriptType,
},
{
title: "Check if hook files are up-to-date and executable",
name: "hooks",
isDefault: false,
f: runDoctorHooks,
},
{
title: "Recalculate merge bases",
name: "recalculate_merge_bases",
isDefault: false,
f: runDoctorPRMergeBase,
},
{
title: "Recalculate Stars number for all user",
name: "recalculate_stars_number",
isDefault: false,
f: runDoctorUserStarNum,
},
// more checks please append here
}
func runDoctor(ctx *cli.Context) error {
// Silence the default loggers
log.DelNamedLogger("console")
log.DelNamedLogger(log.DEFAULT)
// Now setup our own
logFile := ctx.String("log-file")
if !ctx.IsSet("log-file") {
logFile = "doctor.log"
}
if len(logFile) == 0 {
log.NewLogger(1000, "doctor", "console", `{"level":"NONE","stacktracelevel":"NONE","colorize":"%t"}`)
} else if logFile == "-" {
log.NewLogger(1000, "doctor", "console", `{"level":"trace","stacktracelevel":"NONE"}`)
} else {
log.NewLogger(1000, "doctor", "file", fmt.Sprintf(`{"filename":%q,"level":"trace","stacktracelevel":"NONE"}`, logFile))
}
// Finally redirect the default golog to here
golog.SetFlags(0)
golog.SetPrefix("")
golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT)))
if ctx.IsSet("list") {
w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
_, _ = w.Write([]byte("Default\tName\tTitle\n"))
for _, check := range checklist {
if check.isDefault {
_, _ = w.Write([]byte{'*'})
}
_, _ = w.Write([]byte{'\t'})
_, _ = w.Write([]byte(check.name))
_, _ = w.Write([]byte{'\t'})
_, _ = w.Write([]byte(check.title))
_, _ = w.Write([]byte{'\n'})
}
return w.Flush()
}
var checks []check
if ctx.Bool("all") {
checks = checklist
} else if ctx.IsSet("run") {
addDefault := ctx.Bool("default")
names := ctx.StringSlice("run")
for i, name := range names {
names[i] = strings.ToLower(strings.TrimSpace(name))
}
for _, check := range checklist {
if addDefault && check.isDefault {
checks = append(checks, check)
continue
}
for _, name := range names {
if name == check.name {
checks = append(checks, check)
break
}
}
}
} else {
for _, check := range checklist {
if check.isDefault {
checks = append(checks, check)
}
}
}
dbIsInit := false
for i, check := range checks {
if !dbIsInit && !check.skipDatabaseInit {
// Only open database after the most basic configuration check
setting.EnableXORMLog = false
if err := initDBDisableConsole(true); err != nil {
fmt.Println(err)
fmt.Println("Check if you are using the right config file. You can use a --config directive to specify one.")
return nil
}
dbIsInit = true
}
fmt.Println("[", i+1, "]", check.title)
messages, err := check.f(ctx)
for _, message := range messages {
fmt.Println("-", message)
}
if err != nil {
fmt.Println("Error:", err)
if check.abortIfFailed {
return nil
}
} else {
fmt.Println("OK.")
}
fmt.Println()
}
return nil
}
func runDoctorPathInfo(ctx *cli.Context) ([]string, error) {
res := make([]string, 0, 10)
if fi, err := os.Stat(setting.CustomConf); err != nil || !fi.Mode().IsRegular() {
res = append(res, fmt.Sprintf("Failed to find configuration file at '%s'.", setting.CustomConf))
res = append(res, fmt.Sprintf("If you've never ran Gitea yet, this is normal and '%s' will be created for you on first run.", setting.CustomConf))
res = append(res, "Otherwise check that you are running this command from the correct path and/or provide a `--config` parameter.")
return res, fmt.Errorf("can't proceed without a configuration file")
}
setting.NewContext()
fail := false
check := func(name, path string, is_dir, required, is_write bool) {
res = append(res, fmt.Sprintf("%-25s '%s'", name+":", path))
fi, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) && ctx.Bool("fix") && is_dir {
if err := os.MkdirAll(path, 0777); err != nil {
res = append(res, fmt.Sprintf(" ERROR: %v", err))
fail = true
return
}
fi, err = os.Stat(path)
}
}
if err != nil {
if required {
res = append(res, fmt.Sprintf(" ERROR: %v", err))
fail = true
return
}
res = append(res, fmt.Sprintf(" NOTICE: not accessible (%v)", err))
return
}
if is_dir && !fi.IsDir() {
res = append(res, " ERROR: not a directory")
fail = true
return
} else if !is_dir && !fi.Mode().IsRegular() {
res = append(res, " ERROR: not a regular file")
fail = true
} else if is_write {
if err := runDoctorWritableDir(path); err != nil {
res = append(res, fmt.Sprintf(" ERROR: not writable: %v", err))
fail = true
}
}
}
// Note print paths inside quotes to make any leading/trailing spaces evident
check("Configuration File Path", setting.CustomConf, false, true, false)
check("Repository Root Path", setting.RepoRootPath, true, true, true)
check("Data Root Path", setting.AppDataPath, true, true, true)
check("Custom File Root Path", setting.CustomPath, true, false, false)
check("Work directory", setting.AppWorkPath, true, true, false)
check("Log Root Path", setting.LogRootPath, true, true, true)
if options.IsDynamic() {
// Do not check/report on StaticRootPath if data is embedded in Gitea (-tags bindata)
check("Static File Root Path", setting.StaticRootPath, true, true, false)
}
if fail {
return res, fmt.Errorf("please check your configuration file and try again")
}
return res, nil
}
func runDoctorWritableDir(path string) error {
// There's no platform-independent way of checking if a directory is writable
// https://stackoverflow.com/questions/20026320/how-to-tell-if-folder-exists-and-is-writable
tmpFile, err := ioutil.TempFile(path, "doctors-order")
if err != nil {
return err
}
if err := os.Remove(tmpFile.Name()); err != nil {
fmt.Printf("Warning: can't remove temporary file: '%s'\n", tmpFile.Name())
}
tmpFile.Close()
return nil
}
const tplCommentPrefix = `# gitea public key`
func runDoctorAuthorizedKeys(ctx *cli.Context) ([]string, error) {
if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile {
return nil, nil
}
fPath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
f, err := os.Open(fPath)
if err != nil {
if ctx.Bool("fix") {
return []string{fmt.Sprintf("Error whilst opening authorized_keys: %v. Attempting regeneration", err)}, models.RewriteAllPublicKeys()
}
return nil, err
}
defer f.Close()
linesInAuthorizedKeys := map[string]bool{}
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, tplCommentPrefix) {
continue
}
linesInAuthorizedKeys[line] = true
}
f.Close()
// now we regenerate and check if there are any lines missing
regenerated := &bytes.Buffer{}
if err := models.RegeneratePublicKeys(regenerated); err != nil {
return nil, err
}
scanner = bufio.NewScanner(regenerated)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, tplCommentPrefix) {
continue
}
if ok := linesInAuthorizedKeys[line]; ok {
continue
}
if ctx.Bool("fix") {
return []string{"authorized_keys is out of date, attempting regeneration"}, models.RewriteAllPublicKeys()
}
return nil, fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized_keys --fix"`)
}
return nil, nil
}
func runDoctorCheckDBVersion(ctx *cli.Context) ([]string, error) {
if err := models.NewEngine(context.Background(), migrations.EnsureUpToDate); err != nil {
if ctx.Bool("fix") {
return []string{fmt.Sprintf("WARN: Got Error %v during ensure up to date", err), "Attempting to migrate to the latest DB version to fix this."}, models.NewEngine(context.Background(), migrations.Migrate)
}
return nil, err
}
return nil, nil
}
func iterateRepositories(each func(*models.Repository) ([]string, error)) ([]string, error) {
results := []string{}
err := models.Iterate(
models.DefaultDBContext(),
new(models.Repository),
builder.Gt{"id": 0},
func(idx int, bean interface{}) error {
res, err := each(bean.(*models.Repository))
results = append(results, res...)
return err
},
)
return results, err
}
func iteratePRs(repo *models.Repository, each func(*models.Repository, *models.PullRequest) ([]string, error)) ([]string, error) {
results := []string{}
err := models.Iterate(
models.DefaultDBContext(),
new(models.PullRequest),
builder.Eq{"base_repo_id": repo.ID},
func(idx int, bean interface{}) error {
res, err := each(repo, bean.(*models.PullRequest))
results = append(results, res...)
return err
},
)
return results, err
}
func runDoctorHooks(ctx *cli.Context) ([]string, error) {
// Need to iterate across all of the repositories
return iterateRepositories(func(repo *models.Repository) ([]string, error) {
results, err := repository.CheckDelegateHooks(repo.RepoPath())
if err != nil {
return nil, err
}
if len(results) > 0 && ctx.Bool("fix") {
return []string{fmt.Sprintf("regenerated hooks for %s", repo.FullName())}, repository.CreateDelegateHooks(repo.RepoPath())
}
return results, nil
})
}
func runDoctorPRMergeBase(ctx *cli.Context) ([]string, error) {
numRepos := 0
numPRs := 0
numPRsUpdated := 0
results, err := iterateRepositories(func(repo *models.Repository) ([]string, error) {
numRepos++
return iteratePRs(repo, func(repo *models.Repository, pr *models.PullRequest) ([]string, error) {
numPRs++
results := []string{}
pr.BaseRepo = repo
repoPath := repo.RepoPath()
oldMergeBase := pr.MergeBase
if !pr.HasMerged {
var err error
pr.MergeBase, err = git.NewCommand("merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunInDir(repoPath)
if err != nil {
var err2 error
pr.MergeBase, err2 = git.NewCommand("rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath)
if err2 != nil {
results = append(results, fmt.Sprintf("WARN: Unable to get merge base for PR ID %d, #%d onto %s in %s/%s", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name))
log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err, err2)
return results, nil
}
}
} else {
parentsString, err := git.NewCommand("rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath)
if err != nil {
results = append(results, fmt.Sprintf("WARN: Unable to get parents for merged PR ID %d, #%d onto %s in %s/%s", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name))
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err)
return results, nil
}
parents := strings.Split(strings.TrimSpace(parentsString), " ")
if len(parents) < 2 {
return results, nil
}
args := append([]string{"merge-base", "--"}, parents[1:]...)
args = append(args, pr.GetGitRefName())
pr.MergeBase, err = git.NewCommand(args...).RunInDir(repoPath)
if err != nil {
results = append(results, fmt.Sprintf("WARN: Unable to get merge base for merged PR ID %d, #%d onto %s in %s/%s", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name))
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err)
return results, nil
}
}
pr.MergeBase = strings.TrimSpace(pr.MergeBase)
if pr.MergeBase != oldMergeBase {
if ctx.Bool("fix") {
if err := pr.UpdateCols("merge_base"); err != nil {
return results, err
}
} else {
results = append(results, fmt.Sprintf("#%d onto %s in %s/%s: MergeBase should be %s but is %s", pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, oldMergeBase, pr.MergeBase))
}
numPRsUpdated++
}
return results, nil
})
})
if ctx.Bool("fix") {
results = append(results, fmt.Sprintf("%d PR mergebases updated of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos))
} else {
if numPRsUpdated > 0 && err == nil {
return results, fmt.Errorf("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos)
}
results = append(results, fmt.Sprintf("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos))
}
return results, err
}
func runDoctorUserStarNum(ctx *cli.Context) ([]string, error) {
return nil, models.DoctorUserStarNum()
}
func runDoctorScriptType(ctx *cli.Context) ([]string, error) {
path, err := exec.LookPath(setting.ScriptType)
if err != nil {
return []string{fmt.Sprintf("ScriptType %s is not on the current PATH", setting.ScriptType)}, err
}
return []string{fmt.Sprintf("ScriptType %s is on the current PATH at %s", setting.ScriptType, path)}, nil
}
func runDoctorCheckDBConsistency(ctx *cli.Context) ([]string, error) {
var results []string
// make sure DB version is uptodate
if err := models.NewEngine(context.Background(), migrations.EnsureUpToDate); err != nil {
return nil, fmt.Errorf("model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded")
}
//find labels without existing repo or org
count, err := models.CountOrphanedLabels()
if err != nil {
return nil, err
}
if count > 0 {
if ctx.Bool("fix") {
if err = models.DeleteOrphanedLabels(); err != nil {
return nil, err
}
results = append(results, fmt.Sprintf("%d labels without existing repository/organisation deleted", count))
} else {
results = append(results, fmt.Sprintf("%d labels without existing repository/organisation", count))
}
}
//find issues without existing repository
count, err = models.CountOrphanedIssues()
if err != nil {
return nil, err
}
if count > 0 {
if ctx.Bool("fix") {
if err = models.DeleteOrphanedIssues(); err != nil {
return nil, err
}
results = append(results, fmt.Sprintf("%d issues without existing repository deleted", count))
} else {
results = append(results, fmt.Sprintf("%d issues without existing repository", count))
}
}
//find pulls without existing issues
count, err = models.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
if err != nil {
return nil, err
}
if count > 0 {
if ctx.Bool("fix") {
if err = models.DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id"); err != nil {
return nil, err
}
results = append(results, fmt.Sprintf("%d pull requests without existing issue deleted", count))
} else {
results = append(results, fmt.Sprintf("%d pull requests without existing issue", count))
}
}
//find tracked times without existing issues/pulls
count, err = models.CountOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id")
if err != nil {
return nil, err
}
if count > 0 {
if ctx.Bool("fix") {
if err = models.DeleteOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id"); err != nil {
return nil, err
}
results = append(results, fmt.Sprintf("%d tracked times without existing issue deleted", count))
} else {
results = append(results, fmt.Sprintf("%d tracked times without existing issue", count))
}
}
count, err = models.CountNullArchivedRepository()
if err != nil {
return nil, err
}
if count > 0 {
if ctx.Bool("fix") {
updatedCount, err := models.FixNullArchivedRepository()
if err != nil {
return nil, err
}
results = append(results, fmt.Sprintf("%d repositories with null is_archived updated", updatedCount))
} else {
results = append(results, fmt.Sprintf("%d repositories with null is_archived", count))
}
}
//ToDo: function to recalc all counters
return results, nil
}

View File

@@ -8,17 +8,17 @@ package cmd
import (
"fmt"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/unknwon/cae/zip"
"github.com/unknwon/com"
"github.com/Unknwon/cae/zip"
"github.com/Unknwon/com"
"github.com/urfave/cli"
)
@@ -31,12 +31,12 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
Action: runDump,
Flags: []cli.Flag{
cli.StringFlag{
Name: "file, f",
Value: fmt.Sprintf("gitea-dump-%d.zip", time.Now().Unix()),
Usage: "Name of the dump file which will be created.",
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
cli.BoolFlag{
Name: "verbose, V",
Name: "verbose, v",
Usage: "Show process details",
},
cli.StringFlag{
@@ -48,25 +48,16 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
Name: "database, d",
Usage: "Specify the database SQL syntax",
},
cli.BoolFlag{
Name: "skip-repository, R",
Usage: "Skip the repository dumping",
},
cli.BoolFlag{
Name: "skip-log, L",
Usage: "Skip the log dumping",
},
},
}
func fatal(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, format+"\n", args...)
log.Fatal(format, args...)
}
func runDump(ctx *cli.Context) error {
if ctx.IsSet("config") {
setting.CustomConf = ctx.String("config")
}
setting.NewContext()
setting.NewServices() // cannot access session settings otherwise
models.LoadConfigs()
err := models.SetEngine()
if err != nil {
@@ -75,112 +66,92 @@ func runDump(ctx *cli.Context) error {
tmpDir := ctx.String("tempdir")
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
fatal("Path does not exist: %s", tmpDir)
log.Fatalf("Path does not exist: %s", tmpDir)
}
tmpWorkDir, err := ioutil.TempDir(tmpDir, "gitea-dump-")
if err != nil {
fatal("Failed to create tmp work directory: %v", err)
log.Fatalf("Failed to create tmp work directory: %v", err)
}
log.Info("Creating tmp work dir: %s", tmpWorkDir)
log.Printf("Creating tmp work dir: %s", tmpWorkDir)
// work-around #1103
if os.Getenv("TMPDIR") == "" {
os.Setenv("TMPDIR", tmpWorkDir)
}
reposDump := path.Join(tmpWorkDir, "gitea-repo.zip")
dbDump := path.Join(tmpWorkDir, "gitea-db.sql")
fileName := ctx.String("file")
log.Info("Packing dump files...")
z, err := zip.Create(fileName)
if err != nil {
fatal("Failed to create %s: %v", fileName, err)
}
log.Printf("Dumping local repositories...%s", setting.RepoRootPath)
zip.Verbose = ctx.Bool("verbose")
if ctx.IsSet("skip-repository") && ctx.Bool("skip-repository") {
log.Info("Skip dumping local repositories")
} else {
log.Info("Dumping local repositories...%s", setting.RepoRootPath)
reposDump := path.Join(tmpWorkDir, "gitea-repo.zip")
if err := zip.PackTo(setting.RepoRootPath, reposDump, true); err != nil {
fatal("Failed to dump local repositories: %v", err)
}
if err := z.AddFile("gitea-repo.zip", reposDump); err != nil {
fatal("Failed to include gitea-repo.zip: %v", err)
}
if err := zip.PackTo(setting.RepoRootPath, reposDump, true); err != nil {
log.Fatalf("Failed to dump local repositories: %v", err)
}
targetDBType := ctx.String("database")
if len(targetDBType) > 0 && targetDBType != setting.Database.Type {
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
if len(targetDBType) > 0 && targetDBType != models.DbCfg.Type {
log.Printf("Dumping database %s => %s...", models.DbCfg.Type, targetDBType)
} else {
log.Info("Dumping database...")
log.Printf("Dumping database...")
}
if err := models.DumpDatabase(dbDump, targetDBType); err != nil {
fatal("Failed to dump database: %v", err)
log.Fatalf("Failed to dump database: %v", err)
}
fileName := fmt.Sprintf("gitea-dump-%d.zip", time.Now().Unix())
log.Printf("Packing dump files...")
z, err := zip.Create(fileName)
if err != nil {
log.Fatalf("Failed to create %s: %v", fileName, err)
}
if err := z.AddFile("gitea-repo.zip", reposDump); err != nil {
log.Fatalf("Failed to include gitea-repo.zip: %v", err)
}
if err := z.AddFile("gitea-db.sql", dbDump); err != nil {
fatal("Failed to include gitea-db.sql: %v", err)
log.Fatalf("Failed to include gitea-db.sql: %v", err)
}
if len(setting.CustomConf) > 0 {
log.Info("Adding custom configuration file from %s", setting.CustomConf)
if err := z.AddFile("app.ini", setting.CustomConf); err != nil {
fatal("Failed to include specified app.ini: %v", err)
}
}
customDir, err := os.Stat(setting.CustomPath)
if err == nil && customDir.IsDir() {
if err := z.AddDir("custom", setting.CustomPath); err != nil {
fatal("Failed to include custom: %v", err)
log.Fatalf("Failed to include custom: %v", err)
}
} else {
log.Info("Custom dir %s doesn't exist, skipped", setting.CustomPath)
log.Printf("Custom dir %s doesn't exist, skipped", setting.CustomPath)
}
if com.IsExist(setting.AppDataPath) {
log.Info("Packing data directory...%s", setting.AppDataPath)
log.Printf("Packing data directory...%s", setting.AppDataPath)
var sessionAbsPath string
if setting.SessionConfig.Provider == "file" {
sessionAbsPath = setting.SessionConfig.ProviderConfig
}
if err := zipAddDirectoryExclude(z, "data", setting.AppDataPath, sessionAbsPath); err != nil {
fatal("Failed to include data directory: %v", err)
log.Fatalf("Failed to include data directory: %v", err)
}
}
// Doesn't check if LogRootPath exists before processing --skip-log intentionally,
// ensuring that it's clear the dump is skipped whether the directory's initialized
// yet or not.
if ctx.IsSet("skip-log") && ctx.Bool("skip-log") {
log.Info("Skip dumping log files")
} else if com.IsExist(setting.LogRootPath) {
if err := z.AddDir("log", setting.LogRootPath); err != nil {
fatal("Failed to include log: %v", err)
}
if err := z.AddDir("log", setting.LogRootPath); err != nil {
log.Fatalf("Failed to include log: %v", err)
}
if err = z.Close(); err != nil {
_ = os.Remove(fileName)
fatal("Failed to save %s: %v", fileName, err)
log.Fatalf("Failed to save %s: %v", fileName, err)
}
if err := os.Chmod(fileName, 0600); err != nil {
log.Info("Can't change file access permissions mask to 0600: %v", err)
log.Printf("Can't change file access permissions mask to 0600: %v", err)
}
log.Info("Removing tmp work dir: %s", tmpWorkDir)
log.Printf("Removing tmp work dir: %s", tmpWorkDir)
if err := os.RemoveAll(tmpWorkDir); err != nil {
fatal("Failed to remove %s: %v", tmpWorkDir, err)
log.Fatalf("Failed to remove %s: %v", tmpWorkDir, err)
}
log.Info("Finish dumping in file %s", fileName)
log.Printf("Finish dumping in file %s", fileName)
return nil
}

View File

@@ -1,332 +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.
// +build bindata
package cmd
import (
"errors"
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/options"
"code.gitea.io/gitea/modules/public"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"github.com/gobwas/glob"
"github.com/urfave/cli"
)
// Cmdembedded represents the available extract sub-command.
var (
Cmdembedded = cli.Command{
Name: "embedded",
Usage: "Extract embedded resources",
Description: "A command for extracting embedded resources, like templates and images",
Subcommands: []cli.Command{
subcmdList,
subcmdView,
subcmdExtract,
},
}
subcmdList = cli.Command{
Name: "list",
Usage: "List files matching the given pattern",
Action: runList,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "include-vendored,vendor",
Usage: "Include files under public/vendor as well",
},
},
}
subcmdView = cli.Command{
Name: "view",
Usage: "View a file matching the given pattern",
Action: runView,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "include-vendored,vendor",
Usage: "Include files under public/vendor as well",
},
},
}
subcmdExtract = cli.Command{
Name: "extract",
Usage: "Extract resources",
Action: runExtract,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "include-vendored,vendor",
Usage: "Include files under public/vendor as well",
},
cli.BoolFlag{
Name: "overwrite",
Usage: "Overwrite files if they already exist",
},
cli.BoolFlag{
Name: "rename",
Usage: "Rename files as {name}.bak if they already exist (overwrites previous .bak)",
},
cli.BoolFlag{
Name: "custom",
Usage: "Extract to the 'custom' directory as per app.ini",
},
cli.StringFlag{
Name: "destination,dest-dir",
Usage: "Extract to the specified directory",
},
},
}
sections map[string]*section
assets []asset
)
type section struct {
Path string
Names func() []string
IsDir func(string) (bool, error)
Asset func(string) ([]byte, error)
}
type asset struct {
Section *section
Name string
Path string
}
func initEmbeddedExtractor(c *cli.Context) error {
// Silence the console logger
log.DelNamedLogger("console")
log.DelNamedLogger(log.DEFAULT)
// Read configuration file
setting.NewContext()
pats, err := getPatterns(c.Args())
if err != nil {
return err
}
sections := make(map[string]*section, 3)
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}
for _, sec := range sections {
assets = append(assets, buildAssetList(sec, pats, c)...)
}
// Sort assets
sort.SliceStable(assets, func(i, j int) bool {
return assets[i].Path < assets[j].Path
})
return nil
}
func runList(c *cli.Context) error {
if err := runListDo(c); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return err
}
return nil
}
func runView(c *cli.Context) error {
if err := runViewDo(c); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return err
}
return nil
}
func runExtract(c *cli.Context) error {
if err := runExtractDo(c); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return err
}
return nil
}
func runListDo(c *cli.Context) error {
if err := initEmbeddedExtractor(c); err != nil {
return err
}
for _, a := range assets {
fmt.Println(a.Path)
}
return nil
}
func runViewDo(c *cli.Context) error {
if err := initEmbeddedExtractor(c); err != nil {
return err
}
if len(assets) == 0 {
return fmt.Errorf("No files matched the given pattern")
} else if len(assets) > 1 {
return fmt.Errorf("Too many files matched the given pattern; try to be more specific")
}
data, err := assets[0].Section.Asset(assets[0].Name)
if err != nil {
return fmt.Errorf("%s: %v", assets[0].Path, err)
}
if _, err = os.Stdout.Write(data); err != nil {
return fmt.Errorf("%s: %v", assets[0].Path, err)
}
return nil
}
func runExtractDo(c *cli.Context) error {
if err := initEmbeddedExtractor(c); err != nil {
return err
}
if len(c.Args()) == 0 {
return fmt.Errorf("A list of pattern of files to extract is mandatory (e.g. '**' for all)")
}
destdir := "."
if c.IsSet("destination") {
destdir = c.String("destination")
} else if c.Bool("custom") {
destdir = setting.CustomPath
fmt.Println("Using app.ini at", setting.CustomConf)
}
fi, err := os.Stat(destdir)
if errors.Is(err, os.ErrNotExist) {
// In case Windows users attempt to provide a forward-slash path
wdestdir := filepath.FromSlash(destdir)
if wfi, werr := os.Stat(wdestdir); werr == nil {
destdir = wdestdir
fi = wfi
err = nil
}
}
if err != nil {
return fmt.Errorf("%s: %s", destdir, err)
} else if !fi.IsDir() {
return fmt.Errorf("%s is not a directory.", destdir)
}
fmt.Printf("Extracting to %s:\n", destdir)
overwrite := c.Bool("overwrite")
rename := c.Bool("rename")
for _, a := range assets {
if err := extractAsset(destdir, a, overwrite, rename); err != nil {
// Non-fatal error
fmt.Fprintf(os.Stderr, "%s: %v", a.Path, err)
}
}
return nil
}
func extractAsset(d string, a asset, overwrite, rename bool) error {
dest := filepath.Join(d, filepath.FromSlash(a.Path))
dir := filepath.Dir(dest)
data, err := a.Section.Asset(a.Name)
if err != nil {
return fmt.Errorf("%s: %v", a.Path, err)
}
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return fmt.Errorf("%s: %v", dir, err)
}
perms := os.ModePerm & 0666
fi, err := os.Lstat(dest)
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("%s: %v", dest, err)
}
} else if !overwrite && !rename {
fmt.Printf("%s already exists; skipped.\n", dest)
return nil
} else if !fi.Mode().IsRegular() {
return fmt.Errorf("%s already exists, but it's not a regular file", dest)
} else if rename {
if err := os.Rename(dest, dest+".bak"); err != nil {
return fmt.Errorf("Error creating backup for %s: %v", dest, err)
}
// Attempt to respect file permissions mask (even if user:group will be set anew)
perms = fi.Mode()
}
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)
}
defer file.Close()
if _, err = file.Write(data); err != nil {
return fmt.Errorf("%s: %v", dest, err)
}
fmt.Println(dest)
return nil
}
func buildAssetList(sec *section, globs []glob.Glob, c *cli.Context) []asset {
var results = make([]asset, 0, 64)
for _, name := range sec.Names() {
if isdir, err := sec.IsDir(name); !isdir && err == nil {
if sec.Path == "public" &&
strings.HasPrefix(name, "vendor/") &&
!c.Bool("include-vendored") {
continue
}
matchName := sec.Path + "/" + name
for _, g := range globs {
if g.Match(matchName) {
results = append(results, asset{Section: sec,
Name: name,
Path: sec.Path + "/" + name})
break
}
}
}
}
return results
}
func getPatterns(args []string) ([]glob.Glob, error) {
if len(args) == 0 {
args = []string{"**"}
}
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)
} else {
pat[i] = g
}
}
return pat, nil
}

View File

@@ -1,30 +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.
// +build !bindata
package cmd
import (
"fmt"
"os"
"github.com/urfave/cli"
)
// Cmdembedded represents the available extract sub-command.
var (
Cmdembedded = cli.Command{
Name: "embedded",
Usage: "Extract embedded resources",
Description: "A command for extracting embedded resources, like templates and images",
Action: extractorNotImplemented,
}
)
func extractorNotImplemented(c *cli.Context) error {
err := fmt.Errorf("Sorry: the 'embedded' subcommand is not available in builds without bindata")
fmt.Fprintf(os.Stderr, "%s\n", err)
return err
}

View File

@@ -7,11 +7,9 @@ package cmd
import (
"fmt"
"os"
"code.gitea.io/gitea/modules/generate"
"github.com/mattn/go-isatty"
"github.com/urfave/cli"
)
@@ -42,10 +40,9 @@ var (
}
microcmdGenerateLfsJwtSecret = cli.Command{
Name: "JWT_SECRET",
Aliases: []string{"LFS_JWT_SECRET"},
Usage: "Generate a new JWT_SECRET",
Action: runGenerateLfsJwtSecret,
Name: "LFS_JWT_SECRET",
Usage: "Generate a new LFS_JWT_SECRET",
Action: runGenerateLfsJwtSecret,
}
microcmdGenerateSecretKey = cli.Command{
@@ -61,27 +58,17 @@ func runGenerateInternalToken(c *cli.Context) error {
return err
}
fmt.Printf("%s", internalToken)
if isatty.IsTerminal(os.Stdout.Fd()) {
fmt.Printf("\n")
}
fmt.Printf("%s\n", internalToken)
return nil
}
func runGenerateLfsJwtSecret(c *cli.Context) error {
JWTSecretBase64, err := generate.NewJwtSecret()
JWTSecretBase64, err := generate.NewLfsJwtSecret()
if err != nil {
return err
}
fmt.Printf("%s", JWTSecretBase64)
if isatty.IsTerminal(os.Stdout.Fd()) {
fmt.Printf("\n")
}
fmt.Printf("%s\n", JWTSecretBase64)
return nil
}
@@ -91,11 +78,6 @@ func runGenerateSecretKey(c *cli.Context) error {
return err
}
fmt.Printf("%s", secretKey)
if isatty.IsTerminal(os.Stdout.Fd()) {
fmt.Printf("\n")
}
fmt.Printf("%s\n", secretKey)
return nil
}

View File

@@ -8,32 +8,33 @@ import (
"bufio"
"bytes"
"fmt"
"io"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"
"code.gitea.io/git"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"github.com/urfave/cli"
)
const (
hookBatchSize = 30
)
var (
// CmdHook represents the available hooks sub-command.
CmdHook = cli.Command{
Name: "hook",
Usage: "Delegate commands to corresponding Git hooks",
Description: "This should only be called by Git",
Flags: []cli.Flag{
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
Subcommands: []cli.Command{
subcmdHookPreReceive,
subcmdHookUpdate,
@@ -61,134 +62,33 @@ var (
}
)
type delayWriter struct {
internal io.Writer
buf *bytes.Buffer
timer *time.Timer
}
func newDelayWriter(internal io.Writer, delay time.Duration) *delayWriter {
timer := time.NewTimer(delay)
return &delayWriter{
internal: internal,
buf: &bytes.Buffer{},
timer: timer,
}
}
func (d *delayWriter) Write(p []byte) (n int, err error) {
if d.buf != nil {
select {
case <-d.timer.C:
_, err := d.internal.Write(d.buf.Bytes())
if err != nil {
return 0, err
}
d.buf = nil
return d.internal.Write(p)
default:
return d.buf.Write(p)
}
}
return d.internal.Write(p)
}
func (d *delayWriter) WriteString(s string) (n int, err error) {
if d.buf != nil {
select {
case <-d.timer.C:
_, err := d.internal.Write(d.buf.Bytes())
if err != nil {
return 0, err
}
d.buf = nil
return d.internal.Write([]byte(s))
default:
return d.buf.WriteString(s)
}
}
return d.internal.Write([]byte(s))
}
func (d *delayWriter) Close() error {
if d == nil {
return nil
}
stopped := util.StopTimer(d.timer)
if stopped || d.buf == nil {
return nil
}
_, err := d.internal.Write(d.buf.Bytes())
d.buf = nil
return err
}
type nilWriter struct{}
func (n *nilWriter) Write(p []byte) (int, error) {
return len(p), nil
}
func (n *nilWriter) WriteString(s string) (int, error) {
return len(s), nil
}
func runHookPreReceive(c *cli.Context) error {
if os.Getenv(models.EnvIsInternal) == "true" {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
return nil
}
setup("hooks/pre-receive.log", false)
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
fail(`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.`, "")
} else {
return nil
}
if c.IsSet("config") {
setting.CustomConf = c.String("config")
} else if c.GlobalIsSet("config") {
setting.CustomConf = c.GlobalString("config")
}
setup("hooks/pre-receive.log")
// the environment setted on serv command
repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
username := os.Getenv(models.EnvRepoUsername)
reponame := os.Getenv(models.EnvRepoName)
userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
prID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchPRID), 10, 64)
isDeployKey, _ := strconv.ParseBool(os.Getenv(models.EnvIsDeployKey))
hookOptions := private.HookOptions{
UserID: userID,
GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
ProtectedBranchID: prID,
IsDeployKey: isDeployKey,
}
userIDStr := os.Getenv(models.EnvPusherID)
repoPath := models.RepoPath(username, reponame)
buf := bytes.NewBuffer(nil)
scanner := bufio.NewScanner(os.Stdin)
oldCommitIDs := make([]string, hookBatchSize)
newCommitIDs := make([]string, hookBatchSize)
refFullNames := make([]string, hookBatchSize)
count := 0
total := 0
lastline := 0
var out io.Writer
out = &nilWriter{}
if setting.Git.VerbosePush {
if setting.Git.VerbosePushDelay > 0 {
dWriter := newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay)
defer dWriter.Close()
out = dWriter
} else {
out = os.Stdout
}
}
for scanner.Scan() {
buf.Write(scanner.Bytes())
buf.WriteByte('\n')
// TODO: support news feeds for wiki
if isWiki {
continue
@@ -202,127 +102,85 @@ Gitea or set your environment appropriately.`, "")
oldCommitID := string(fields[0])
newCommitID := string(fields[1])
refFullName := string(fields[2])
total++
lastline++
// If the ref is a branch, check if it's protected
if strings.HasPrefix(refFullName, git.BranchPrefix) {
oldCommitIDs[count] = oldCommitID
newCommitIDs[count] = newCommitID
refFullNames[count] = refFullName
count++
fmt.Fprintf(out, "*")
branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
protectBranch, err := private.GetProtectedBranchBy(repoID, branchName)
if err != nil {
fail("Internal error", fmt.Sprintf("retrieve protected branches information failed: %v", err))
}
if count >= hookBatchSize {
fmt.Fprintf(out, " Checking %d branches\n", count)
hookOptions.OldCommitIDs = oldCommitIDs
hookOptions.NewCommitIDs = newCommitIDs
hookOptions.RefFullNames = refFullNames
statusCode, msg := private.HookPreReceive(username, reponame, hookOptions)
switch statusCode {
case http.StatusOK:
// no-op
case http.StatusInternalServerError:
fail("Internal Server Error", msg)
default:
fail(msg, "")
}
count = 0
lastline = 0
if protectBranch != nil && protectBranch.IsProtected() {
// check and deletion
if newCommitID == git.EmptySHA {
fail(fmt.Sprintf("branch %s is protected from deletion", branchName), "")
}
// detect force push
if git.EmptySHA != oldCommitID {
output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDir(repoPath)
if err != nil {
fail("Internal error", "Fail to detect force push: %v", err)
} else if len(output) > 0 {
fail(fmt.Sprintf("branch %s is protected from force push", branchName), "")
}
}
userID, _ := strconv.ParseInt(userIDStr, 10, 64)
canPush, err := private.CanUserPush(protectBranch.ID, userID)
if err != nil {
fail("Internal error", "Fail to detect user can push: %v", err)
} else if !canPush {
fail(fmt.Sprintf("protected branch %s can not be pushed to", branchName), "")
}
} else {
fmt.Fprintf(out, ".")
}
if lastline >= hookBatchSize {
fmt.Fprintf(out, "\n")
lastline = 0
}
}
if count > 0 {
hookOptions.OldCommitIDs = oldCommitIDs[:count]
hookOptions.NewCommitIDs = newCommitIDs[:count]
hookOptions.RefFullNames = refFullNames[:count]
fmt.Fprintf(out, " Checking %d branches\n", count)
statusCode, msg := private.HookPreReceive(username, reponame, hookOptions)
switch statusCode {
case http.StatusInternalServerError:
fail("Internal Server Error", msg)
case http.StatusForbidden:
fail(msg, "")
}
} else if lastline > 0 {
fmt.Fprintf(out, "\n")
lastline = 0
}
fmt.Fprintf(out, "Checked %d references in total\n", total)
return nil
}
func runHookUpdate(c *cli.Context) error {
// Update is empty and is kept only for backwards compatibility
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
return nil
}
if c.IsSet("config") {
setting.CustomConf = c.String("config")
} else if c.GlobalIsSet("config") {
setting.CustomConf = c.GlobalString("config")
}
setup("hooks/update.log")
return nil
}
func runHookPostReceive(c *cli.Context) error {
if os.Getenv(models.EnvIsInternal) == "true" {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
return nil
}
setup("hooks/post-receive.log", false)
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
fail(`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.`, "")
} else {
return nil
}
if c.IsSet("config") {
setting.CustomConf = c.String("config")
} else if c.GlobalIsSet("config") {
setting.CustomConf = c.GlobalString("config")
}
var out io.Writer
var dWriter *delayWriter
out = &nilWriter{}
if setting.Git.VerbosePush {
if setting.Git.VerbosePushDelay > 0 {
dWriter = newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay)
defer dWriter.Close()
out = dWriter
} else {
out = os.Stdout
}
}
setup("hooks/post-receive.log")
// the environment setted on serv command
repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
repoUser := os.Getenv(models.EnvRepoUsername)
isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
repoName := os.Getenv(models.EnvRepoName)
pusherID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
pusherName := os.Getenv(models.EnvPusherName)
hookOptions := private.HookOptions{
UserName: pusherName,
UserID: pusherID,
GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
}
oldCommitIDs := make([]string, hookBatchSize)
newCommitIDs := make([]string, hookBatchSize)
refFullNames := make([]string, hookBatchSize)
count := 0
total := 0
wasEmpty := false
masterPushed := false
results := make([]private.HookPostReceiveBranchResult, 0)
buf := bytes.NewBuffer(nil)
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
buf.Write(scanner.Bytes())
buf.WriteByte('\n')
// TODO: support news feeds for wiki
if isWiki {
continue
@@ -333,93 +191,63 @@ Gitea or set your environment appropriately.`, "")
continue
}
fmt.Fprintf(out, ".")
oldCommitIDs[count] = string(fields[0])
newCommitIDs[count] = string(fields[1])
refFullNames[count] = string(fields[2])
if refFullNames[count] == git.BranchPrefix+"master" && newCommitIDs[count] != git.EmptySHA && count == total {
masterPushed = true
}
count++
total++
oldCommitID := string(fields[0])
newCommitID := string(fields[1])
refFullName := string(fields[2])
if count >= hookBatchSize {
fmt.Fprintf(out, " Processing %d references\n", count)
hookOptions.OldCommitIDs = oldCommitIDs
hookOptions.NewCommitIDs = newCommitIDs
hookOptions.RefFullNames = refFullNames
resp, err := private.HookPostReceive(repoUser, repoName, hookOptions)
if resp == nil {
_ = dWriter.Close()
hookPrintResults(results)
fail("Internal Server Error", err)
}
wasEmpty = wasEmpty || resp.RepoWasEmpty
results = append(results, resp.Results...)
count = 0
if err := private.PushUpdate(models.PushUpdateOptions{
RefFullName: refFullName,
OldCommitID: oldCommitID,
NewCommitID: newCommitID,
PusherID: pusherID,
PusherName: pusherName,
RepoUserName: repoUser,
RepoName: repoName,
}); err != nil {
log.GitLogger.Error(2, "Update: %v", err)
}
}
if count == 0 {
if wasEmpty && masterPushed {
// We need to tell the repo to reset the default branch to master
err := private.SetDefaultBranch(repoUser, repoName, "master")
if newCommitID != git.EmptySHA && strings.HasPrefix(refFullName, git.BranchPrefix) {
branch := strings.TrimPrefix(refFullName, git.BranchPrefix)
repo, pullRequestAllowed, err := private.GetRepository(repoID)
if err != nil {
fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
log.GitLogger.Error(2, "get repo: %v", err)
break
}
if !pullRequestAllowed {
break
}
baseRepo := repo
if repo.IsFork {
baseRepo = repo.BaseRepo
}
if !repo.IsFork && branch == baseRepo.DefaultBranch {
break
}
pr, err := private.ActivePullRequest(baseRepo.ID, repo.ID, baseRepo.DefaultBranch, branch)
if err != nil {
log.GitLogger.Error(2, "get active pr: %v", err)
break
}
fmt.Fprintln(os.Stderr, "")
if pr == nil {
if repo.IsFork {
branch = fmt.Sprintf("%s:%s", repo.OwnerName, branch)
}
fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", branch)
fmt.Fprintf(os.Stderr, " %s/compare/%s...%s\n", baseRepo.HTMLURL(), url.QueryEscape(baseRepo.DefaultBranch), url.QueryEscape(branch))
} else {
fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
fmt.Fprintf(os.Stderr, " %s/pulls/%d\n", baseRepo.HTMLURL(), pr.Index)
}
fmt.Fprintln(os.Stderr, "")
}
fmt.Fprintf(out, "Processed %d references in total\n", total)
_ = dWriter.Close()
hookPrintResults(results)
return nil
}
hookOptions.OldCommitIDs = oldCommitIDs[:count]
hookOptions.NewCommitIDs = newCommitIDs[:count]
hookOptions.RefFullNames = refFullNames[:count]
fmt.Fprintf(out, " Processing %d references\n", count)
resp, err := private.HookPostReceive(repoUser, repoName, hookOptions)
if resp == nil {
_ = dWriter.Close()
hookPrintResults(results)
fail("Internal Server Error", err)
}
wasEmpty = wasEmpty || resp.RepoWasEmpty
results = append(results, resp.Results...)
fmt.Fprintf(out, "Processed %d references in total\n", total)
if wasEmpty && masterPushed {
// We need to tell the repo to reset the default branch to master
err := private.SetDefaultBranch(repoUser, repoName, "master")
if err != nil {
fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
}
}
_ = dWriter.Close()
hookPrintResults(results)
return nil
}
func hookPrintResults(results []private.HookPostReceiveBranchResult) {
for _, res := range results {
if !res.Message {
continue
}
fmt.Fprintln(os.Stderr, "")
if res.Create {
fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", res.Branch)
fmt.Fprintf(os.Stderr, " %s\n", res.URL)
} else {
fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
fmt.Fprintf(os.Stderr, " %s\n", res.URL)
}
fmt.Fprintln(os.Stderr, "")
os.Stderr.Sync()
}
}

View File

@@ -9,7 +9,8 @@ import (
"fmt"
"strings"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli"
)
@@ -40,10 +41,19 @@ var CmdKeys = cli.Command{
Value: "",
Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)",
},
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
func runKeys(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
if !c.IsSet("username") {
return errors.New("No username provided")
}
@@ -62,12 +72,14 @@ func runKeys(c *cli.Context) error {
return errors.New("No key type and content provided")
}
setup("keys.log", false)
if err := initDBDisableConsole(true); err != nil {
return err
}
authorizedString, err := private.AuthorizedPublicKeyByContent(content)
publicKey, err := models.SearchPublicKeyByContent(content)
if err != nil {
return err
}
fmt.Println(strings.TrimSpace(authorizedString))
fmt.Println(publicKey.AuthorizedString())
return nil
}

View File

@@ -1,92 +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 cmd
import (
"fmt"
"net/http"
"os"
"time"
"code.gitea.io/gitea/modules/private"
"github.com/urfave/cli"
)
var (
// CmdManager represents the manager command
CmdManager = cli.Command{
Name: "manager",
Usage: "Manage the running gitea process",
Description: "This is a command for managing the running gitea process",
Subcommands: []cli.Command{
subcmdShutdown,
subcmdRestart,
subcmdFlushQueues,
},
}
subcmdShutdown = cli.Command{
Name: "shutdown",
Usage: "Gracefully shutdown the running process",
Action: runShutdown,
}
subcmdRestart = cli.Command{
Name: "restart",
Usage: "Gracefully restart the running process - (not implemented for windows servers)",
Action: runRestart,
}
subcmdFlushQueues = cli.Command{
Name: "flush-queues",
Usage: "Flush queues in the running process",
Action: runFlushQueues,
Flags: []cli.Flag{
cli.DurationFlag{
Name: "timeout",
Value: 60 * time.Second,
Usage: "Timeout for the flushing process",
},
cli.BoolFlag{
Name: "non-blocking",
Usage: "Set to true to not wait for flush to complete before returning",
},
},
}
)
func runShutdown(c *cli.Context) error {
setup("manager", false)
statusCode, msg := private.Shutdown()
switch statusCode {
case http.StatusInternalServerError:
fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}
func runRestart(c *cli.Context) error {
setup("manager", false)
statusCode, msg := private.Restart()
switch statusCode {
case http.StatusInternalServerError:
fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}
func runFlushQueues(c *cli.Context) error {
setup("manager", false)
statusCode, msg := private.FlushQueues(c.Duration("timeout"), c.Bool("non-blocking"))
switch statusCode {
case http.StatusInternalServerError:
fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}

View File

@@ -5,8 +5,6 @@
package cmd
import (
"context"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/migrations"
"code.gitea.io/gitea/modules/log"
@@ -21,9 +19,20 @@ var CmdMigrate = cli.Command{
Usage: "Migrate the database",
Description: "This is a command for migrating the database, so that you can run gitea admin create-user before starting the server.",
Action: runMigrate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
func runMigrate(ctx *cli.Context) error {
if ctx.IsSet("config") {
setting.CustomConf = ctx.String("config")
}
if err := initDB(); err != nil {
return err
}
@@ -32,10 +41,10 @@ func runMigrate(ctx *cli.Context) error {
log.Trace("AppWorkPath: %s", setting.AppWorkPath)
log.Trace("Custom path: %s", setting.CustomPath)
log.Trace("Log path: %s", setting.LogRootPath)
setting.InitDBConfig()
models.LoadConfigs()
if err := models.NewEngine(context.Background(), migrations.Migrate); err != nil {
log.Fatal("Failed to initialize ORM engine: %v", err)
if err := models.NewEngine(migrations.Migrate); err != nil {
log.Fatal(4, "Failed to initialize ORM engine: %v", err)
return err
}

View File

@@ -8,28 +8,27 @@ package cmd
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"os/exec"
"regexp"
"strconv"
"path/filepath"
"strings"
"time"
"code.gitea.io/git"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/pprof"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/com"
"github.com/dgrijalva/jwt-go"
"github.com/unknwon/com"
version "github.com/mcuadros/go-version"
"github.com/urfave/cli"
)
const (
accessDenied = "Repository does not exist or you do not have access"
lfsAuthenticateVerb = "git-lfs-authenticate"
)
@@ -40,23 +39,41 @@ var CmdServ = cli.Command{
Description: `Serv provide access auth for repositories`,
Action: runServ,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "enable-pprof",
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
cli.BoolFlag{
Name: "debug",
Name: "enable-pprof",
},
},
}
func setup(logPath string, debug bool) {
if !debug {
_ = log.DelLogger("console")
func checkLFSVersion() {
if setting.LFS.StartServer {
//Disable LFS client hooks if installed for the current OS user
//Needs at least git v2.1.2
binVersion, err := git.BinVersion()
if err != nil {
fail(fmt.Sprintf("Error retrieving git version: %v", err), fmt.Sprintf("Error retrieving git version: %v", err))
}
if !version.Compare(binVersion, "2.1.2", ">=") {
setting.LFS.StartServer = false
println("LFS server support needs at least Git v2.1.2, disabled")
} else {
git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "filter.lfs.required=",
"-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
}
}
}
func setup(logPath string) {
log.DelLogger("console")
setting.NewContext()
if debug {
setting.ProdMode = false
}
checkLFSVersion()
log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
}
func parseCmd(cmd string) (string, string) {
@@ -74,7 +91,6 @@ var (
"git-receive-pack": models.AccessModeWrite,
lfsAuthenticateVerb: models.AccessModeNone,
}
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
)
func fail(userMessage, logMessage string, args ...interface{}) {
@@ -84,14 +100,19 @@ func fail(userMessage, logMessage string, args ...interface{}) {
if !setting.ProdMode {
fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
}
log.GitLogger.Fatal(3, logMessage, args...)
return
}
log.GitLogger.Close()
os.Exit(1)
}
func runServ(c *cli.Context) error {
// FIXME: This needs to internationalised
setup("serv.log", c.Bool("debug"))
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
setup("serv.log")
if setting.SSH.Disabled {
println("Gitea: SSH has been disabled")
@@ -99,29 +120,13 @@ func runServ(c *cli.Context) error {
}
if len(c.Args()) < 1 {
if err := cli.ShowSubcommandHelp(c); err != nil {
fmt.Printf("error showing subcommand help: %v\n", err)
}
cli.ShowSubcommandHelp(c)
return nil
}
keys := strings.Split(c.Args()[0], "-")
if len(keys) != 2 || keys[0] != "key" {
fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
}
keyID := com.StrTo(keys[1]).MustInt64()
cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
if len(cmd) == 0 {
key, user, err := private.ServNoCommand(keyID)
if err != nil {
fail("Internal error", "Failed to check provided key: %v", err)
}
if key.Type == models.KeyTypeDeploy {
println("Hi there! You've successfully authenticated with the deploy key named " + key.Name + ", but Gitea does not provide shell access.")
} else {
println("Hi there, " + user.Name + "! You've successfully authenticated with the key named " + key.Name + ", but Gitea does not provide shell access.")
}
println("Hi there, You've successfully authenticated, but Gitea does not provide shell access.")
println("If this is unexpected, please log in with password and setup Gitea under another user.")
return nil
}
@@ -150,28 +155,46 @@ func runServ(c *cli.Context) error {
username := strings.ToLower(rr[0])
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
if alphaDashDotPattern.MatchString(reponame) {
fail("Invalid repo name", "Invalid repo name: %s", reponame)
}
if setting.EnablePprof || c.Bool("enable-pprof") {
if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
}
stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
if err != nil {
fail("Internal Server Error", "Unable to start CPU profile: %v", err)
}
stopCPUProfiler := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
defer func() {
stopCPUProfiler()
err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
if err != nil {
fail("Internal Server Error", "Unable to dump Mem Profile: %v", err)
}
pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
}()
}
var (
isWiki bool
unitType = models.UnitTypeCode
unitName = "code"
)
if strings.HasSuffix(reponame, ".wiki") {
isWiki = true
unitType = models.UnitTypeWiki
unitName = "wiki"
reponame = reponame[:len(reponame)-5]
}
os.Setenv(models.EnvRepoUsername, username)
if isWiki {
os.Setenv(models.EnvRepoIsWiki, "true")
} else {
os.Setenv(models.EnvRepoIsWiki, "false")
}
os.Setenv(models.EnvRepoName, reponame)
repo, err := private.GetRepositoryByOwnerAndName(username, reponame)
if err != nil {
if strings.Contains(err.Error(), "Failed to get repository: repository does not exist") {
fail(accessDenied, "Repository does not exist: %s/%s", username, reponame)
}
fail("Internal error", "Failed to get repository: %v", err)
}
requestedMode, has := allowedCommands[verb]
if !has {
fail("Unknown git command", "Unknown git command %s", verb)
@@ -187,41 +210,97 @@ func runServ(c *cli.Context) error {
}
}
results, err := private.ServCommand(keyID, username, reponame, requestedMode, verb, lfsVerb)
if err != nil {
if private.IsErrServCommand(err) {
errServCommand := err.(private.ErrServCommand)
if errServCommand.StatusCode != http.StatusInternalServerError {
fail("Unauthorized", "%s", errServCommand.Error())
} else {
fail("Internal Server Error", "%s", errServCommand.Error())
}
}
fail("Internal Server Error", "%s", err.Error())
// Prohibit push to mirror repositories.
if requestedMode > models.AccessModeRead && repo.IsMirror {
fail("mirror repository is read-only", "")
}
// Allow anonymous clone for public repositories.
var (
keyID int64
user *models.User
)
if requestedMode == models.AccessModeWrite || repo.IsPrivate || setting.Service.RequireSignInView {
keys := strings.Split(c.Args()[0], "-")
if len(keys) != 2 {
fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
}
key, err := private.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64())
if err != nil {
fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err)
}
keyID = key.ID
// Check deploy key or user key.
if key.Type == models.KeyTypeDeploy {
// Now we have to get the deploy key for this repo
deployKey, err := private.GetDeployKey(key.ID, repo.ID)
if err != nil {
fail("Key access denied", "Failed to access internal api: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
}
if deployKey == nil {
fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
}
if deployKey.Mode < requestedMode {
fail("Key permission denied", "Cannot push with read-only deployment key: %d to repo_id: %d", key.ID, repo.ID)
}
// Update deploy key activity.
if err = private.UpdateDeployKeyUpdated(key.ID, repo.ID); err != nil {
fail("Internal error", "UpdateDeployKey: %v", err)
}
// FIXME: Deploy keys aren't really the owner of the repo pushing changes
// however we don't have good way of representing deploy keys in hook.go
// so for now use the owner
os.Setenv(models.EnvPusherName, username)
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", repo.OwnerID))
} else {
user, err = private.GetUserByKeyID(key.ID)
if err != nil {
fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err)
}
if !user.IsActive || user.ProhibitLogin {
fail("Your account is not active or has been disabled by Administrator",
"User %s is disabled and have no access to repository %s",
user.Name, repoPath)
}
mode, err := private.CheckUnitUser(user.ID, repo.ID, user.IsAdmin, unitType)
if err != nil {
fail("Internal error", "Failed to check access: %v", err)
} else if *mode < requestedMode {
clientMessage := accessDenied
if *mode >= models.AccessModeRead {
clientMessage = "You do not have sufficient authorization for this action"
}
fail(clientMessage,
"User %s does not have level %v access to repository %s's "+unitName,
user.Name, requestedMode, repoPath)
}
os.Setenv(models.EnvPusherName, user.Name)
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
}
}
os.Setenv(models.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki))
os.Setenv(models.EnvRepoName, results.RepoName)
os.Setenv(models.EnvRepoUsername, results.OwnerName)
os.Setenv(models.EnvPusherName, results.UserName)
os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10))
os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0))
os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey))
os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID))
//LFS token authentication
if verb == lfsAuthenticateVerb {
url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))
url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, username, repo.Name)
now := time.Now()
claims := lfs.Claims{
StandardClaims: jwt.StandardClaims{
ExpiresAt: now.Add(setting.LFS.HTTPAuthExpiry).Unix(),
NotBefore: now.Unix(),
},
RepoID: results.RepoID,
Op: lfsVerb,
UserID: results.UserID,
claims := jwt.MapClaims{
"repo": repo.ID,
"op": lfsVerb,
"exp": now.Add(setting.LFS.HTTPAuthExpiry).Unix(),
"nbf": now.Unix(),
}
if user != nil {
claims["user"] = user.ID
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
@@ -242,6 +321,7 @@ func runServ(c *cli.Context) error {
if err != nil {
fail("Internal error", "Failed to encode LFS json response: %v", err)
}
return nil
}
@@ -257,6 +337,13 @@ func runServ(c *cli.Context) error {
} else {
gitcmd = exec.Command(verb, repoPath)
}
if isWiki {
if err = private.InitWiki(repo.ID); err != nil {
fail("Internal error", "Failed to init wiki repo: %v", err)
}
}
os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", repo.ID))
gitcmd.Dir = setting.RepoRootPath
gitcmd.Stdout = os.Stdout
@@ -267,9 +354,9 @@ func runServ(c *cli.Context) error {
}
// Update user key activity.
if results.KeyID > 0 {
if err = private.UpdatePublicKeyInRepo(results.KeyID, results.RepoID); err != nil {
fail("Internal error", "UpdatePublicKeyInRepo: %v", err)
if keyID > 0 {
if err = private.UpdatePublicKeyUpdated(keyID); err != nil {
fail("Internal error", "UpdatePublicKey: %v", err)
}
}

View File

@@ -5,21 +5,23 @@
package cmd
import (
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
"net/http/fcgi"
_ "net/http/pprof" // Used for debugging if enabled and a web server is running
"os"
"strings"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup/external"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/routes"
"github.com/Unknwon/com"
context2 "github.com/gorilla/context"
"github.com/unknwon/com"
"github.com/urfave/cli"
"golang.org/x/crypto/acme/autocert"
ini "gopkg.in/ini.v1"
@@ -38,6 +40,11 @@ and it takes care of all the other things for you`,
Value: "3000",
Usage: "Temporary port number to prevent conflict",
},
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
cli.StringFlag{
Name: "pid, P",
Value: "/var/run/gitea.pid",
@@ -59,10 +66,10 @@ func runHTTPRedirector() {
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
})
var err = runHTTP("tcp", source, context2.ClearHandler(handler))
var err = runHTTP(source, context2.ClearHandler(handler))
if err != nil {
log.Fatal("Failed to start port redirection: %v", err)
log.Fatal(4, "Failed to start port redirection: %v", err)
}
}
@@ -75,13 +82,19 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler)
}
go func() {
log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
// all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
var err = runHTTP("tcp", setting.HTTPAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)))
var err = http.ListenAndServe(setting.HTTPAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler))) // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
if err != nil {
log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
log.Fatal(4, "Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
}
}()
return runHTTPSWithTLSConfig("tcp", listenAddr, certManager.TLSConfig(), context2.ClearHandler(m))
server := &http.Server{
Addr: listenAddr,
Handler: m,
TLSConfig: &tls.Config{
GetCertificate: certManager.GetCertificate,
},
}
return server.ListenAndServeTLS("", "")
}
func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
@@ -97,25 +110,18 @@ func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
}
func runWeb(ctx *cli.Context) error {
managerCtx, cancel := context.WithCancel(context.Background())
graceful.InitManager(managerCtx)
defer cancel()
if os.Getppid() > 1 && len(os.Getenv("LISTEN_FDS")) > 0 {
log.Info("Restarting Gitea on PID: %d from parent PID: %d", os.Getpid(), os.Getppid())
} else {
log.Info("Starting Gitea on PID: %d", os.Getpid())
if ctx.IsSet("config") {
setting.CustomConf = ctx.String("config")
}
// Set pid file setting
if ctx.IsSet("pid") {
setting.CustomPID = ctx.String("pid")
}
// Perform global initialization
routers.GlobalInit(graceful.GetManager().HammerContext())
routers.GlobalInit()
external.RegisterParsers()
// Set up Macaron
m := routes.NewMacaron()
routes.RegisterRoutes(m)
@@ -127,7 +133,6 @@ func runWeb(ctx *cli.Context) error {
switch setting.Protocol {
case setting.UnixSocket:
case setting.FCGI:
case setting.FCGIUnix:
default:
// Save LOCAL_ROOT_URL if port changed
cfg := ini.Empty()
@@ -155,7 +160,7 @@ func runWeb(ctx *cli.Context) error {
}
listenAddr := setting.HTTPAddr
if setting.Protocol != setting.UnixSocket && setting.Protocol != setting.FCGIUnix {
if setting.Protocol != setting.UnixSocket {
listenAddr += ":" + setting.HTTPPort
}
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL)
@@ -174,8 +179,7 @@ func runWeb(ctx *cli.Context) error {
var err error
switch setting.Protocol {
case setting.HTTP:
NoHTTPRedirector()
err = runHTTP("tcp", listenAddr, context2.ClearHandler(m))
err = runHTTP(listenAddr, context2.ClearHandler(m))
case setting.HTTPS:
if setting.EnableLetsEncrypt {
err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, context2.ClearHandler(m))
@@ -183,29 +187,38 @@ func runWeb(ctx *cli.Context) error {
}
if setting.RedirectOtherPort {
go runHTTPRedirector()
} else {
NoHTTPRedirector()
}
err = runHTTPS("tcp", listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m))
err = runHTTPS(listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m))
case setting.FCGI:
NoHTTPRedirector()
err = runFCGI("tcp", listenAddr, context2.ClearHandler(m))
listener, err := net.Listen("tcp", listenAddr)
if err != nil {
log.Fatal(4, "Failed to bind %s", listenAddr, err)
}
defer listener.Close()
err = fcgi.Serve(listener, context2.ClearHandler(m))
case setting.UnixSocket:
NoHTTPRedirector()
err = runHTTP("unix", listenAddr, context2.ClearHandler(m))
case setting.FCGIUnix:
NoHTTPRedirector()
err = runFCGI("unix", listenAddr, context2.ClearHandler(m))
if err := os.Remove(listenAddr); err != nil && !os.IsNotExist(err) {
log.Fatal(4, "Failed to remove unix socket directory %s: %v", listenAddr, err)
}
var listener *net.UnixListener
listener, err = net.ListenUnix("unix", &net.UnixAddr{Name: listenAddr, Net: "unix"})
if err != nil {
break // Handle error after switch
}
// FIXME: add proper implementation of signal capture on all protocols
// execute this on SIGTERM or SIGINT: listener.Close()
if err = os.Chmod(listenAddr, os.FileMode(setting.UnixSocketPermission)); err != nil {
log.Fatal(4, "Failed to set permission of unix socket: %v", err)
}
err = http.Serve(listener, context2.ClearHandler(m))
default:
log.Fatal("Invalid protocol: %s", setting.Protocol)
log.Fatal(4, "Invalid protocol: %s", setting.Protocol)
}
if err != nil {
log.Critical("Failed to start server: %v", err)
log.Fatal(4, "Failed to start server: %v", err)
}
log.Info("HTTP Listener: %s Closed", listenAddr)
<-graceful.GetManager().Done()
log.Info("PID: %d Gitea Web Finished", os.Getpid())
log.Close()
return nil
}

View File

@@ -1,3 +1,5 @@
// +build !windows
// 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.
@@ -6,47 +8,38 @@ package cmd
import (
"crypto/tls"
"net"
"net/http"
"net/http/fcgi"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"github.com/facebookgo/grace/gracehttp"
)
func runHTTP(network, listenAddr string, m http.Handler) error {
return graceful.HTTPListenAndServe(network, listenAddr, m)
}
func runHTTPS(network, listenAddr, certFile, keyFile string, m http.Handler) error {
return graceful.HTTPListenAndServeTLS(network, listenAddr, certFile, keyFile, m)
}
func runHTTPSWithTLSConfig(network, listenAddr string, tlsConfig *tls.Config, m http.Handler) error {
return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, tlsConfig, m)
}
// NoHTTPRedirector tells our cleanup routine that we will not be using a fallback http redirector
func NoHTTPRedirector() {
graceful.GetManager().InformCleanup()
}
// NoMainListener tells our cleanup routine that we will not be using a possibly provided listener
// for our main HTTP/HTTPS service
func NoMainListener() {
graceful.GetManager().InformCleanup()
}
func runFCGI(network, listenAddr string, m http.Handler) error {
// This needs to handle stdin as fcgi point
fcgiServer := graceful.NewServer(network, listenAddr)
err := fcgiServer.ListenAndServe(func(listener net.Listener) error {
return fcgi.Serve(listener, m)
func runHTTP(listenAddr string, m http.Handler) error {
return gracehttp.Serve(&http.Server{
Addr: listenAddr,
Handler: m,
})
}
func runHTTPS(listenAddr, certFile, keyFile string, m http.Handler) error {
config := &tls.Config{
MinVersion: tls.VersionTLS10,
}
if config.NextProtos == nil {
config.NextProtos = []string{"http/1.1"}
}
config.Certificates = make([]tls.Certificate, 1)
var err error
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Fatal(4, "Failed to load https cert file %s: %v", listenAddr, err)
}
return gracehttp.Serve(&http.Server{
Addr: listenAddr,
Handler: m,
TLSConfig: config,
})
if err != nil {
log.Fatal("Failed to start FCGI main server: %v", err)
}
log.Info("FCGI Listener: %s Closed", listenAddr)
return err
}

19
cmd/web_windows.go Normal file
View File

@@ -0,0 +1,19 @@
// +build windows
// 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.
package cmd
import (
"net/http"
)
func runHTTP(listenAddr string, m http.Handler) error {
return http.ListenAndServe(listenAddr, m)
}
func runHTTPS(listenAddr, certFile, keyFile string, m http.Handler) error {
return http.ListenAndServeTLS(listenAddr, certFile, keyFile, m)
}

View File

@@ -1,66 +0,0 @@
Environment To Ini
==================
Multiple docker users have requested that the Gitea docker is changed
to permit arbitrary configuration via environment variables.
Gitea needs to use an ini file for configuration because the running
environment that starts the docker may not be the same as that used
by the hooks. An ini file also gives a good default and means that
users do not have to completely provide a full environment.
With those caveats above, this command provides a generic way of
converting suitably structured environment variables into any ini
value.
To use the command is very simple just run it and the default gitea
app.ini will be rewritten to take account of the variables provided,
however there are various options to give slightly different
behavior and these can be interrogated with the `-h` option.
The environment variables should be of the form:
GITEA__SECTION_NAME__KEY_NAME
Environment variables are usually restricted to a reduced character
set "0-9A-Z_" - in order to allow the setting of sections with
characters outside of that set, they should be escaped as following:
"_0X2E_" for ".". The entire section and key names can be escaped as
a UTF8 byte string if necessary. E.g. to configure:
"""
...
[log.console]
COLORIZE=false
STDERR=true
...
"""
You would set the environment variables: "GITEA__LOG_0x2E_CONSOLE__COLORIZE=false"
and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found
on the configuration cheat sheet.
To plug this command in to the docker, you simply compile the provided go file using:
go build environment-to-ini.go
And copy the resulting `environment-to-ini` command to /app/gitea in the docker.
Apply the below patch to /etc/s6/gitea.setup to wire this in.
If you find this useful please comment on #7287
diff --git a/docker/root/etc/s6/gitea/setup b/docker/root/etc/s6/gitea/setup
index f87ce9115..565bfcba9 100755
--- a/docker/root/etc/s6/gitea/setup
+++ b/docker/root/etc/s6/gitea/setup
@@ -44,6 +44,8 @@ if [ ! -f ${GITEA_CUSTOM}/conf/app.ini ]; then
SECRET_KEY=${SECRET_KEY:-""} \
envsubst < /etc/templates/app.ini > ${GITEA_CUSTOM}/conf/app.ini
+ /app/gitea/environment-to-ini -c ${GITEA_CUSTOM}/conf/app.ini
+
chown ${USER}:git ${GITEA_CUSTOM}/conf/app.ini
fi

View File

@@ -1,224 +0,0 @@
// 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.
package main
import (
"os"
"regexp"
"strconv"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/unknwon/com"
"github.com/urfave/cli"
ini "gopkg.in/ini.v1"
)
// EnvironmentPrefix environment variables prefixed with this represent ini values to write
const EnvironmentPrefix = "GITEA"
func main() {
app := cli.NewApp()
app.Name = "environment-to-ini"
app.Usage = "Use provided environment to update configuration ini"
app.Description = `As a helper to allow docker users to update the gitea configuration
through the environment, this command allows environment variables to
be mapped to values in the ini.
Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME"
will be mapped to the ini section "[section_name]" and the key
"KEY_NAME" with the value as provided.
Environment variables are usually restricted to a reduced character
set "0-9A-Z_" - in order to allow the setting of sections with
characters outside of that set, they should be escaped as following:
"_0X2E_" for ".". The entire section and key names can be escaped as
a UTF8 byte string if necessary. E.g. to configure:
"""
...
[log.console]
COLORIZE=false
STDERR=true
...
"""
You would set the environment variables: "GITEA__LOG_0x2E_CONSOLE__COLORIZE=false"
and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found
on the configuration cheat sheet.`
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "custom-path, C",
Value: setting.CustomPath,
Usage: "Custom path file path",
},
cli.StringFlag{
Name: "config, c",
Value: setting.CustomConf,
Usage: "Custom configuration file path",
},
cli.StringFlag{
Name: "work-path, w",
Value: setting.AppWorkPath,
Usage: "Set the gitea working path",
},
cli.StringFlag{
Name: "out, o",
Value: "",
Usage: "Destination file to write to",
},
cli.BoolFlag{
Name: "clear",
Usage: "Clears the matched variables from the environment",
},
cli.StringFlag{
Name: "prefix, p",
Value: EnvironmentPrefix,
Usage: "Environment prefix to look for - will be suffixed by __ (2 underscores)",
},
}
app.Action = runEnvironmentToIni
setting.SetCustomPathAndConf("", "", "")
err := app.Run(os.Args)
if err != nil {
log.Fatal("Failed to run app with %s: %v", os.Args, err)
}
}
func runEnvironmentToIni(c *cli.Context) error {
providedCustom := c.String("custom-path")
providedConf := c.String("config")
providedWorkPath := c.String("work-path")
setting.SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath)
cfg := ini.Empty()
if com.IsFile(setting.CustomConf) {
if err := cfg.Append(setting.CustomConf); err != nil {
log.Fatal("Failed to load custom conf '%s': %v", setting.CustomConf, err)
}
} else {
log.Warn("Custom config '%s' not found, ignore this if you're running first time", setting.CustomConf)
}
cfg.NameMapper = ini.SnackCase
prefix := c.String("prefix") + "__"
for _, kv := range os.Environ() {
idx := strings.IndexByte(kv, '=')
if idx < 0 {
continue
}
eKey := kv[:idx]
value := kv[idx+1:]
if !strings.HasPrefix(eKey, prefix) {
continue
}
eKey = eKey[len(prefix):]
sectionName, keyName := DecodeSectionKey(eKey)
if len(keyName) == 0 {
continue
}
section, err := cfg.GetSection(sectionName)
if err != nil {
section, err = cfg.NewSection(sectionName)
if err != nil {
log.Error("Error creating section: %s : %v", sectionName, err)
continue
}
}
key := section.Key(keyName)
if key == nil {
key, err = section.NewKey(keyName, value)
if err != nil {
log.Error("Error creating key: %s in section: %s with value: %s : %v", keyName, sectionName, value, err)
continue
}
}
key.SetValue(value)
}
destination := c.String("out")
if len(destination) == 0 {
destination = setting.CustomConf
}
err := cfg.SaveTo(destination)
if err != nil {
return err
}
if c.Bool("clear") {
for _, kv := range os.Environ() {
idx := strings.IndexByte(kv, '=')
if idx < 0 {
continue
}
eKey := kv[:idx]
if strings.HasPrefix(eKey, prefix) {
_ = os.Unsetenv(eKey)
}
}
}
return nil
}
const escapeRegexpString = "_0[xX](([0-9a-fA-F][0-9a-fA-F])+)_"
var escapeRegex = regexp.MustCompile(escapeRegexpString)
// DecodeSectionKey will decode a portable string encoded Section__Key pair
// Portable strings are considered to be of the form [A-Z0-9_]*
// We will encode a disallowed value as the UTF8 byte string preceded by _0X and
// followed by _. E.g. _0X2C_ for a '-' and _0X2E_ for '.'
// Section and Key are separated by a plain '__'.
// The entire section can be encoded as a UTF8 byte string
func DecodeSectionKey(encoded string) (string, string) {
section := ""
key := ""
inKey := false
last := 0
escapeStringIndices := escapeRegex.FindAllStringIndex(encoded, -1)
for _, unescapeIdx := range escapeStringIndices {
preceding := encoded[last:unescapeIdx[0]]
if !inKey {
if splitter := strings.Index(preceding, "__"); splitter > -1 {
section += preceding[:splitter]
inKey = true
key += preceding[splitter+2:]
} else {
section += preceding
}
} else {
key += preceding
}
toDecode := encoded[unescapeIdx[0]+3 : unescapeIdx[1]-1]
decodedBytes := make([]byte, len(toDecode)/2)
for i := 0; i < len(toDecode)/2; i++ {
// Can ignore error here as we know these should be hexadecimal from the regexp
byteInt, _ := strconv.ParseInt(toDecode[2*i:2*i+2], 16, 0)
decodedBytes[i] = byte(byteInt)
}
if inKey {
key += string(decodedBytes)
} else {
section += string(decodedBytes)
}
last = unescapeIdx[1]
}
remaining := encoded[last:]
if !inKey {
if splitter := strings.Index(remaining, "__"); splitter > -1 {
section += remaining[:splitter]
inKey = true
key += remaining[splitter+2:]
} else {
section += remaining
}
} else {
key += remaining
}
return section, key
}

View File

@@ -1,42 +0,0 @@
#!/bin/bash
########################################################################
# This script some defaults for gitea to run in a FHS compliant manner #
########################################################################
# It assumes that you place this script as gitea in /usr/bin
#
# And place the original in /usr/lib/gitea with working files in /var/lib/gitea
# and main configuration in /etc/gitea/app.ini
GITEA="/usr/lib/gitea/gitea"
WORK_DIR="/var/lib/gitea"
APP_INI="/etc/gitea/app.ini"
APP_INI_SET=""
for i in "$@"; do
case "$i" in
"-c")
APP_INI_SET=1
;;
"-c="*)
APP_INI_SET=1
;;
"--config")
APP_INI_SET=1
;;
"--config="*)
APP_INI_SET=1
;;
*)
;;
esac
done
if [ -z "$APP_INI_SET" ]; then
CONF_ARG="-c \"$APP_INI\""
fi
# Provide FHS compliant defaults to
GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" "$GITEA" $CONF_ARG "$@"

View File

@@ -1,76 +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
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"code.gitea.io/gitea/models"
)
// To generate derivative fixtures, execute the following from Gitea's repository base dir:
// go run -tags 'sqlite sqlite_unlock_notify' contrib/fixtures/fixture_generation.go [fixture...]
var (
generators = []struct {
gen func() (string, error)
name string
}{
{
models.GetYamlFixturesAccess, "access",
},
}
fixturesDir string
)
func main() {
pathToGiteaRoot := "."
fixturesDir = filepath.Join(pathToGiteaRoot, "models", "fixtures")
if err := models.CreateTestEngine(fixturesDir); err != nil {
fmt.Printf("CreateTestEngine: %+v", err)
os.Exit(1)
}
if err := models.PrepareTestDatabase(); err != nil {
fmt.Printf("PrepareTestDatabase: %+v\n", err)
os.Exit(1)
}
if len(os.Args) == 0 {
for _, r := range os.Args {
if err := generate(r); err != nil {
fmt.Printf("generate '%s': %+v\n", r, err)
os.Exit(1)
}
}
} else {
for _, g := range generators {
if err := generate(g.name); err != nil {
fmt.Printf("generate '%s': %+v\n", g.name, err)
os.Exit(1)
}
}
}
}
func generate(name string) error {
for _, g := range generators {
if g.name == name {
data, err := g.gen()
if err != nil {
return err
}
path := filepath.Join(fixturesDir, name+".yml")
if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil {
return fmt.Errorf("%s: %+v", path, err)
}
fmt.Printf("%s created.\n", path)
return nil
}
}
return fmt.Errorf("generator not found")
}

View File

@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
"label": "Build",
"taskName": "Build",
"type": "shell",
"command": "go",
"group": "build",
@@ -25,7 +25,7 @@
"problemMatcher": ["$go"]
},
{
"label": "Build (with SQLite3)",
"taskName": "Build (with SQLite3)",
"type": "shell",
"command": "go",
"group": "build",

View File

@@ -1,196 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Privacy Policy</title>
</head>
<body>
<h1>Privacy Policy</h1>
<h4>Last updated: December 28, 2019</h4>
<h2>Who We Are?</h2>
<p>Your Gitea Instance</p>
<h2>What Personal Data We Collect?</h2>
<p>We collect following personal data (collectively called User Personal Information):</p>
<ol>
<li>Registration information (username, email, password, etc.)</li>
<li>Profile information for your Account (such as your full name, biography, website, gpg key, and location.)</li>
<li>Usage information (pages you view, your IP address, referring site, session information, and request date and time.)</li>
<li>Device information (its IP address, client application information, language preference, operating system and application version, device type, ID, model and manufacturer.)</li>
<li>Git data that you upload to a repository</li>
<li>Cookies and Similar Technologies</li>
</ol>
<p>We may also collect User Personal Information from third-parties (vendors, partners, or affiliates). We don't purchase them from third-party data brokers, though.</p>
<p>However, we don't intentionally collect sensitive information (such as racial or ethnic origin, political affiliations, religious/philosophical beliefs, biometric data, etc.)</p>
<!--If you choose to store any of such data on our servers, you are responsible for complying with any regulations regarding them.-->
<h2>How We Share Information We Collect?</h2>
<p>We may share your User Personal Information with third-parties under following circumstances:</p>
<h3>With your Consent</h3>
<p>We share your User Personal Information, if you consent, after letting you know what information will be shared, with whom, and why. For example, if you allow third party applications to access your Account using <a href="https://docs.gitea.io/en-us/oauth2-provider/">OAuth2 providers</a>, we share all information associated with your Account, including private repos and organizations. You may also direct us through your action on Your Gitea Instance to share your User Personal Information, such as when joining an Organization.</p>
<h3>With Service Providers</h3>
<p>We share User Personal Information with a limited number of service providers who process it on our behalf to provide or improve our Service, and who have agreed to privacy restrictions similar to the ones in our Privacy Statement by signing data protection agreements or making similar commitments. Our service providers perform payment processing, customer support ticketing, network data transmission, security, and other similar services. While Your Gitea Instance processes all User Personal Information in the (country/state where Gitea is deployed), our service providers may process data outside of (country/state where Gitea is deployed), the United States or the European Union.</p>
<h3>For Security Purposes</h3>
<p>If you are a member of an Organization, Your Gitea Instance may share your username, Usage Information, and Device Information associated with that Organization with an owner and/or administrator of the Organization who has agreed to the Corporate Terms of Service or applicable customer agreements, to the extent that such information is provided only to investigate or respond to a security incident that affects or compromises the security of that particular Organization.</p>
<h3>For Legal Disclosure</h3>
<p>Your Gitea Instance strives for transparency in complying with legal process and legal obligations. Unless prevented from doing so by law or court order, or in rare, exigent circumstances, we make a reasonable effort to notify users of any legally compelled or required disclosure of their information. Your Gitea Instance may disclose User Personal Information or other information we collect about you to law enforcement if required in response to a valid subpoena, court order, search warrant, a similar government order, or when we believe in good faith that disclosure is necessary to comply with our legal obligations, to protect our property or rights, or those of third parties or the public at large.</p>
<h3>Change in Control or Sale</h3>
<p>We may share User Personal Information if we are involved in a merger, sale, or acquisition of corporate entities or business units. If any such change of ownership happens, we will ensure that it is under terms that preserve the confidentiality of User Personal Information, and we will notify you on our Website or by email before any transfer of your User Personal Information. The organization receiving any User Personal Information will have to honor any promises we made in our Privacy Statement or Terms of Service.</p>
<h3>Aggregate, Non-Personally Identifying Information</h3>
<p>We share certain aggregated, non-personally identifying information with others about how our users, collectively, use Your Gitea Instance, or how our users respond to our other offerings, such as our conferences or events. For example, we may compile statistics on the open source activity across Your Gitea Instance.</p>
<p>We <b>don't</b> sell your User Personal Information for monetary or other consideration. </p>
<h2>How We Use Your Information?</h2>
<p>We may use your information for following purposes:</p>
<ol>
<li>We use your Registration Information to create your account, and to provide you the Service.</li>
<li>We use your User Personal Information, specifically your username, to identify you on Your Gitea Instance.</li>
<li>We use your Profile Information to fill out your Account profile and to share that profile with other users if you ask us to.</li>
<li>We use your email address to communicate with you, if you've said that's okay, and only for the reasons youve said thats okay.</li>
<li>We use User Personal Information and other data to make recommendations for you, such as to suggest projects you may want to follow or contribute to. We learn from your public behavior on Your Gitea Instance—such as the projects you star—to determine your coding interests, and we recommend similar projects. These recommendations are automated decisions, but they have no legal impact on your rights.</li>
<li>We use Usage Information and Device Information to better understand how our Users use Your Gitea Instance and to improve our Website and Service.</li>
<li>We may use your User Personal Information if it is necessary for security purposes or to investigate possible fraud or attempts to harm Your Gitea Instance or our Users.</li>
<li>We may use your User Personal Information to comply with our legal obligations, protect our intellectual property, and enforce our Terms of Service.</li>
<li>We limit our use of your User Personal Information to the purposes listed in this Privacy Statement. If we need to use your User Personal Information for other purposes, we will ask your permission first. You can always see what information we have, how we're using it, and what permissions you have given us in your user profile.</li>
</ol>
<h2>How Your Gitea Instance Secures Your Information?</h2>
<p>Your Gitea Instance takes all measures reasonably necessary to protect User Personal Information from unauthorized access, alteration, or destruction; maintain data accuracy; and help ensure the appropriate use of User Personal Information.</p>
<p>To the extent above, we enforce a written security information program, which:</p>
<ul>
<li>aligns with industry recognized frameworks;</li>
<li>includes security safeguards reasonably designed to protect the confidentiality, integrity, availability, and resilience of our Users' data;</li>
<li>is appropriate to the nature, size, and complexity of Your Gitea Instances business operations;</li>
<li>includes incident response and data breach notification processes; and</li>
<li>complies with applicable information security-related laws and regulations in the geographic regions where Your Gitea Instance does business.</li>
</ul>
<p>In the event of a data breach that affects your User Personal Information, we will act promptly to mitigate the impact of a breach and notify any affected Users without undue delay.</p>
<p>Transmission of data on Your Gitea Instance is encrypted using SSH, HTTPS (TLS), and git repository content is encrypted at rest. We host Your Gitea Instance at our hosting partner, which they provide data centers with high level of physical and network security.</p>
<p><b>Disclaimer:</b> No method of transmission, or method of electronic storage, is 100% secure, therefore, we cannot guarantee absolute security.</p>
<h2>Cookies and Tracking Usage</h2>
<h3>Cookies</h3>
<p>We uses cookies to make interactions with our service easy and meaningful. Cookies are small text files that websites often store on computer hard drives or mobile devices of visitors. We use cookies (and similar technologies, like HTML5 localStorage) to keep you logged in, remember your preferences, and provide information for future development of Your Gitea Instance. For security purposes, we use cookies to identify a device. By using our Website, you agree that we can place these types of cookies on your computer or device. If you disable your browser or devices ability to accept these cookies, you will not be able to log in or use our services.</p>
<h3>Tracking and Analytics</h3>
<p>Out of the box, Gitea doesn't use third-party analytics. In case when we opt in to their usage, we do that to help us evaluate our Users' use of Your Gitea Instance, compile statistical reports on activity, and improve our content and Website performance. We only use these third-party analytics providers on certain areas of our Website, and all of them have signed data protection agreements with us that limit the type of User Personal Information they can collect and the purpose for which they can process the information. In addition, we may also deploy internal analytics software to provide similar functionality.</p>
<p>Some browsers have incorporated "Do Not Track" (DNT) features that can send a signal to the websites you visit indicating you do not wish to be tracked. Your Gitea Instance responds to browser DNT signals and follows the <a href="https://www.w3.org/TR/tracking-dnt/">W3C standard for responding to DNT signals</a>. If you have not enabled DNT on a browser that supports it, cookies on some parts of our Website will track your online browsing activity on other online services over time, though we do not permit third parties other than our analytics and service providers to track Your Gitea Instance Users' activity over time on Your Gitea Instance.</p>
<h2>Repository Contents</h2>
<p>Our employees do not access private repositories unless required to for security purposes, for support, to maintain integrity of the Service, or to comply with our legal obligations. While we don't generally search for content in your repositories, we may scan our servers and your content to detect tokens or security signatures, known malwares, or child exploitation imagery.</p>
<p>If your repository is public, anyone may view its contents. If you include private, confidential or Sensitive Personal Information, such as email addresses or passwords, in your public repository, that information may be indexed by search engines or used by third parties.</p>
<h2>Public Information</h2>
<p>Many of our services and feature are public-facing. If your content is public-facing, third parties may access and use it in compliance with our Terms of Service, such as by viewing your profile or repositories or pulling data via our API. We do not sell that content; it is yours. However, we do allow third parties, such as research organizations or archives, to compile public-facing Your Gitea Instance information. Other third parties, such as data brokers, have been known to scrape Your Gitea Instance and compile data as well.</p>
<p>Your User Personal Information associated with your content could be gathered by third parties in these compilations of Your Gitea Instance data. If you do not want your User Personal Information to appear in third parties compilations of Your Gitea Instance data, please do not make your User Personal Information publicly available and be sure to configure your email address to be private in your user profile and in your git commit settings.</p>
<p>If you would like to compile Your Gitea Instance data, you must comply with our Terms of Service regarding scraping and privacy, and you may only use any public-facing User Personal Information you gather for the purpose for which our user authorized it. For example, where a Your Gitea Instance user has made an email address public-facing for the purpose of identification and attribution, do not use that email address for commercial advertising. We expect you to reasonably secure any User Personal Information you have gathered from Your Gitea Instance, and to respond promptly to complaints, removal requests, and "do not contact" requests from Your Gitea Instance or Your Gitea Instance users.</p>
<p>In similar fashion, projects on Your Gitea Instance may include publicly available User Personal Information collected as part of the collaborative events.</p>
<h2>Organizations</h2>
<p>If you collaborate on or become a member of an Organization, then its Account owners may receive your User Personal Information. When you accept an invitation to an Organization, you will be notified of the types of information owners may be able to see. If you accept an invitation to an Organization with a verified domain, then the owners of that Organization will be able to see your full email address(es) within that Organization's verified domain(s).</p>
<p>Please note, Your Gitea Instance may share your username, Usage Information, and Device Information with the owner of the Organization you are a member of, to the extent that your User Personal Information is provided only to investigate or respond to a security incident that affects or compromises the security of that particular Organization.</p>
<p>If you collaborate with or become a member of an Account that has agreed to a Data Protection Addendum (DPA) to this Privacy Policy, then that DPA governs in the event of conflicts between this Privacy Policy and DPA with respect to your activity in the Account.</p>
<p>Please contact the Account owners for more information about how they might process your User Personal Information in their Organization and the ways for you to access, update, alter, or delete the User Personal Information stored in the Account.</p>
<h2>How You Can Access and Control the Information We Collect?</h2>
<p>If you're already a Your Gitea Instance user, you may access, update, alter, or delete your basic user information by editing your user profile. You can control the information we collect about you by limiting what information is in your profile, or by keeping your information current.</p>
<p>If Your Gitea Instance processes information about you, such as information receives from third parties, and you do not have an account, then you may, subject to applicable law, access, update, alter, delete, or object to the processing of your personal information by contacting our support.</p>
<h3>Data Portability</h3>
<p>As a Your Gitea Instance User, you can always take your data with you. You can clone your repositories to your computer, or you can <a href="https://docs.gitea.io/en-us/migrations-interfaces/">perform migrations using the provided interfaces</a>, for example.</p>
<h3>Data Retention and Deletion of Data</h3>
<p>In general, Your Gitea Instance retains User Personal Information for as long as your account is active, or as needed to provide you service.</p>
<p>If you would like to cancel your account or delete your User Personal Information, you may do so in your user profile. We retain and use your information as necessary to comply with our legal obligations, resolve disputes, and enforce our agreements, but barring legal requirements, we will delete your full profile (within reason) within 90 days of your request. Feel free to contact our support to request erasure of the data we process on the bassis of consent within 30 days.</p>
<p>After an account has been deleted, certain data, such as contributions to other Users' repositories and comments in others' issues, will remain. However, we will delete or de-identify your User Personal Information, including your username and email address, from the author field of issues, pull requests, and comments by associating them with a ghost user.</p>
<p>That said, the email address you have supplied via your Git commit settings will always be associated with your commits in the Git system. If you choose to make your email address private, you should also update your Git commit settings. We are unable to change or delete data in the Git commit history — the Git software is designed to maintain a record — but we do enable you to control what information you put in that record.</p>
<h2>Our Global Privacy Practices</h2>
<p>We store and process the information that we collect in the (country/state where Gitea is deployed) in accordance with this Privacy Statement though our service providers may store and process data outside the (country/state where Gitea is deployed). However, we understand that we have Users from different countries and regions with different privacy expectations, and we try to meet those needs even when the (country/state where Gitea is deployed) does not have the same privacy framework as other countries.</p>
<p>We provide a high standard of privacy protection—as described in this Privacy Statement—to all our users around the world, regardless of their country of origin or location, and we are proud of the levels of notice, choice, accountability, security, data integrity, access, and recourse we provide. We work hard to comply with the applicable data privacy laws wherever we do business, working with our Data Protection Officer as part of a cross-functional team that oversees our privacy compliance efforts. Additionally, if our vendors or affiliates have access to User Personal Information, they must sign agreements that require them to comply with our privacy policies and with applicable data privacy laws.</p>
<p>In particular:</p>
<ul>
<li>Your Gitea Instance provides clear methods of unambiguous, informed, specific, and freely given consent at the time of data collection, when we collect your User Personal Information using consent as a basis.</li>
<li>We collect only the minimum amount of User Personal Information necessary for our purposes, unless you choose to provide more. We encourage you to only give us the amount of data you are comfortable sharing.</li>
<li>We offer you simple methods of accessing, altering, or deleting the User Personal Information we have collected, where legally permitted.</li>
<li>We provide our Users notice, choice, accountability, security, and access regarding their User Personal Information, and we limit the purpose for processing it. We also provide our Users a method of recourse and enforcement. These are the Privacy Shield Principles, but they are also just good practices.</li>
</ul>
<h2>How We Communicate with You?</h2>
<p>We use your email address to communicate with you, if you've said that's okay, and only for the reasons youve said thats okay. For example, if you contact our support with a request, we respond to you via email. You have a lot of control over how your email address is used and shared on and through Your Gitea instance. You may manage your communication preferences in your user profile.</p>
<p>By design, the Git version control system associates many actions with a User's email address, such as commit messages. We are not able to change many aspects of the Git system. If you would like your email address to remain private, even when youre commenting on public repositories, you can create a private email address in your user profile. You should also update your local Git configuration to use your private email address. This will not change how we contact you, but it will affect how others see you.</p>
<p>Depending on your email settings, Your Gitea instance may occasionally send notification emails about changes in a repository youre watching, new features, requests for feedback, important policy changes, or to offer customer support. We also send marketing emails, based on your choices and in accordance with applicable laws and regulations. There's an “unsubscribe” link located at the bottom of each of the marketing emails we send you. Note that you can opt out of any communications with us, except the important ones (like from our support and system emails).</p>
<p>Our emails may contain a pixel tag, which is a small, clear image that can tell us whether or not you have opened an email and what your IP address is. We use this pixel tag to make our email more effective for you and to make sure were not sending you unwanted email.</p>
<h2>Changes to this Privacy Policy</h2>
<p>Although most changes are likely to be minor, Your Gitea Instance may change our Privacy Statement from time to time. We will provide notification to Users of material changes to this Privacy Statement through our Website at least 30 days prior to the change taking effect by posting a notice on our home page or sending email to the primary email address specified in your account.</p>
<h2>Contact</h2>
<p>If you have any concerns about privacy, please contact us at <a href="mailto:privacy@your-gitea-instance">privacy@your-gitea-instance</a>. We will respond promptly, within 45 days.</p>
<h2>COPYING</h2>
<p>This document is licensed under <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0 Public Domain license</a>.</p>
</body>
</html>

View File

@@ -1,245 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Terms of Service</title>
</head>
<body>
<h1>Terms of Service</h1>
<h4>Last updated: December 31, 2019</h4>
<p>Thank you for choosing Your Gitea Instance! Before you use it, please read this Terms of Service agreement carefully, which contains important contract between us and our users.</p>
<h2>Definitions</h2>
<ol>
<li>An "Account" represents your legal relationship with Your Gitea Instance. A “User Account” represents an individual Users authorization to log in to and use the Service and serves as a Users identity on Your Gitea Instance. “Organizations” are shared workspaces that may be associated with a single entity or with one or more Users where multiple Users can collaborate across many projects at once. A User Account can be a member of any number of Organizations.</li>
<li>The "Agreement" collectively refers to all terms, conditions, and notices referenced or contained in this document and other operating rules, policies (including Privacy Policy) and procedures that we may publish from time to time on this Website.</li>
<li>“Content” refers to content featured or displayed through the Website, including without limitation code, text, data, articles, images, photographs, graphics, software, applications, packages, designs, features, and other materials that are available on the Website or otherwise available through the Service. "Content" also includes Services. “User-Generated Content” is Content, written or otherwise, created or uploaded by our Users. "Your Content" is Content that you create or own.</li>
<li>"Your Gitea Instance", "We", and "Us" refers to Your Gitea Instance, as well as our affiliates, directors, subsidiaries, contractors, licensors, officers, agents, and employees.</li>
<li>The "Service" refers to applications/software, products, and services provided by Your Gitea Instance.</li>
<li>The "User", "You", and "Your" refers to individual person or institution (organizations or company) that has visited or using the Service; that have access or use any part of the Account; or that directs to use the Account to perform its function. Please note that additional terms may apply for Accounts related to business or government.</li>
<li>The "Website" refers to Your Gitea Instance's website at <a href="https://your-gitea-instance">your-gitea-instance</a>, including its subdomains and other websites owned by Your Gitea Instance.</li>
</ol>
<h2>Account Terms</h2>
<h3>Account Controls</h3>
<ul>
<li>Users: Subject to these Terms, you retain ultimate administrative control over your User Account and the Content within it.</li>
<li>Organizations. The "owner" of an Organization that was created under these Terms has ultimate administrative control over that Organization and the Content within it. Within the Service, an owner can manage User access to the Organizations data and projects. An Organization may have multiple owners, but there must be at least one User Account designated as an owner of an Organization. If you are the owner of an Organization under these Terms, we consider you responsible for the actions that are performed on or through that Organization.</li>
</ul>
<h3>Required Information</h3>
<p>You must provide a valid email address in order to complete the signup process. Any other information requested, such as your real name, is optional, unless you are accepting these terms on behalf of a legal entity (in which case we need more information about the legal entity).</p>
<h3>Account Requirements</h3>
<ul>
<li>You must be a human to create an Account. Accounts registered by "bots" or other automated methods are not permitted. We do permit machine accounts:</li>
<li>A machine account is an Account set up by an individual human who accepts the Terms on behalf of the Account, provides a valid email address, and is responsible for its actions. A machine account is used exclusively for performing automated tasks. Multiple users may direct the actions of a machine account, but the owner of the Account is ultimately responsible for the machine's actions.</li>
<li>You must be age 13 or older. If we learn of any User under that age, we will immediately terminate that User's Account. Different countries may have different minimum age; in such cases you are responsible for complying with your country's regulation. By using Your Gitea Instance, you agree to comply with <a href="https://www.ftc.gov/enforcement/rules/rulemaking-regulatory-reform-proceedings/childrens-online-privacy-protection-rule">COPPA</a> and/or similar law in your country.</li>
</ul>
<h3>User Account Security</h3>
<p>You are responsible for keeping your Account secure while you use our Service. We offer tools such as two-factor authentication to help you maintain your Account's security, but the content of your Account and its security are up to you.</p>
<h3>Additional Terms</h3>
<p>In some situations, third parties' terms may apply to your use of Your Gitea Instance. For example, you may be a member of an organization on Your Gitea Instance with its own terms or license agreements; you may download an application that integrates with Your Gitea Instance; or you may use Your Gitea Instance to authenticate to another service. Please be aware that while these Terms are our full agreement with you, other parties' terms govern their relationships with you.</p>
<h2>Acceptable Use</h2>
<p>Your use of the Website and Service must not violate any applicable laws, including copyright or trademark laws, export control or sanctions laws, or other laws in your jurisdiction. You are responsible for making sure that your use of the Service is in compliance with laws and any applicable regulations.</p>
<h2>User-Generated Content</h2>
<ol>
<li>You may create or upload User-Generated Content while using the Service. You are solely responsible for the content of, and for any harm resulting from, any User-Generated Content that you post, upload, link to or otherwise make available via the Service, regardless of the form of that Content. We are not responsible for any public display or misuse of your User-Generated Content.</li>
<li>We do not pre-screen User-Generated Content, but we have the right (though not the obligation) to refuse or remove any User-Generated Content that, in our sole discretion, violates any our terms or policies.</li>
<li>
<p>You retain ownership of and responsibility for Your Content. If you're posting anything you did not create yourself or do not own the rights to, you agree that you are responsible for any Content you post; that you will only submit Content that you have the right to post; and that you will fully comply with any third party licenses relating to Content you post.</p>
<p>Because of above, we need you to grant us -- and other Your Gitea Instance users -- certain legal permissions, listed below in this section. If you upload Content that already comes with a license granting Your Gitea Instance the permissions we need to run our Service, no additional license is required. You understand that you will not receive any payment for any of the rights granted below. The licenses you grant to us will end when you remove Your Content from our servers, unless other Users have forked it.</p>
</li>
<li>
<p>We need the legal right to do things like host Your Content, publish it, and share it. You grant us and our legal successors the right to store, parse, and display Your Content, and make incidental copies as necessary to render the Website and provide the Service. This includes the right to do things like copy it to our database and make backups; show it to you and other users; parse it into a search index or otherwise analyze it on our servers; share it with other users; and perform it, in case Your Content is something like music or video.</p>
<p>This license, however, doesn't grant Your Gitea Instance the right to sell Your Content or otherwise distribute or use it outside of our provision of the Service.</p>
</li>
<li>
<p>Any User-Generated Content you post publicly, including issues, comments, and contributions to other Users' repositories, may be viewed by others. By setting your repositories to be viewed publicly, you agree to allow others to view and "fork" your repositories (this means that others may make their own copies of Content from your repositories in repositories they control).</p>
<p>If you set your pages and repositories to be viewed publicly, you grant each User of Your Gitea Instance a nonexclusive, worldwide license to use, display, and perform Your Content through the Your Gitea Instance Service and to reproduce Your Content solely on Your Gitea Instance as permitted through Your Gitea Instance's functionality (for example, through forking). You may grant further rights if you adopt a license. If you are uploading Content you did not create or own, you are responsible for ensuring that the Content you upload is licensed under terms that grant these permissions to other Your Gitea Instance Users.</p>
</li>
<li>
<p>Whenever you make a contribution to a repository containing notice of a license, you license your contribution under the same terms, and you agree that you have the right to license your contribution under those terms. If you have a separate agreement to license your contributions under different terms, such as a contributor license agreement, that agreement will supersede.</p>
<p><i>Isn't this just how it works already? Yep. This is widely accepted as the norm in the open-source community; it's commonly referred to by the shorthand "inbound=outbound". We're just making it explicit.</i></p>
</li>
<li>
<p>You retain all moral rights to Your Content that you upload, publish, or submit to any part of the Service, including the rights of integrity and attribution. However, you waive these rights and agree not to assert them against us, to enable us to reasonably exercise the rights granted above, but not otherwise.</p>
<p>To the extent this agreement is not enforceable by applicable law, you grant Your Gitea Instance the rights we need to use Your Content without attribution and to make reasonable adaptations of Your Content as necessary to render the Website and provide the Service.</p>
</li>
</ol>
<h2>Private Repositories</h2>
<ol>
<li>Some Accounts may have private repositories, which allow the User to control access to Content.</li>
<li>Your Gitea Instance considers the contents of private repositories to be confidential to you. Your Gitea Instance will protect the contents of private repositories from unauthorized use, access, or disclosure in the same manner that we would use to protect our own confidential information of a similar nature and in no event with less than a reasonable degree of care.</li>
<li>
<p>Your Gitea Instance employees may only access the content of your private repositories in the following situations:</p>
<ul>
<li>With your consent and knowledge, for support reasons. If Your Gitea Instance accesses a private repository for support reasons, we will only do so with the owners consent and knowledge.</li>
<li>When access is required for security reasons, including when access is required to maintain ongoing confidentiality, integrity, availability and resilience of Your Gitea Instance's systems and Service.</li>
</ul>
</li>
<li>You may choose to enable additional access to your private repositories. For example: You may enable various Your Gitea Instance services or features that require additional rights to Your Content in private repositories. These rights may vary depending on the service or feature, but Your Gitea Instance will continue to treat your private repository Content as confidential. If those services or features require rights in addition to those we need to provide the Your Gitea Instance Service, we will provide an explanation of those rights.</li>
</ol>
<h2>Copyright Infringement and DMCA Policy</h2>
<p>If you are copyright owner and believe that content on our website violates your copyright, please contact us at <a href="mailto:copyright@your-gitea-instance">copyright@your-gitea-instance</a>. Please note that before sending a takedown notice, consider legal uses (such as fair use and licensed use); and legal consequences for sending false notices.</p>
<h2>Intellectual Properties and COPYING</h2>
<p>Your Gitea Instance and our licensors, vendors, agents, and/or our content providers retain ownership of all intellectual property rights of any kind related to the Website and Service. We reserve all rights that are not expressly granted to you under this Agreement or by law. The look and feel of the Website and Service is copyright © Your Gitea Instance. All rights reserved.</p>
<p>If you'd like to use our trademarks, you must follow all of our trademark guidelines.</p>
<p>This Agreement is licensed under <a href="https://creativecommons.org/publicdomain/zero/1.0/">CCO Public Domain License</a>.</p>
<h2>API Terms</h2>
<p>Abuse or excessively frequent requests to Your Gitea Instance via the API may result in the temporary or permanent suspension of your Account's access to the API. Your Gitea Instance, in our sole discretion, will determine abuse or excessive usage of the API. We will make a reasonable attempt to warn you via email prior to suspension.</p>
<p>You may not share API tokens to exceed Your Gitea Instance's rate limitations.</p>
<p>You may not use the API to download data or Content from Your Gitea Instance for spamming purposes, including for the purposes of selling Your Gitea Instance users' personal information, such as to recruiters, headhunters, and job boards.</p>
<p>All use of the Your Gitea Instance API is subject to these Terms of Service and the Your Gitea Instance Privacy Statement.</p>
<p>However, we may provide subscription-based access to our API for Users who need high-throughput access or reselling our Service.</p>
<h2>Cancellation and Termination</h2>
<h3>Account Cancellation</h3>
<p>It is your responsibility to properly cancel your Account with Your Gitea Instance. You can cancel your Account at any time by going into your Settings in the global navigation bar at the top of the screen. The Account screen provides a simple, no questions asked cancellation link. We are not able to cancel Accounts in response to an email or phone request.</p>
<h3>Upon Cancellation</h3>
<p>We will retain and use your information as necessary to comply with our legal obligations, resolve disputes, and enforce our agreements, but barring legal requirements, we will delete your full profile and the Content of your repositories within 90 days of cancellation or termination (though some information may remain in encrypted backups). This information can not be recovered once your Account is cancelled.</p>
<p>We will not delete Content that you have contributed to other Users' repositories or that other Users have forked.</p>
<p>Upon request, we will make a reasonable effort to provide an Account owner with a copy of your lawful, non-infringing Account contents after Account cancellation or termination. You must make this request within 90 days of cancellation or termination.</p>
<h3>We May Terminate</h3>
<p>Your Gitea Instance has the right to suspend or terminate your access to all or any part of the Website at any time, with or without cause, with or without notice, effective immediately. Your Gitea Instance reserves the right to refuse service to anyone for any reason at any time.</p>
<h3>Survival</h3>
<p>All provisions of this Agreement which, by their nature, should survive termination will survive termination — including, without limitation: ownership provisions, warranty disclaimers, indemnity, and limitations of liability.</p>
<h2>Communications with Us</h2>
<h3>Electronic Communications Required</h3>
<p>For contractual purposes, you (1) consent to receive communications from us in an electronic form via the email address you have submitted or via the Service; and (2) agree that all Terms of Service, agreements, notices, disclosures, and other communications that we provide to you electronically satisfy any legal requirement that those communications would satisfy if they were on paper. This section does not affect your non-waivable rights.</p>
<h3>Legal Notices to Us Must Be in Writing</h3>
<p>Communications made through email or Your Gitea Instance Support's messaging system will not constitute legal notice to Your Gitea Instance or any of its officers, employees, agents or representatives in any situation where notice to Your Gitea Instance is required by contract or any law or regulation. Legal notice to Your Gitea Instance must be in writing and served on Your Gitea Instance's legal agent.</p>
<h3>No Phone Support</h3>
<p>We only offer support via email, in-Service communications, and electronic messages. We do not offer telephone support.</p>
<h2>Disclaimer of Warranties</h2>
<p>Your Gitea Instance provides the Website and the Service “as is” and “as available,” without warranty of any kind. Without limiting this, we expressly disclaim all warranties, whether express, implied or statutory, regarding the Website and the Service including without limitation any warranty of merchantability, fitness for a particular purpose, title, security, accuracy and non-infringement.</p>
<p>Your Gitea Instance does not warrant that the Service will meet your requirements; that the Service will be uninterrupted, timely, secure, or error-free; that the information provided through the Service is accurate, reliable or correct; that any defects or errors will be corrected; that the Service will be available at any particular time or location; or that the Service is free of viruses or other harmful components. You assume full responsibility and risk of loss resulting from your downloading and/or use of files, information, content or other material obtained from the Service.</p>
<h2>Limitation of Liability</h2>
<p>You understand and agree that we will not be liable to you or any third party for any loss of profits, use, goodwill, or data, or for any incidental, indirect, special, consequential or exemplary damages, however arising, that result from:</p>
<ul>
<li>the use, disclosure, or display of your User-Generated Content;</li>
<li>your use or inability to use the Service;</li>
<li>any modification, price change, suspension or discontinuance of the Service;</li>
<li>the Service generally or the software or systems that make the Service available;</li>
<li>unauthorized access to or alterations of your transmissions or data;</li>
<li>statements or conduct of any third party on the Service;</li>
<li>any other user interactions that you input or receive through your use of the Service; or
any other matter relating to the Service.</li>
</ul>
<p>Our liability is limited whether or not we have been informed of the possibility of such damages, and even if a remedy set forth in this Agreement is found to have failed of its essential purpose. We will have no liability for any failure or delay due to matters beyond our reasonable control.</p>
<h2>Release and Indemnification</h2>
<p>If you have a dispute with one or more Users, you agree to release Your Gitea Instance from any and all claims, demands and damages (actual and consequential) of every kind and nature, known and unknown, arising out of or in any way connected with such disputes.</p>
<p>You agree to indemnify us, defend us, and hold us harmless from and against any and all claims, liabilities, and expenses, including attorneys fees, arising out of your use of the Website and the Service, including but not limited to your violation of this Agreement, provided that Your Gitea Instance (1) promptly gives you written notice of the claim, demand, suit or proceeding; (2) gives you sole control of the defense and settlement of the claim, demand, suit or proceeding (provided that you may not settle any claim, demand, suit or proceeding unless the settlement unconditionally releases Your Gitea Instance of all liability); and (3) provides to you all reasonable assistance, at your expense.</p>
<h2>Changes to These Terms</h2>
<p>We reserve the right, at our sole discretion, to amend these Terms of Service at any time and will update these Terms of Service in the event of any such amendments. We will notify our Users of material changes to this Agreement, such as price changes, at least 30 days prior to the change taking effect by posting a notice on our Website. For non-material modifications, your continued use of the Website constitutes agreement to our revisions of these Terms of Service.</p>
<h2>Miscellaneous</h2>
<h3>Governing Law</h3>
<p>Except to the extent applicable law provides otherwise, this Agreement between you and us and any access to or use of the Website or the Service are governed by (national laws of country/state where Gitea is deployed) and (regional laws of locality where Gitea is deployed), without regard to conflict of law provisions. You and Your Gitea Instance agree to submit to the exclusive jurisdiction and venue of the courts located in (locality where Gitea is deployed).</p>
<h3>Non-Assignability</h3>
<p>Your Gitea Instance may assign or delegate these Terms of Service and/or our Privacy Policy in whole or in part, to any person or entity at any time with or without your consent, including the license granted in <i>User-Generated Content</i>. You may not assign or delegate any rights or obligations under the Terms of Service or Privacy Statement without our prior written consent, and any unauthorized assignment and delegation by you is void.</p>
<h3>Severablity, No Waiver, and Survival</h3>
<p>If any part of this Agreement is held invalid or unenforceable, that portion of the Agreement will be construed to reflect the parties original intent. The remaining portions will remain in full force and effect. Any failure on the part of Your Gitea Instance to enforce any provision of this Agreement will not be considered a waiver of our right to enforce such provision. Our rights under this Agreement will survive any termination of this Agreement.</p>
<h3>Amendments and Complete Agreement</h3>
<p>This Agreement may only be modified by a written amendment signed by an authorized representative of Your Gitea Instance, or by the posting by Your Gitea Instance of a revised version in accordance with <i>Changes to These Terms</i>. These Terms of Service, together with the Your Gitea Instance Privacy Policy, represent the complete and exclusive statement of the agreement between you and us. This Agreement supersedes any proposal or prior agreement oral or written, and any other communications between you and Your Gitea Instance relating to the subject matter of these terms including any confidentiality or nondisclosure agreements.</p>
<h3>Contact</h3>
<p>If you have questions about these Terms of Service, you can <a href="mailto:support@your-gitea-instance">contact our support</a>.</p>
</body>
</html>

View File

@@ -1,26 +0,0 @@
#424242 Status: Needs feedback ; Feedback is needed
#fbc02d Status: In progress ; Work is in progress
#43a047 Status: Completed ; Work is complete
#00796b Status: Help wanted ;
#880e4f Status: Blocked ;
#b0bec5 Status: Stale ;
#d32f2f Kind: Bug ;
#607d8b Kind: Question ;
#9c27b0 Kind: Security ;
#795548 Kind: Testing ;
#c62828 Kind: Breaking ;
#37474f Kind: Documentation ;
#0288d1 Kind: Feature ;
#2e7d32 Kind: Enhancement ;
#f4511e Kind: Maintenance ;
#546e7a Reviewed: Invalid ; Something was marked as invalid
#616161 Reviewed: Duplicate; Something exists already
#795548 Reviewed: Confirmed ; Something has been confirmed
#eeeeee Reviewed: Wontfix ; Something won't be fixed
#d32f2f Priority: High ; The priority is high
#e64a19 Priority: Medium ; The priority is medium
#4caf50 Priority: Low ; The priority is low
#b71c1c Priority: Critical ; The priority is critical

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"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"os/exec"
"os/user"
"path"
"path/filepath"
"runtime"
"strconv"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/external"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/routes"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
context2 "github.com/gorilla/context"
"github.com/unknwon/com"
"gopkg.in/testfixtures.v2"
"xorm.io/xorm"
)
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.NewContext()
setting.RepoRootPath, err = ioutil.TempDir(os.TempDir(), "repos")
if err != nil {
log.Fatalf("TempDir: %v\n", err)
}
setting.AppDataPath, err = ioutil.TempDir(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")
setting.CheckLFSVersion()
//models.LoadConfigs()
/*
setting.Database.Type = "sqlite3"
setting.Database.Path = ":memory:"
setting.Database.Timeout = 500
*/
db := setting.Cfg.Section("database")
db.NewKey("DB_TYPE", "sqlite3")
db.NewKey("PATH", ":memory:")
routers.NewServices()
setting.Database.LogSQL = true
//x, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared")
var helper testfixtures.Helper = &testfixtures.SQLite{}
models.NewEngine(context.Background(), func(_ *xorm.Engine) error {
return nil
})
models.HasEngine = true
//x.ShowSQL(true)
err = models.InitFixtures(
helper,
path.Join(curDir, "models/fixtures/"),
)
if err != nil {
fmt.Printf("Error initializing test database: %v\n", err)
os.Exit(1)
}
models.LoadFixtures()
os.RemoveAll(setting.RepoRootPath)
os.RemoveAll(models.LocalCopyPath())
com.CopyDir(path.Join(curDir, "integrations/gitea-repositories-meta"), setting.RepoRootPath)
log.Printf("[PR] Setting up router\n")
//routers.GlobalInit()
external.RegisterParsers()
markup.Init()
m := routes.NewMacaron()
routes.RegisterRoutes(m)
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", context2.ClearHandler(m))
log.Printf("[PR] Cleaning up ...\n")
/*
if err = os.RemoveAll(setting.Indexer.IssuePath); err != nil {
fmt.Printf("os.RemoveAll: %v\n", err)
os.Exit(1)
}
if err = os.RemoveAll(setting.Indexer.RepoPath); err != nil {
fmt.Printf("Unable to remove repo indexer: %v\n", err)
os.Exit(1)
}
*/
if err = os.RemoveAll(setting.RepoRootPath); err != nil {
log.Fatalf("os.RemoveAll: %v\n", err)
}
if err = os.RemoveAll(setting.AppDataPath); err != nil {
log.Fatalf("os.RemoveAll: %v\n", err)
}
}
func main() {
var 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 := ioutil.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" || 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("refs/pull/%s/head:%s", 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), 0755)
if err != nil {
log.Fatalf("Failed to duplicate this code file in PR : %v", err)
}
err = ioutil.WriteFile(codeFilePath, dat, 0644)
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

@@ -2,42 +2,10 @@
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target
###
# Don't forget to add the database service requirements
###
#
#Requires=mysql.service
#Requires=mariadb.service
#Requires=postgresql.service
#Requires=memcached.service
#Requires=redis.service
#
###
# If using socket activation for main http/s
###
#
#After=gitea.main.socket
#Requires=gitea.main.socket
#
###
# (You can also provide gitea an http fallback and/or ssh socket too)
#
# An example of /etc/systemd/system/gitea.main.socket
###
##
## [Unit]
## Description=Gitea Web Socket
## PartOf=gitea.service
##
## [Socket]
## Service=gitea.service
## ListenStream=<some_port>
## NoDelay=true
##
## [Install]
## WantedBy=sockets.target
##
###
#After=mysqld.service
#After=postgresql.service
#After=memcached.service
#After=redis.service
[Service]
# Modify these two values and uncomment them if you have
@@ -51,18 +19,14 @@ Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea/
# If using Unix socket: tells systemd to create the /run/gitea folder, which will contain the gitea.sock file
# (manually creating /run/gitea doesn't work, because it would not persist across reboots)
#RuntimeDirectory=gitea
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
ExecStart=/usr/local/bin/gitea web -c /etc/gitea/app.ini
Restart=always
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
# If you want to bind Gitea to a port below 1024, uncomment
# the two values below, or use socket activation to pass Gitea its ports as above
# If you want to bind Gitea to a port below 1024 uncomment
# the two values below
###
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
#AmbientCapabilities=CAP_NET_BIND_SERVICE
###
[Install]
WantedBy=multi-user.target

View File

@@ -31,30 +31,11 @@ PULL_REQUEST_QUEUE_LENGTH = 1000
PREFERRED_LICENSES = Apache License 2.0,MIT License
; Disable the ability to interact with repositories using the HTTP protocol
DISABLE_HTTP_GIT = false
; Value for Access-Control-Allow-Origin header, default is not to present
; WARNING: This maybe harmful to you website if you do not give it a right value.
ACCESS_CONTROL_ALLOW_ORIGIN =
; Force ssh:// clone url instead of scp-style uri when default SSH port is used
USE_COMPAT_SSH_URI = false
; Close issues as long as a commit on any branch marks it as fixed
DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH = false
; Allow users to push local repositories to Gitea and have them automatically created for a user or an org
ENABLE_PUSH_CREATE_USER = false
ENABLE_PUSH_CREATE_ORG = false
; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki
DISABLED_REPO_UNITS =
; Comma separated list of default repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki.
; Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility.
; External wiki and issue tracker can't be enabled by default as it requires additional settings.
; Disabled repo units will not be added to new repositories regardless if it is in the default list.
DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki
; Prefix archive files by placing them in a directory named after the repository
PREFIX_ARCHIVE_FILES = true
; The default branch name of new repositories
DEFAULT_BRANCH=master
[repository.editor]
; List of file extensions for which lines should be wrapped in the Monaco editor
; List of file extensions for which lines should be wrapped in the CodeMirror 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
@@ -82,73 +63,6 @@ MAX_FILES = 5
[repository.pull-request]
; List of prefixes used in Pull Request title to mark them as Work In Progress
WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP]
; List of keywords used in Pull Request comments to automatically close a related issue
CLOSE_KEYWORDS=close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved
; List of keywords used in Pull Request comments to automatically reopen a related issue
REOPEN_KEYWORDS=reopen,reopens,reopened
; In the default merge message for squash commits include at most this many commits
DEFAULT_MERGE_MESSAGE_COMMITS_LIMIT=50
; In the default merge message for squash commits limit the size of the commit messages to this
DEFAULT_MERGE_MESSAGE_SIZE=5120
; In the default merge message for squash commits walk all commits to include all authors in the Co-authored-by otherwise just use those in the limited list
DEFAULT_MERGE_MESSAGE_ALL_AUTHORS=false
; In default merge messages limit the number of approvers listed as Reviewed-by: to this many
DEFAULT_MERGE_MESSAGE_MAX_APPROVERS=10
; In default merge messages only include approvers who are official
DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY=true
[repository.issue]
; List of reasons why a Pull Request or Issue can be locked
LOCK_REASONS=Too heated,Off-topic,Resolved,Spam
[repository.signing]
; GPG key to use to sign commits, Defaults to the default - that is the value of git config --get user.signingkey
; run in the context of the RUN_USER
; Switch to none to stop signing completely
SIGNING_KEY = default
; If a SIGNING_KEY ID is provided and is not set to default, use the provided Name and Email address as the signer.
; These should match a publicized name and email address for the key. (When SIGNING_KEY is default these are set to
; the results of git config --get user.name and git config --get user.email respectively and can only be overrided
; by setting the SIGNING_KEY ID to the correct ID.)
SIGNING_NAME =
SIGNING_EMAIL =
; Determines when gitea should sign the initial commit when creating a repository
; Either:
; - never
; - pubkey: only sign if the user has a pubkey
; - twofa: only sign if the user has logged in with twofa
; - always
; options other than none and always can be combined as comma separated list
INITIAL_COMMIT = always
; Determines when to sign for CRUD actions
; - as above
; - parentsigned: requires that the parent commit is signed.
CRUD_ACTIONS = pubkey, twofa, parentsigned
; Determines when to sign Wiki commits
; - as above
WIKI = never
; Determines when to sign on merges
; - basesigned: require that the parent of commit on the base repo is signed.
; - commitssigned: require that all the commits in the head branch are signed.
; - approved: only sign when merging an approved pr to a protected branch
MERGES = pubkey, twofa, basesigned, commitssigned
[cors]
; More information about CORS can be found here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers
; enable cors headers (disabled by default)
ENABLED=false
; scheme of allowed requests
SCHEME=http
; list of requesting domains that are allowed
ALLOW_DOMAIN=*
; allow subdomains of headers listed above to request
ALLOW_SUBDOMAIN=false
; list of methods allowed to request
METHODS=GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS
; max time to cache response
MAX_AGE=10m
; allow request with credentials
ALLOW_CREDENTIALS=false
[ui]
; Number of repositories that are displayed on one explore page
@@ -171,18 +85,6 @@ MAX_DISPLAY_FILE_SIZE = 8388608
SHOW_USER_EMAIL = true
; Set the default theme for the Gitea install
DEFAULT_THEME = gitea
; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`.
THEMES = gitea,arc-green
;All available reactions users can choose on issues/prs and comments.
;Values can be emoji alias (:smile:) or a unicode emoji.
;For custom reactions, add a tightly cropped square image to public/emoji/img/reaction_name.png
REACTIONS = +1, -1, laugh, hooray, confused, heart, rocket, eyes
; Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
DEFAULT_SHOW_FULL_NAME = false
; Whether to search within description at repository search on explore page.
SEARCH_REPO_DESCRIPTION = true
; Whether to enable a Service Worker to cache frontend assets
USE_SERVICE_WORKER = true
[ui.admin]
; Number of users that are displayed on one page
@@ -203,28 +105,11 @@ AUTHOR = Gitea - Git with a cup of tea
DESCRIPTION = Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go
KEYWORDS = go,git,self-hosted,gitea
[ui.notification]
; Control how often the notification endpoint is polled to update the notification
; The timeout will increase to MAX_TIMEOUT in TIMEOUT_STEPs if the notification count is unchanged
; Set MIN_TIMEOUT to 0 to turn off
MIN_TIMEOUT = 10s
MAX_TIMEOUT = 60s
TIMEOUT_STEP = 10s
; This setting determines how often the db is queried to get the latest notification counts.
; If the browser client supports EventSource and SharedWorker, a SharedWorker will be used in preference to polling notification. Set to -1 to disable the EventSource
EVENT_SOURCE_UPDATE_TIME = 10s
[markdown]
; Render soft line breaks as hard line breaks, which means a single newline character between
; paragraphs will cause a line break and adding trailing whitespace to paragraphs is not
; necessary to force a line break.
; Render soft line breaks as hard line breaks for comments
ENABLE_HARD_LINE_BREAK_IN_COMMENTS = true
; Render soft line breaks as hard line breaks for markdown documents
ENABLE_HARD_LINE_BREAK_IN_DOCUMENTS = false
; Comma separated list of custom URL-Schemes that are allowed as links when rendering Markdown
; for example git,magnet,ftp (more at https://en.wikipedia.org/wiki/List_of_URI_schemes)
; URLs starting with http and https are always displayed, whatever is put in this entry.
; Enable hard line break extension
ENABLE_HARD_LINE_BREAK = false
; List of custom URL-Schemes that are allowed as links when rendering Markdown
; for example git,magnet
CUSTOM_URL_SCHEMES =
; List of file extensions that should be rendered/edited as Markdown
; Separate the extensions with a comma. To render files without any extension as markdown, just put a comma
@@ -235,11 +120,8 @@ FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd
PROTOCOL = http
DOMAIN = localhost
ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
; when STATIC_URL_PREFIX is empty it will follow ROOT_URL
STATIC_URL_PREFIX =
; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket.
HTTP_ADDR = 0.0.0.0
; The port to listen on. Leave empty when using a unix socket.
HTTP_PORT = 3000
; If REDIRECT_OTHER_PORT is true, and PROTOCOL is set to https an http server
; will be started on PORT_TO_REDIRECT and it will redirect plain, non-secure http requests to the main
@@ -303,9 +185,8 @@ DISABLE_ROUTER_LOG = false
; not forget to export the private key):
; $ openssl pkcs12 -in cert.pfx -out cert.pem -nokeys
; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes
; Paths are relative to CUSTOM_PATH
CERT_FILE = https/cert.pem
KEY_FILE = https/key.pem
CERT_FILE = custom/https/cert.pem
KEY_FILE = custom/https/key.pem
; Root directory containing templates and static files.
; default is the path where Gitea is executed
STATIC_ROOT_PATH =
@@ -319,8 +200,7 @@ ENABLE_GZIP = false
ENABLE_PPROF = false
; PPROF_DATA_PATH, use an absolute path when you start gitea as service
PPROF_DATA_PATH = data/tmp/pprof
; Landing page, can be "home", "explore", "organizations" or "login"
; The "login" choice is not a security measure but just a UI flow change, use REQUIRE_SIGNIN_VIEW to force users to log in.
; Landing page, can be "home", "explore", or "organizations"
LANDING_PAGE = home
; Enables git-lfs support. true or false, default is false.
LFS_START_SERVER = false
@@ -330,21 +210,6 @@ LFS_CONTENT_PATH = data/lfs
LFS_JWT_SECRET =
; LFS authentication validity period (in time.Duration), pushes taking longer than this may fail.
LFS_HTTP_AUTH_EXPIRY = 20m
; Maximum allowed LFS file size in bytes (Set to 0 for no limit).
LFS_MAX_FILE_SIZE = 0
; Maximum number of locks returned per page
LFS_LOCKS_PAGING_NUM = 50
; Allow graceful restarts using SIGHUP to fork
ALLOW_GRACEFUL_RESTARTS = true
; After a restart the parent will finish ongoing requests before
; shutting down. Force shutdown if this process takes longer than this delay.
; set to a negative value to disable
GRACEFUL_HAMMER_TIME = 60s
; Allows the setting of a startup timeout and waithint for Windows as SVC service
; 0 disables this.
STARTUP_TIMEOUT = 0
; Static resources, includes resources on custom/, public/ and all uploaded avatars web browser cache time, default is 6h
STATIC_CACHE_TIME = 6h
; Define allowed algorithms and their minimum key length (use -1 to disable a type)
[ssh.minimum_key_sizes]
@@ -354,23 +219,16 @@ RSA = 2048
DSA = 1024
[database]
; Database to use. Either "mysql", "postgres", "mssql" or "sqlite3".
; Either "mysql", "postgres", "mssql" or "sqlite3", it's your choice
DB_TYPE = mysql
HOST = 127.0.0.1:3306
NAME = gitea
USER = root
; Use PASSWD = `your password` for quoting if you use special characters in the password.
PASSWD =
; For Postgres, schema to use if different from "public". The schema must exist beforehand,
; the user must have creation privileges on it, and the user search path must be set
; to the look into the schema first. e.g.:ALTER USER user SET SEARCH_PATH = schema_name,"$user",public;
SCHEMA =
; For Postgres, either "disable" (default), "require", or "verify-full"
; For MySQL, either "false" (default), "true", or "skip-verify"
SSL_MODE = disable
; For MySQL only, either "utf8" or "utf8mb4", default is "utf8".
; NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this.
CHARSET = utf8
; For "sqlite3" and "tidb", use an absolute path when you start gitea as service
PATH = data/gitea.db
; For "sqlite3" only. Query timeout
@@ -379,95 +237,25 @@ SQLITE_TIMEOUT = 500
ITERATE_BUFFER_SIZE = 50
; Show the database generated SQL
LOG_SQL = true
; Maximum number of DB Connect retries
DB_RETRIES = 10
; Backoff time per DB retry (time.Duration)
DB_RETRY_BACKOFF = 3s
; Max idle database connections on connnection pool, default is 2
MAX_IDLE_CONNS = 2
; Database connection max life time, default is 0 or 3s mysql (See #6804 & #7071 for reasoning)
CONN_MAX_LIFETIME = 3s
; Database maximum number of open connections, default is 0 meaning no maximum
MAX_OPEN_CONNS = 0
[indexer]
; Issue indexer type, currently support: bleve, db or elasticsearch, default is bleve
ISSUE_INDEXER_TYPE = bleve
; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch
ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
; Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch
ISSUE_INDEXER_NAME = gitea_issues
; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve
ISSUE_INDEXER_PATH = indexers/issues.bleve
; Issue indexer queue, currently support: channel, levelqueue or redis, default is levelqueue
ISSUE_INDEXER_QUEUE_TYPE = levelqueue
; When ISSUE_INDEXER_QUEUE_TYPE is levelqueue, this will be the queue will be saved path,
; default is indexers/issues.queue
ISSUE_INDEXER_QUEUE_DIR = indexers/issues.queue
; When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string.
ISSUE_INDEXER_QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0"
; Batch queue number, default is 20
ISSUE_INDEXER_QUEUE_BATCH_NUMBER = 20
; Timeout the indexer if it takes longer than this to start.
; Set to zero to disable timeout.
STARTUP_TIMEOUT=30s
; repo indexer by default disabled, since it uses a lot of disk space
REPO_INDEXER_ENABLED = false
REPO_INDEXER_PATH = indexers/repos.bleve
UPDATE_BUFFER_LEN = 20
MAX_FILE_SIZE = 1048576
; A comma separated list of glob patterns (see https://github.com/gobwas/glob) to include
; in the index; default is empty
REPO_INDEXER_INCLUDE =
; A comma separated list of glob patterns to exclude from the index; ; default is empty
REPO_INDEXER_EXCLUDE =
[queue]
; Specific queues can be individually configured with [queue.name]. [queue] provides defaults
;
; General queue queue type, currently support: persistable-channel, channel, level, redis, dummy
; default to persistable-channel
TYPE = persistable-channel
; data-dir for storing persistable queues and level queues, individual queues will be named by their type
DATADIR = queues/
; Default queue length before a channel queue will block
LENGTH = 20
; Batch size to send for batched queues
BATCH_LENGTH = 20
; Connection string for redis queues this will store the redis connection string.
CONN_STR = "addrs=127.0.0.1:6379 db=0"
; Provide the suffix of the default redis queue name - specific queues can be overriden within in their [queue.name] sections.
QUEUE_NAME = "_queue"
; If the queue cannot be created at startup - level queues may need a timeout at startup - wrap the queue:
WRAP_IF_NECESSARY = true
; Attempt to create the wrapped queue at max
MAX_ATTEMPTS = 10
; Timeout queue creation
TIMEOUT = 15m30s
; Create a pool with this many workers
WORKERS = 1
; Dynamically scale the worker pool to at this many workers
MAX_WORKERS = 10
; Add boost workers when the queue blocks for BLOCK_TIMEOUT
BLOCK_TIMEOUT = 1s
; Remove the boost workers after BOOST_TIMEOUT
BOOST_TIMEOUT = 5m
; During a boost add BOOST_WORKERS
BOOST_WORKERS = 5
[admin]
; Disallow regular (non-admin) users from creating organizations.
DISABLE_REGULAR_ORG_CREATION = false
; Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled
DEFAULT_EMAIL_NOTIFICATIONS = enabled
[security]
; Whether the installer is disabled
INSTALL_LOCK = false
; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
SECRET_KEY = !#@FDEWREWR&*(
; How long to remember that a user is logged in before requiring relogin (in days)
; How long to remember that an user is logged in before requiring relogin (in days)
LOGIN_REMEMBER_DAYS = 7
COOKIE_USERNAME = gitea_awesome
COOKIE_REMEMBER_NAME = gitea_incredible
@@ -480,16 +268,6 @@ MIN_PASSWORD_LENGTH = 6
IMPORT_LOCAL_PATHS = false
; Set to true to prevent all users (including admin) from creating custom git hooks
DISABLE_GIT_HOOKS = false
; Set to false to allow pushes to gitea repositories despite having an incomplete environment - NOT RECOMMENDED
ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET = true
;Comma separated list of character classes required to pass minimum complexity.
;If left empty or no valid values are specified, the default values ("lower,upper,digit,spec") will be used.
;Use "off" to disable checking.
PASSWORD_COMPLEXITY = lower,upper,digit,spec
; Password Hash algorithm, either "pbkdf2", "argon2", "scrypt" or "bcrypt"
PASSWORD_HASH_ALGO = pbkdf2
; Set false to allow JavaScript to read CSRF cookie
CSRF_COOKIE_HTTP_ONLY = true
[openid]
;
@@ -543,10 +321,6 @@ ALLOW_ONLY_EXTERNAL_REGISTRATION = false
REQUIRE_SIGNIN_VIEW = false
; Mail notification
ENABLE_NOTIFY_MAIL = false
; This setting enables gitea to be signed in with HTTP BASIC Authentication using the user's password
; If you set this to false you will not be able to access the tokens endpoints on the API with your password
; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token
ENABLE_BASIC_AUTHENTICATION = true
; More detail: https://github.com/gogits/gogs/issues/165
ENABLE_REVERSE_PROXY_AUTHENTICATION = false
ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
@@ -559,27 +333,15 @@ CAPTCHA_TYPE = image
; Go to https://www.google.com/recaptcha/admin to sign up for a key
RECAPTCHA_SECRET =
RECAPTCHA_SITEKEY =
; Change this to use recaptcha.net or other recaptcha service
RECAPTCHA_URL = https://www.google.com/recaptcha/
; Default value for KeepEmailPrivate
; Each new user will get the value of this setting copied into their profile
DEFAULT_KEEP_EMAIL_PRIVATE = false
; Default value for AllowCreateOrganization
; Every new user will have rights set to create organizations depending on this setting
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
; Either "public", "limited" or "private", default is "public"
; Limited is for signed user only
; Private is only for member of the organization
; Public is for everyone
DEFAULT_ORG_VISIBILITY = public
; Default value for DefaultOrgMemberVisible
; True will make the membership of the users visible when added to the organisation
DEFAULT_ORG_MEMBER_VISIBLE = false
; Default value for EnableDependencies
; Repositories will use dependencies by default depending on this setting
DEFAULT_ENABLE_DEPENDENCIES = true
; Dependencies can be added from any repository where the user is granted access or only from the current repository depending on this setting.
ALLOW_CROSS_REPOSITORY_DEPENDENCIES = true
; Enable heatmap on users profiles.
ENABLE_USER_HEATMAP = true
; Enable Timetracking
@@ -593,18 +355,7 @@ DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME = true
; Default value for the domain part of the user's email address in the git log
; if he has set KeepEmailPrivate to true. The user's email will be replaced with a
; concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS.
NO_REPLY_ADDRESS = noreply.%(DOMAIN)s
; Show Registration button
SHOW_REGISTRATION_BUTTON = true
; Show milestones dashboard page - a view of all the user's milestones
SHOW_MILESTONES_DASHBOARD_PAGE = true
; Default value for AutoWatchNewRepos
; When adding a repo to a team or creating a new repo all team members will watch the
; repo automatically if enabled
AUTO_WATCH_NEW_REPOS = true
; Default value for AutoWatchOnChanges
; Make the user watch a repository When they commit for the first time
AUTO_WATCH_ON_CHANGES = false
NO_REPLY_ADDRESS = noreply.example.org
[webhook]
; Hook task queue length, increase if webhook shooting starts hanging
@@ -615,17 +366,13 @@ DELIVER_TIMEOUT = 5
SKIP_TLS_VERIFY = false
; Number of history information in each page
PAGING_NUM = 10
; Proxy server URL, support http://, https//, socks://, blank will follow environment http_proxy/https_proxy
PROXY_URL =
; Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts.
PROXY_HOSTS =
[mailer]
ENABLED = false
; Buffer length of channel, keep it as it is if you don't know what it is.
SEND_BUFFER_LEN = 100
; Prefix displayed before subject in mail
SUBJECT_PREFIX =
; Name displayed in mail title
SUBJECT = %(APP_NAME)s
; Mail server
; Gmail: smtp.gmail.com:587
; QQ: smtp.qq.com:465
@@ -651,18 +398,14 @@ USER =
PASSWD =
; Send mails as plain text
SEND_AS_PLAIN_TEXT = false
; Set Mailer Type (either SMTP, sendmail or dummy to just send to the log)
MAILER_TYPE = smtp
; Enable sendmail (override SMTP)
USE_SENDMAIL = false
; Specify an alternative sendmail binary
SENDMAIL_PATH = sendmail
; Specify any extra sendmail arguments
SENDMAIL_ARGS =
; Timeout for Sendmail
SENDMAIL_TIMEOUT = 5m
[cache]
; if the cache enabled
ENABLED = true
; Either "memory", "redis", or "memcache", default is "memory"
ADAPTER = memory
; For "memory" only, GC interval in seconds, default is 60
@@ -675,16 +418,6 @@ HOST =
; Setting it to 0 disables caching
ITEM_TTL = 16h
; Last commit cache
[cache.last_commit]
; if the cache enabled
ENABLED = true
; Time to keep items in cache if not used, default is 8760 hours.
; Setting it to 0 disables caching
ITEM_TTL = 8760h
; Only enable the cache when repository's commits count great than
COMMITS_COUNT = 1000
[session]
; Either "memory", "file", or "redis", default is "memory"
PROVIDER = memory
@@ -707,18 +440,10 @@ SESSION_LIFE_TIME = 86400
[picture]
AVATAR_UPLOAD_PATH = data/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = data/repo-avatars
; How Gitea deals with missing repository avatars
; none = no avatar will be displayed; random = random avatar will be displayed; image = default image will be used
REPOSITORY_AVATAR_FALLBACK = none
REPOSITORY_AVATAR_FALLBACK_IMAGE = /img/repo_default.png
; Max Width and Height of uploaded avatars.
; This is to limit the amount of RAM used when resizing the image.
; Max Width and Height of uploaded avatars. This is to limit the amount of RAM
; used when resizing the image.
AVATAR_MAX_WIDTH = 4096
AVATAR_MAX_HEIGHT = 3072
; Maximum alloved file size for uploaded avatars.
; This is to limit the amount of RAM used when resizing the image.
AVATAR_MAX_FILE_SIZE = 1048576
; Chinese users can choose "duoshuo"
; or a custom avatar source, like: http://cn.gravatar.com/avatar/
GRAVATAR_SOURCE = gravatar
@@ -734,7 +459,7 @@ ENABLE_FEDERATED_AVATAR = false
ENABLED = true
; Path for attachments. Defaults to `data/attachments`
PATH = data/attachments
; One or more allowed types, e.g. "image/jpeg|image/png". Use "*/*" for all types.
; One or more allowed types, e.g. image/jpeg|image/png
ALLOWED_TYPES = image/jpeg|image/png|application/zip|application/gzip
; Max size of each file. Defaults to 4MB
MAX_SIZE = 4
@@ -746,9 +471,6 @@ MAX_FILES = 5
; Special supported values are ANSIC, UnixDate, RubyDate, RFC822, RFC822Z, RFC850, RFC1123, RFC1123Z, RFC3339, RFC3339Nano, Kitchen, Stamp, StampMilli, StampMicro and StampNano
; For more information about the format see http://golang.org/pkg/time/#pkg-constants
FORMAT =
; Location the UI time display i.e. Asia/Shanghai
; Empty means server's location setting
DEFAULT_UI_LOCATION =
[log]
ROOT_PATH =
@@ -757,37 +479,16 @@ ROOT_PATH =
MODE = console
; Buffer length of the channel, keep it as it is if you don't know what it is.
BUFFER_LEN = 10000
REDIRECT_MACARON_LOG = false
MACARON = file
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Info"
ROUTER_LOG_LEVEL = Info
ROUTER = console
ENABLE_ACCESS_LOG = false
ACCESS_LOG_TEMPLATE = {{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"
ACCESS = file
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
LEVEL = Info
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "None"
STACKTRACE_LEVEL = None
; Generic log modes
[log.x]
FLAGS = stdflags
EXPRESSION =
PREFIX =
COLORIZE = false
LEVEL = Trace
; For "console" mode only
[log.console]
LEVEL =
STDERR = false
; For "file" mode only
[log.file]
LEVEL =
; Set the file_name for the logger. If this is a relative path this
; will be relative to ROOT_PATH
FILE_NAME =
; This enables automated log rotate(switch of following options), default is true
LOG_ROTATE = true
; Max number of lines in a single file, default is 1000000
@@ -798,10 +499,6 @@ MAX_SIZE_SHIFT = 28
DAILY_ROTATE = true
; delete the log file after n days, default is 7
MAX_DAYS = 7
; compress logs with gzip
COMPRESS = true
; compression level see godoc for compress/gzip
COMPRESSION_LEVEL = -1
; For "conn" mode only
[log.conn]
@@ -829,6 +526,14 @@ PASSWD =
; Receivers, can be one or more, e.g. 1@example.com,2@example.com
RECEIVERS =
; For "database" mode only
[log.database]
LEVEL =
; Either "mysql" or "postgres"
DRIVER =
; Based on xorm, e.g.: root:root@localhost/gitea?charset=utf8
CONN =
[cron]
; Enable running cron tasks periodically.
ENABLED = true
@@ -873,14 +578,7 @@ SCHEDULE = @every 24h
; or only create new users if UPDATE_EXISTING is set to false
UPDATE_EXISTING = true
; Update migrated repositories' issues and comments' posterid, it will always attempt synchronization when the instance starts.
[cron.update_migration_poster_id]
; Interval as a duration between each synchronization. (default every 24h)
SCHEDULE = @every 24h
[git]
; The path of git executable. If empty, Gitea searches through the PATH environment.
PATH =
; Disables highlight of added and removed changes
DISABLE_DIFF_HIGHLIGHT = false
; Max number of lines allowed in a single file in diff view
@@ -892,14 +590,9 @@ MAX_GIT_DIFF_FILES = 100
; Arguments for command 'git gc', e.g. "--aggressive --auto"
; see more on http://git-scm.com/docs/git-gc/
GC_ARGS =
; If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1
ENABLE_AUTO_GIT_WIRE_PROTOCOL = true
; Respond to pushes to a non-default branch with a URL for creating a Pull Request (if the repository has them enabled)
PULL_REQUEST_PUSH_MESSAGE = true
; Operation timeout in seconds
[git.timeout]
DEFAULT = 360
MIGRATE = 600
MIRROR = 300
CLONE = 300
@@ -917,30 +610,10 @@ MIN_INTERVAL = 10m
ENABLE_SWAGGER = true
; Max number of items in a page
MAX_RESPONSE_ITEMS = 50
; Default paging number of api
DEFAULT_PAGING_NUM = 30
; Default and maximum number of items per page for git trees api
DEFAULT_GIT_TREES_PER_PAGE = 1000
; Default size of a blob returned by the blobs API (default is 10MiB)
DEFAULT_MAX_BLOB_SIZE = 10485760
[oauth2]
; Enables OAuth2 provider
ENABLE = true
; Lifetime of an OAuth2 access token in seconds
ACCESS_TOKEN_EXPIRATION_TIME=3600
; Lifetime of an OAuth2 access token in hours
REFRESH_TOKEN_EXPIRATION_TIME=730
; Check if refresh token got already used
INVALIDATE_REFRESH_TOKENS=false
; OAuth2 authentication secret for access and refresh tokens, change this to a unique string.
JWT_SECRET=Bk0yK7Y9g_p56v86KaHqjSbxvNvu3SbKoOdOt2ZcXvU
; Maximum length of oauth2 token/cookie stored on server
MAX_TOKEN_LENGTH=32767
[i18n]
LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR
NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,Українська,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어
LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR
NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,Українська,日本語,español,português do Brasil,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어
; Used for datetimepicker
[i18n.datelang]
@@ -957,7 +630,6 @@ uk-UA = uk
ja-JP = ja
es-ES = es
pt-BR = pt-BR
pt-PT = pt
pl-PL = pl
bg-BG = bg
it-IT = it
@@ -969,12 +641,11 @@ sv-SE = sv
ko-KR = ko
[U2F]
; NOTE: THE DEFAULT VALUES HERE WILL NEED TO BE CHANGED
; Two Factor authentication with security keys
; https://developers.yubico.com/U2F/App_ID.html
;APP_ID = http://localhost:3000/
; Comma seperated list of trusted facets
;TRUSTED_FACETS = http://localhost:3000/
APP_ID = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
; Comma seperated list of truisted facets
TRUSTED_FACETS = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
; Extension mapping to highlight class
; e.g. .toml=ini
@@ -987,14 +658,6 @@ SHOW_FOOTER_VERSION = true
; Show template execution time in the footer
SHOW_FOOTER_TEMPLATE_LOAD_TIME = true
[markup.sanitizer.1]
; The following keys can appear once to define a sanitation policy rule.
; This section can appear multiple times by adding a unique alphanumeric suffix to define multiple rules.
; e.g., [markup.sanitizer.1] -> [markup.sanitizer.2] -> [markup.sanitizer.TeX]
;ELEMENT = span
;ALLOW_ATTR = class
;REGEXP = ^(info|warning|error)$
[markup.asciidoc]
ENABLED = false
; List of file extensions that should be rendered by an external command
@@ -1009,18 +672,3 @@ IS_INPUT_FILE = false
ENABLED = false
; If you want to add authorization, specify a token here
TOKEN =
[task]
; Task queue type, could be `channel` or `redis`.
QUEUE_TYPE = channel
; Task queue length, available only when `QUEUE_TYPE` is `channel`.
QUEUE_LENGTH = 1000
; Task queue connection string, available only when `QUEUE_TYPE` is `redis`.
; If there is a password of redis, use `addrs=127.0.0.1:6379 password=123 db=0`.
QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0"
[migrations]
; Max attempts per http/https request on migrations.
MAX_ATTEMPTS = 3
; Backoff time per http/https request retry (seconds)
RETRY_BACKOFF = 3

3
docker/Makefile vendored
View File

@@ -4,6 +4,7 @@ DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
.PHONY: docker
docker:
docker build --disable-content-trust=false -t $(DOCKER_REF) .
@@ -11,4 +12,4 @@ docker:
.PHONY: docker-build
docker-build:
docker run -ti --rm -v $(CURDIR):/srv/app/src/code.gitea.io/gitea -w /srv/app/src/code.gitea.io/gitea -e TAGS="bindata $(TAGS)" LDFLAGS="$(LDFLAGS)" CGO_EXTRA_CFLAGS="$(CGO_EXTRA_CFLAGS)" webhippie/golang:edge make clean build
docker run -ti --rm -v $(CURDIR):/srv/app/src/code.gitea.io/gitea -w /srv/app/src/code.gitea.io/gitea -e TAGS="bindata $(TAGS)" webhippie/golang:edge make clean generate build

2
docker/etc/profile.d/gitea.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
export GITEA_CUSTOM=/data/gitea

46
docker/etc/s6/gitea/setup Executable file
View File

@@ -0,0 +1,46 @@
#!/bin/bash
if [ ! -d /data/git/.ssh ]; then
mkdir -p /data/git/.ssh
chmod 700 /data/git/.ssh
fi
if [ ! -f /data/git/.ssh/environment ]; then
echo "GITEA_CUSTOM=/data/gitea" >| /data/git/.ssh/environment
chmod 600 /data/git/.ssh/environment
fi
if [ ! -f /data/gitea/conf/app.ini ]; then
mkdir -p /data/gitea/conf
# Set INSTALL_LOCK to true only if SECRET_KEY is not empty and
# INSTALL_LOCK is empty
if [ -n "$SECRET_KEY" ] && [ -z "$INSTALL_LOCK" ]; then
INSTALL_LOCK=true
fi
# Substitude the environment variables in the template
APP_NAME=${APP_NAME:-"Gitea: Git with a cup of tea"} \
RUN_MODE=${RUN_MODE:-"dev"} \
SSH_DOMAIN=${SSH_DOMAIN:-"localhost"} \
HTTP_PORT=${HTTP_PORT:-"3000"} \
ROOT_URL=${ROOT_URL:-""} \
DISABLE_SSH=${DISABLE_SSH:-"false"} \
SSH_PORT=${SSH_PORT:-"22"} \
DB_TYPE=${DB_TYPE:-"sqlite3"} \
DB_HOST=${DB_HOST:-"localhost:3306"} \
DB_NAME=${DB_NAME:-"gitea"} \
DB_USER=${DB_USER:-"root"} \
DB_PASSWD=${DB_PASSWD:-""} \
INSTALL_LOCK=${INSTALL_LOCK:-"false"} \
DISABLE_REGISTRATION=${DISABLE_REGISTRATION:-"false"} \
REQUIRE_SIGNIN_VIEW=${REQUIRE_SIGNIN_VIEW:-"false"} \
SECRET_KEY=${SECRET_KEY:-""} \
envsubst < /etc/templates/app.ini > /data/gitea/conf/app.ini
fi
# only chown if current owner is not already the gitea ${USER}. No recursive check to save time
if ! [[ $(ls -ld /data/gitea | awk '{print $3}') = ${USER} ]]; then chown -R ${USER}:git /data/gitea; fi
if ! [[ $(ls -ld /app/gitea | awk '{print $3}') = ${USER} ]]; then chown -R ${USER}:git /app/gitea; fi
if ! [[ $(ls -ld /data/git | awk '{print $3}') = ${USER} ]]; then chown -R ${USER}:git /data/git; fi
chmod 0755 /data/gitea /app/gitea /data/git

2
docker/etc/s6/openssh/finish Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
exit 0

6
docker/etc/s6/openssh/run Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
[[ -f ./setup ]] && source ./setup
pushd /root > /dev/null
exec su-exec root /usr/sbin/sshd -D
popd

29
docker/etc/s6/openssh/setup Executable file
View File

@@ -0,0 +1,29 @@
#!/bin/bash
if [ ! -d /data/ssh ]; then
mkdir -p /data/ssh
fi
if [ ! -f /data/ssh/ssh_host_ed25519_key ]; then
echo "Generating /data/ssh/ssh_host_ed25519_key..."
ssh-keygen -t ed25519 -b 4096 -f /data/ssh/ssh_host_ed25519_key -N "" > /dev/null
fi
if [ ! -f /data/ssh/ssh_host_rsa_key ]; then
echo "Generating /data/ssh/ssh_host_rsa_key..."
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
fi
chown root:root /data/ssh/*
chmod 0700 /data/ssh
chmod 0600 /data/ssh/*

2
docker/etc/s6/syslogd/finish Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
exit 0

6
docker/etc/s6/syslogd/run Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
[[ -f ./setup ]] && source ./setup
pushd /root > /dev/null
exec su-exec root /sbin/syslogd -nS -O-
popd

1
docker/etc/s6/syslogd/setup Executable file
View File

@@ -0,0 +1 @@
#!/bin/bash

View File

@@ -1,4 +1,4 @@
Port ${SSH_LISTEN_PORT}
Port 22
Protocol 2
AddressFamily any
@@ -25,9 +25,9 @@ ChallengeResponseAuthentication no
PasswordAuthentication no
PermitEmptyPasswords no
AllowUsers ${USER}
AllowUsers git
Banner none
Subsystem sftp /usr/lib/ssh/sftp-server
AcceptEnv GIT_PROTOCOL
AcceptEnv GIT_PROTOCOL

View File

@@ -0,0 +1,51 @@
APP_NAME = $APP_NAME
RUN_MODE = $RUN_MODE
[repository]
ROOT = /data/git/repositories
[repository.local]
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
[repository.upload]
TEMP_PATH = /data/gitea/uploads
[server]
APP_DATA_PATH = /data/gitea
SSH_DOMAIN = $SSH_DOMAIN
HTTP_PORT = $HTTP_PORT
ROOT_URL = $ROOT_URL
DISABLE_SSH = $DISABLE_SSH
SSH_PORT = $SSH_PORT
LFS_CONTENT_PATH = /data/git/lfs
[database]
PATH = /data/gitea/gitea.db
DB_TYPE = $DB_TYPE
HOST = $DB_HOST
NAME = $DB_NAME
USER = $DB_USER
PASSWD = $DB_PASSWD
[indexer]
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
[session]
PROVIDER_CONFIG = /data/gitea/sessions
[picture]
AVATAR_UPLOAD_PATH = /data/gitea/avatars
[attachment]
PATH = /data/gitea/attachments
[log]
ROOT_PATH = /data/gitea/log
[security]
INSTALL_LOCK = $INSTALL_LOCK
SECRET_KEY = $SECRET_KEY
[service]
DISABLE_REGISTRATION = $DISABLE_REGISTRATION
REQUIRE_SIGNIN_VIEW = $REQUIRE_SIGNIN_VIEW

19
docker/manifest.tmpl vendored
View File

@@ -1,19 +0,0 @@
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}}
tags:
{{#each build.tags}}
- {{this}}
{{/each}}
{{/if}}
manifests:
-
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform:
architecture: amd64
os: linux
-
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform:
architecture: arm64
os: linux
variant: v8

View File

@@ -1,2 +0,0 @@
#!/bin/bash
s6-svscanctl -t /etc/s6/

View File

@@ -1,55 +0,0 @@
#!/bin/bash
if [ ! -d /data/git/.ssh ]; then
mkdir -p /data/git/.ssh
chmod 700 /data/git/.ssh
fi
if [ ! -f /data/git/.ssh/environment ]; then
echo "GITEA_CUSTOM=$GITEA_CUSTOM" >| /data/git/.ssh/environment
chmod 600 /data/git/.ssh/environment
elif ! grep -q "^GITEA_CUSTOM=$GITEA_CUSTOM$" /data/git/.ssh/environment; then
sed -i /^GITEA_CUSTOM=/d /data/git/.ssh/environment
echo "GITEA_CUSTOM=$GITEA_CUSTOM" >> /data/git/.ssh/environment
fi
if [ ! -f ${GITEA_CUSTOM}/conf/app.ini ]; then
mkdir -p ${GITEA_CUSTOM}/conf
# Set INSTALL_LOCK to true only if SECRET_KEY is not empty and
# INSTALL_LOCK is empty
if [ -n "$SECRET_KEY" ] && [ -z "$INSTALL_LOCK" ]; then
INSTALL_LOCK=true
fi
# Substitude the environment variables in the template
APP_NAME=${APP_NAME:-"Gitea: Git with a cup of tea"} \
RUN_MODE=${RUN_MODE:-"dev"} \
DOMAIN=${DOMAIN:-"localhost"} \
SSH_DOMAIN=${SSH_DOMAIN:-"localhost"} \
HTTP_PORT=${HTTP_PORT:-"3000"} \
ROOT_URL=${ROOT_URL:-""} \
DISABLE_SSH=${DISABLE_SSH:-"false"} \
SSH_PORT=${SSH_PORT:-"22"} \
SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-"${SSH_PORT}"} \
LFS_START_SERVER=${LFS_START_SERVER:-"false"} \
DB_TYPE=${DB_TYPE:-"sqlite3"} \
DB_HOST=${DB_HOST:-"localhost:3306"} \
DB_NAME=${DB_NAME:-"gitea"} \
DB_USER=${DB_USER:-"root"} \
DB_PASSWD=${DB_PASSWD:-""} \
INSTALL_LOCK=${INSTALL_LOCK:-"false"} \
DISABLE_REGISTRATION=${DISABLE_REGISTRATION:-"false"} \
REQUIRE_SIGNIN_VIEW=${REQUIRE_SIGNIN_VIEW:-"false"} \
SECRET_KEY=${SECRET_KEY:-""} \
envsubst < /etc/templates/app.ini > ${GITEA_CUSTOM}/conf/app.ini
chown ${USER}:git ${GITEA_CUSTOM}/conf/app.ini
fi
# only chown if current owner is not already the gitea ${USER}. No recursive check to save time
if ! [[ $(ls -ld /data/gitea | awk '{print $3}') = ${USER} ]]; then chown -R ${USER}:git /data/gitea; fi
if ! [[ $(ls -ld /app/gitea | awk '{print $3}') = ${USER} ]]; then chown -R ${USER}:git /app/gitea; fi
if ! [[ $(ls -ld /data/git | awk '{print $3}') = ${USER} ]]; then chown -R ${USER}:git /data/git; fi
chmod 0755 /data/gitea /app/gitea /data/git

View File

@@ -1,6 +0,0 @@
#!/bin/bash
[[ -f ./setup ]] && source ./setup
pushd /root > /dev/null
exec su-exec root /usr/sbin/sshd -D -e 2>&1
popd

View File

@@ -1,37 +0,0 @@
#!/bin/bash
if [ ! -d /data/ssh ]; then
mkdir -p /data/ssh
fi
if [ ! -f /data/ssh/ssh_host_ed25519_key ]; then
echo "Generating /data/ssh/ssh_host_ed25519_key..."
ssh-keygen -t ed25519 -f /data/ssh/ssh_host_ed25519_key -N "" > /dev/null
fi
if [ ! -f /data/ssh/ssh_host_rsa_key ]; then
echo "Generating /data/ssh/ssh_host_rsa_key..."
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
fi
if [ -d /etc/ssh ]; then
SSH_PORT=${SSH_PORT:-"22"} \
SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-"${SSH_PORT}"} \
envsubst < /etc/templates/sshd_config > /etc/ssh/sshd_config
chmod 0644 /etc/ssh/sshd_config
fi
chown root:root /data/ssh/*
chmod 0700 /data/ssh
chmod 0600 /data/ssh/*

View File

@@ -1,55 +0,0 @@
APP_NAME = $APP_NAME
RUN_MODE = $RUN_MODE
[repository]
ROOT = /data/git/repositories
[repository.local]
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
[repository.upload]
TEMP_PATH = /data/gitea/uploads
[server]
APP_DATA_PATH = /data/gitea
DOMAIN = $DOMAIN
SSH_DOMAIN = $SSH_DOMAIN
HTTP_PORT = $HTTP_PORT
ROOT_URL = $ROOT_URL
DISABLE_SSH = $DISABLE_SSH
SSH_PORT = $SSH_PORT
SSH_LISTEN_PORT = $SSH_LISTEN_PORT
LFS_START_SERVER = $LFS_START_SERVER
LFS_CONTENT_PATH = /data/git/lfs
[database]
PATH = /data/gitea/gitea.db
DB_TYPE = $DB_TYPE
HOST = $DB_HOST
NAME = $DB_NAME
USER = $DB_USER
PASSWD = $DB_PASSWD
[indexer]
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
[session]
PROVIDER_CONFIG = /data/gitea/sessions
[picture]
AVATAR_UPLOAD_PATH = /data/gitea/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars
[attachment]
PATH = /data/gitea/attachments
[log]
ROOT_PATH = /data/gitea/log
[security]
INSTALL_LOCK = $INSTALL_LOCK
SECRET_KEY = $SECRET_KEY
[service]
DISABLE_REGISTRATION = $DISABLE_REGISTRATION
REQUIRE_SIGNIN_VIEW = $REQUIRE_SIGNIN_VIEW

View File

@@ -3,14 +3,8 @@
if [ "${USER}" != "git" ]; then
# rename user
sed -i -e "s/^git\:/${USER}\:/g" /etc/passwd
fi
if [ -z "${USER_GID}" ]; then
USER_GID="`id -g ${USER}`"
fi
if [ -z "${USER_UID}" ]; then
USER_UID="`id -u ${USER}`"
# switch sshd config to different user
sed -i -e "s/AllowUsers git$/AllowUsers ${USER}/g" /etc/ssh/sshd_config
fi
## Change GID for USER?

1
docs/.gitignore vendored
View File

@@ -1,4 +1,3 @@
public/
templates/swagger/v1_json.tmpl
themes/
resources/

View File

@@ -1,16 +1,20 @@
# Gitea: Docs
[![Join the chat at https://img.shields.io/discord/322538954119184384.svg](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/Gitea)
[![Build Status](http://drone.gitea.io/api/badges/go-gitea/docs/status.svg)](http://drone.gitea.io/go-gitea/docs)
[![Join the chat at https://img.shields.io/discord/322538954119184384.svg](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/NsatcWJ)
[![](https://images.microbadger.com/badges/image/gitea/docs.svg)](http://microbadger.com/images/gitea/docs "Get your own image badge on microbadger.com")
## Hosting
These pages are hosted using [netlifycms](https://www.netlifycms.org/) and get
This page is hosted on our infrastructure within Docker containers, it gets
automatically updated on every push to the `master` branch.
If you want to host this page on your own you can take our docker image
[gitea/docs](https://hub.docker.com/r/gitea/docs/).
## Install
These pages use the [Hugo](https://gohugo.io/) static site generator.
This pages uses the [Hugo](https://github.com/spf13/hugo) static site generator.
If you are planning to contribute you'll want to download and install Hugo on
your local machine.

View File

@@ -1,7 +1,7 @@
# Gitea: 文档
[![Build Status](http://drone.gitea.io/api/badges/go-gitea/docs/status.svg)](http://drone.gitea.io/go-gitea/docs)
[![Join the chat at https://img.shields.io/discord/322538954119184384.svg](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/Gitea)
[![Join the chat at https://img.shields.io/discord/322538954119184384.svg](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/NsatcWJ)
[![](https://images.microbadger.com/badges/image/gitea/docs.svg)](http://microbadger.com/images/gitea/docs "Get your own image badge on microbadger.com")
## 关于托管方式

View File

@@ -1,174 +0,0 @@
/* global Fuse, Mark */
function ready(fn) {
if (document.readyState !== 'loading') {
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
ready(doSearch);
const summaryInclude = 60;
const fuseOptions = {
shouldSort: true,
includeMatches: true,
matchAllTokens: true,
threshold: 0.0, // for parsing diacritics
tokenize: true,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [{
name: 'title',
weight: 0.8
},
{
name: 'contents',
weight: 0.5
},
{
name: 'tags',
weight: 0.3
},
{
name: 'categories',
weight: 0.3
}
]
};
function param(name) {
return decodeURIComponent((window.location.search.split(`${name}=`)[1] || '').split('&')[0]).replace(/\+/g, ' ');
}
const searchQuery = param('s');
function doSearch() {
if (searchQuery) {
document.getElementById('search-query').value = searchQuery;
executeSearch(searchQuery);
} else {
const para = document.createElement('P');
para.innerText = 'Please enter a word or phrase above';
document.getElementById('search-results').appendChild(para);
}
}
function getJSON(url, fn) {
const request = new XMLHttpRequest();
request.open('GET', url, true);
request.onload = function () {
if (request.status >= 200 && request.status < 400) {
const data = JSON.parse(request.responseText);
fn(data);
} else {
console.error(`Target reached on ${url} with error ${request.status}`);
}
};
request.onerror = function () {
console.error(`Connection error ${request.status}`);
};
request.send();
}
function executeSearch(searchQuery) {
getJSON(`/${document.LANG}/index.json`, (data) => {
const pages = data;
const fuse = new Fuse(pages, fuseOptions);
const result = fuse.search(searchQuery);
document.getElementById('search-results').innerHTML = '';
if (result.length > 0) {
populateResults(result);
} else {
const para = document.createElement('P');
para.innerText = 'No matches found';
document.getElementById('search-results').appendChild(para);
}
});
}
function populateResults(result) {
result.forEach((value, key) => {
const content = value.item.contents;
let snippet = '';
const snippetHighlights = [];
if (fuseOptions.tokenize) {
snippetHighlights.push(searchQuery);
value.matches.forEach((mvalue) => {
if (mvalue.key === 'tags' || mvalue.key === 'categories') {
snippetHighlights.push(mvalue.value);
} else if (mvalue.key === 'contents') {
const ind = content.toLowerCase().indexOf(searchQuery.toLowerCase());
const start = ind - summaryInclude > 0 ? ind - summaryInclude : 0;
const end = ind + searchQuery.length + summaryInclude < content.length ? ind + searchQuery.length + summaryInclude : content.length;
snippet += content.substring(start, end);
if (ind > -1) {
snippetHighlights.push(content.substring(ind, ind + searchQuery.length));
} else {
snippetHighlights.push(mvalue.value.substring(mvalue.indices[0][0], mvalue.indices[0][1] - mvalue.indices[0][0] + 1));
}
}
});
}
if (snippet.length < 1) {
snippet += content.substring(0, summaryInclude * 2);
}
// pull template from hugo template definition
const templateDefinition = document.getElementById('search-result-template').innerHTML;
// replace values
const output = render(templateDefinition, {
key,
title: value.item.title,
link: value.item.permalink,
tags: value.item.tags,
categories: value.item.categories,
snippet
});
document.getElementById('search-results').appendChild(htmlToElement(output));
snippetHighlights.forEach((snipvalue) => {
new Mark(document.getElementById(`summary-${key}`)).mark(snipvalue);
});
});
}
function render(templateString, data) {
let conditionalMatches, copy;
const conditionalPattern = /\$\{\s*isset ([a-zA-Z]*) \s*\}(.*)\$\{\s*end\s*}/g;
// since loop below depends on re.lastInxdex, we use a copy to capture any manipulations whilst inside the loop
copy = templateString;
while ((conditionalMatches = conditionalPattern.exec(templateString)) !== null) {
if (data[conditionalMatches[1]]) {
// valid key, remove conditionals, leave content.
copy = copy.replace(conditionalMatches[0], conditionalMatches[2]);
} else {
// not valid, remove entire section
copy = copy.replace(conditionalMatches[0], '');
}
}
templateString = copy;
// now any conditionals removed we can do simple substitution
let key, find, re;
for (key of Object.keys(data)) {
find = `\\$\\{\\s*${key}\\s*\\}`;
re = new RegExp(find, 'g');
templateString = templateString.replace(re, data[key]);
}
return templateString;
}
/**
* By Mark Amery: https://stackoverflow.com/a/35385518
* @param {String} HTML representing a single element
* @return {Element}
*/
function htmlToElement(html) {
const template = document.createElement('template');
html = html.trim(); // Never return a text node of whitespace as the result
template.innerHTML = html;
return template.content.firstChild;
}

View File

@@ -6,7 +6,6 @@ theme: gitea
defaultContentLanguage: en-us
defaultContentLanguageInSubdir: true
enableMissingTranslationPlaceholders: true
enableEmoji: true
permalinks:
post: /:year/:month/:title/
@@ -18,16 +17,6 @@ params:
description: Git with a cup of tea
author: The Gitea Authors
website: https://docs.gitea.io
version: 1.11.5
minGoVersion: 1.12
goVersion: 1.14
minNodeVersion: 10.13
outputs:
home:
- HTML
- RSS
- JSON
menu:
page:
@@ -52,10 +41,6 @@ menu:
url: https://code.gitea.io/
weight: 40
pre: code
- name: Translation
url: https://crowdin.com/project/gitea
weight: 41
pre: language
- name: Downloads
url: https://dl.gitea.io/
weight: 50
@@ -65,7 +50,7 @@ menu:
weight: 60
pre: github
- name: Discord Chat
url: https://discord.gg/Gitea
url: https://discord.gg/NsatcWJ
weight: 70
pre: comment
- name: Forum
@@ -104,10 +89,6 @@ languages:
url: https://code.gitea.io/
weight: 40
pre: code
- name: 翻译
url: https://crowdin.com/project/gitea
weight: 41
pre: language
- name: 下载
url: https://dl.gitea.io/
weight: 50
@@ -117,7 +98,7 @@ languages:
weight: 60
pre: github
- name: Discord Chat
url: https://discord.gg/Gitea
url: https://discord.gg/NsatcWJ
weight: 70
pre: comment
- name: Forum
@@ -151,10 +132,6 @@ languages:
url: https://code.gitea.io/
weight: 40
pre: code
- name: 翻译
url: https://crowdin.com/project/gitea
weight: 41
pre: language
- name: 下载
url: https://dl.gitea.io/
weight: 50
@@ -164,7 +141,7 @@ languages:
weight: 60
pre: github
- name: Discord Chat
url: https://discord.gg/Gitea
url: https://discord.gg/NsatcWJ
weight: 70
pre: comment
- name: Forum
@@ -198,10 +175,6 @@ languages:
url: https://code.gitea.io/
weight: 40
pre: code
- name: Translation
url: https://crowdin.com/project/gitea
weight: 41
pre: language
- name: Downloads
url: https://dl.gitea.io/
weight: 50
@@ -211,7 +184,7 @@ languages:
weight: 60
pre: github
- name: Chat no Discord
url: https://discord.gg/Gitea
url: https://discord.gg/NsatcWJ
weight: 70
pre: comment
- name: Forum
@@ -245,10 +218,6 @@ languages:
url: https://code.gitea.io/
weight: 40
pre: code
- name: Translation
url: https://crowdin.com/project/gitea
weight: 41
pre: language
- name: Downloads
url: https://dl.gitea.io/
weight: 50
@@ -258,7 +227,7 @@ languages:
weight: 60
pre: github
- name: Discord Chat
url: https://discord.gg/Gitea
url: https://discord.gg/NsatcWJ
weight: 70
pre: comment
- name: Forum
@@ -292,10 +261,6 @@ languages:
url: https://code.gitea.io/
weight: 40
pre: code
- name: Translation
url: https://crowdin.com/project/gitea
weight: 41
pre: language
- name: Téléchargement
url: https://dl.gitea.io/
weight: 50
@@ -305,57 +270,10 @@ languages:
weight: 60
pre: github
- name: Discord Chat
url: https://discord.gg/Gitea
url: https://discord.gg/NsatcWJ
weight: 70
pre: comment
- name: Forum
url: https://discourse.gitea.io/
weight: 80
pre: group
pt-pt:
weight: 6
languageName: Português de Portugal
menu:
page:
- name: Página inicial
url: https://gitea.io/pt-pt/
weight: 10
pre: home
- name: Documentação
url: /pt-pt/
weight: 20
pre: question
post: active
- name: API
url: https://try.gitea.io/api/swagger
weight: 45
pre: plug
- name: Blog
url: https://blog.gitea.io/
weight: 30
pre: rss
- name: Código-fonte
url: https://code.gitea.io/
weight: 40
pre: code
- name: Tradução
url: https://crowdin.com/project/gitea
weight: 41
pre: language
- name: Descarregamentos
url: https://dl.gitea.io/
weight: 50
pre: download
- name: GitHub
url: https://github.com/go-gitea/
weight: 60
pre: github
- name: Discussão no Discord
url: https://discord.gg/Gitea
weight: 70
pre: comment
- name: Fórum
url: https://discourse.gitea.io/
weight: 80
pre: group

View File

@@ -1,38 +0,0 @@
---
date: "2019-12-28"
title: "Adding Legal Pages"
slug: adding-legal-pages
weight: 9
toc: false
draft: false
menu:
sidebar:
parent: "advanced"
name: "Adding Legal Pages"
identifier: "adding-legal-pages"
weight: 9
---
Some jurisdictions (such as EU), requires certain legal pages (e.g. Privacy Policy) to be added to website. Follow these steps to add them to your Gitea instance.
## Getting Pages
Gitea source code ships with sample pages, available in `contrib/legal` directory. Copy them to `custom/public/`. For example, to add Privacy Policy:
```
wget -O /path/to/custom/public/privacy.html https://raw.githubusercontent.com/go-gitea/gitea/master/contrib/legal/privacy.html.sample
```
Now you need to edit the page to meet your requirements. In particular you must change the email addresses, web addresses and references to "Your Gitea Instance" to match your situation.
You absolutely must not place a general ToS or privacy statement that implies that the gitea project is responsible for your server.
## Make it Visible
Create or append to `/path/to/custom/templates/custom/extra_links_footer.tmpl`:
```go
<a class="item" href="{{AppSubUrl}}/privacy.html">Privacy Policy</a>
```
Restart Gitea to see the changes.

View File

@@ -17,7 +17,7 @@ menu:
## Enabling/configuring API access
By default, `ENABLE_SWAGGER` is true, and
By default, `ENABLE_SWAGGER_ENDPOINT` is true, and
`MAX_RESPONSE_ITEMS` is set to 50. See [Config Cheat
Sheet](https://docs.gitea.io/en-us/config-cheat-sheet/) for more
information.
@@ -31,26 +31,18 @@ Gitea supports these methods of API authentication:
- `access_token=...` parameter in URL query string
- `Authorization: token ...` header in HTTP headers
All of these methods accept the same API key token type. You can
All of these methods accept the same apiKey token type. You can
better understand this by looking at the code -- as of this writing,
Gitea parses queries and headers to find the token in
[modules/auth/auth.go](https://github.com/go-gitea/gitea/blob/6efdcaed86565c91a3dc77631372a9cc45a58e89/modules/auth/auth.go#L47).
You can create an API key token via your Gitea installation's web interface:
You can create an apiKey token via your gitea install's web interface:
`Settings | Applications | Generate New Token`.
### OAuth2
Access tokens obtained from Gitea's [OAuth2 provider](https://docs.gitea.io/en-us/oauth2-provider) are accepted by these methods:
- `Authorization bearer ...` header in HTTP headers
- `token=...` parameter in URL query string
- `access_token=...` parameter in URL query string
### More on the `Authorization:` header
For historical reasons, Gitea needs the word `token` included before
the API key token in an authorization header, like this:
the apiKey token in an authorization header, like this:
```
Authorization: token 65eaa9c8ef52460d22a93307fe0aee76289dc675
@@ -68,14 +60,6 @@ curl -X POST "http://localhost:4000/api/v1/repos/test1/test1/issues" \
As mentioned above, the token used is the same one you would use in
the `token=` string in a GET request.
## API Guide:
API Reference guide is auto-generated by swagger and available on:
`https://gitea.your.host/api/swagger`
or on
[gitea demo instance](https://try.gitea.io/api/swagger)
## Listing your issued tokens via the API
As mentioned in
@@ -90,12 +74,6 @@ $ curl --request GET --url https://yourusername:yourpassword@gitea.your.host/api
[{"name":"test","sha1":"..."},{"name":"dev","sha1":"..."}]
```
As of v1.8.0 of Gitea, if using basic authentication with the API and your user has two factor authentication enabled, you'll need to send an additional header that contains the one time password (6 digit rotating token). An example of the header is `X-Gitea-OTP: 123456` where `123456` is where you'd place the code from your authenticator. Here is how the request would look like in curl:
```
$ curl -H "X-Gitea-OTP: 123456" --request GET --url https://yourusername:yourpassword@gitea.your.host/api/v1/users/yourusername/tokens
```
## Sudo
The API allows admin users to sudo API requests as another user. Simply add either a `sudo=` parameter or `Sudo:` request header with the username of the user to sudo.

View File

@@ -17,7 +17,7 @@ menu:
## 开启/配置 API 访问
通常情况下, `ENABLE_SWAGGER` 默认开启并且参数 `MAX_RESPONSE_ITEMS` 默认为 50。您可以从 [Config Cheat
通常情况下, `ENABLE_SWAGGER_ENDPOINT` 默认开启并且参数 `MAX_RESPONSE_ITEMS` 默认为 50。您可以从 [Config Cheat
Sheet](https://docs.gitea.io/en-us/config-cheat-sheet/) 中获取更多配置相关信息。
## 通过 API 认证

View File

@@ -1,37 +0,0 @@
---
date: "2019-08-27:00:00+02:00"
title: "CI/CD Usage"
slug: "ci-cd"
weight: 40
toc: true
draft: false
menu:
sidebar:
parent: "advanced"
name: "CI/CD Usage"
weight: 40
identifier: "ci-cd"
---
# Gitea and CI/CD
**NOTE:** These tools are not endorsed by Gitea. They are listed here for convenience only.
## Hey! This page may be out of date or even removed in the future! :scream:
Instead, check out [awesome-gitea](https://gitea.com/gitea/awesome-gitea/src/branch/master/README.md#user-content-devops)!
## Listing
CI/CD solutions that have integration with Gitea. Following list is not complete,
the purpose is to give a starting point to integrate a CI/CD process with your Gitea instance.
- [Drone](https://drone.io) with [Gitea documentation](https://docs.drone.io/installation/providers/gitea/)
- [Jenkins](https://jenkins.io/) with [Gitea plugin](https://plugins.jenkins.io/gitea)
- [Agola](https://agola.io)
- [Buildkite](https://buildkite.com) with [Gitea connector](https://github.com/techknowlogick/gitea-buildkite-connector)
- [AppVeyor](https://www.appveyor.com) with [built-in Gitea support](https://www.appveyor.com/blog/2019/09/05/gitea-receives-first-class-support-in-appveyor/)
- [Buildbot](https://www.buildbot.net/) with [Gitea plugin](https://github.com/lab132/buildbot-gitea)
Others CI/CD solutions that can partially be integrated with Gitea:
- [Concourse](https://www.concourse-ci.org), see more information at [Concourse community forum](https://discuss.concourse-ci.org/t/concourse-ci-and-gitea-oauth/1475)

View File

@@ -1,117 +0,0 @@
---
date: "2020-01-25T21:00:00-03:00"
title: "Embedded data extraction tool"
slug: "cmd-embedded"
weight: 40
toc: true
draft: false
menu:
sidebar:
parent: "advanced"
name: "Embedded data extraction tool"
weight: 40
identifier: "cmd-embedded"
---
# Embedded data extraction tool
Gitea's executable contains all the resources required to run: templates, images, style-sheets
and translations. Any of them can be overridden by placing a replacement in a matching path
inside the `custom` directory (see [Customizing Gitea]({{< relref "doc/advanced/customizing-gitea.en-us.md" >}})).
To obtain a copy of the embedded resources ready for editing, the `embedded` command from the CLI
can be used from the OS shell interface.
**NOTE:** The embedded data extraction tool is included in Gitea versions 1.12 and above.
## Listing resources
To list resources embedded in Gitea's executable, use the following syntax:
```
gitea embedded list [--include-vendored] [patterns...]
```
The `--include-vendored` flag makes the command include vendored files, which are
normally excluded; that is, files from external libraries that are required for Gitea
(e.g. [font-awesome](https://fontawesome.com/), [octicons](https://octicons.github.com/), etc).
A list of file search patterns can be provided. Gitea uses [gobwas/glob](https://github.com/gobwas/glob)
for its glob syntax. Here are some examples:
- List all template files, in any virtual directory: `**.tmpl`
- List all mail template files: `templates/mail/**.tmpl`
- List all files inside `public/img`: `public/img/**`
Don't forget to use quotes for the patterns, as spaces, `*` and other characters might have
a special meaning for your command shell.
If no pattern is provided, all files are listed.
#### Example
Listing all embedded files with `openid` in their path:
```
$ gitea embedded list '**openid**'
public/img/auth/openid_connect.svg
public/img/openid-16x16.png
templates/user/auth/finalize_openid.tmpl
templates/user/auth/signin_openid.tmpl
templates/user/auth/signup_openid_connect.tmpl
templates/user/auth/signup_openid_navbar.tmpl
templates/user/auth/signup_openid_register.tmpl
templates/user/settings/security_openid.tmpl
```
## Extracting resources
To extract resources embedded in Gitea's executable, use the following syntax:
```
gitea [--config {file}] embedded extract [--destination {dir}|--custom] [--overwrite|--rename] [--include-vendored] {patterns...}
```
The `--config` option tells gitea the location of the `app.ini` configuration file if
it's not in its default location. This option is only used with the `--custom` flag.
The `--destination` option tells gitea the directory where the files must be extracted to.
The default is the current directory.
The `--custom` flag tells gitea to extract the files directly into the `custom` directory.
For this to work, the command needs to know the location of the `app.ini` configuration
file (`--config`) and, depending of the configuration, be ran from the directory where
gitea normally starts. See [Customizing Gitea]({{< relref "doc/advanced/customizing-gitea.en-us.md" >}}) for details.
The `--overwrite` flag allows any existing files in the destination directory to be overwritten.
The `--rename` flag tells gitea to rename any existing files in the destination directory
as `filename.bak`. Previous `.bak` files are overwritten.
At least one file search pattern must be provided; see `list` subcomand above for pattern
syntax and examples.
#### Important notice
Make sure to **only extract those files that require customization**. Files that
are present in the `custom` directory are not upgraded by Gitea's upgrade process.
When Gitea is upgraded to a new version (by replacing the executable), many of the
embedded files will suffer changes. Gitea will honor and use any files found
in the `custom` directory, even if they are old and incompatible.
#### Example
Extracting mail templates to a temporary directory:
```
$ mkdir tempdir
$ gitea embedded extract --destination tempdir 'templates/mail/**.tmpl'
Extracting to tempdir:
tempdir/templates/mail/auth/activate.tmpl
tempdir/templates/mail/auth/activate_email.tmpl
tempdir/templates/mail/auth/register_notify.tmpl
tempdir/templates/mail/auth/reset_passwd.tmpl
tempdir/templates/mail/issue/assigned.tmpl
tempdir/templates/mail/issue/default.tmpl
tempdir/templates/mail/notify/collaborator.tmpl
```

View File

@@ -15,8 +15,8 @@ menu:
# Configuration Cheat Sheet
This is a cheat sheet for the Gitea configuration file. It contains most of the settings
that can be configured as well as their default values.
This is a cheat sheet for the Gitea configuration file. It contains most settings
that can configured as well as their default values.
Any changes to the Gitea configuration file should be made in `custom/conf/app.ini`
or any corresponding location. When installing from a distribution, this will
@@ -44,7 +44,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `ROOT`: **~/gitea-repositories/**: Root path for storing all repository data. It must be
an absolute path.
- `SCRIPT_TYPE`: **bash**: The script type this server supports. Usually this is `bash`,
- `SCRIPT_TYPE`: **bash**: The script type this server supports, usually this is `bash`,
but some users report that only `sh` is available.
- `ANSI_CHARSET`: **\<empty\>**: The default charset for an unrecognized charset.
- `FORCE_PRIVATE`: **false**: Force every new repository to be private.
@@ -62,79 +62,18 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
HTTP protocol.
- `USE_COMPAT_SSH_URI`: **false**: Force ssh:// clone url instead of scp-style uri when
default SSH port is used.
- `ACCESS_CONTROL_ALLOW_ORIGIN`: **\<empty\>**: Value for Access-Control-Allow-Origin header,
default is not to present. **WARNING**: This maybe harmful to you website if you do not
give it a right value.
- `DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH`: **false**: Close an issue if a commit on a non default branch marks it as closed.
- `ENABLE_PUSH_CREATE_USER`: **false**: Allow users to push local repositories to Gitea and have them automatically created for a user.
- `ENABLE_PUSH_CREATE_ORG`: **false**: Allow users to push local repositories to Gitea and have them automatically created for an org.
- `PREFIX_ARCHIVE_FILES`: **true**: Prefix archive files by placing them in a directory named after the repository.
- `DEFAULT_BRANCH`: **master**: Default branch name of all repositories.
### Repository - Pull Request (`repository.pull-request`)
- `WORK_IN_PROGRESS_PREFIXES`: **WIP:,\[WIP\]**: List of prefixes used in Pull Request
title to mark them as Work In Progress
- `CLOSE_KEYWORDS`: **close**, **closes**, **closed**, **fix**, **fixes**, **fixed**, **resolve**, **resolves**, **resolved**: List of
keywords used in Pull Request comments to automatically close a related issue
- `REOPEN_KEYWORDS`: **reopen**, **reopens**, **reopened**: List of keywords used in Pull Request comments to automatically reopen
a related issue
- `DEFAULT_MERGE_MESSAGE_COMMITS_LIMIT`: **50**: In the default merge message for squash commits include at most this many commits. Set to `-1` to include all commits
- `DEFAULT_MERGE_MESSAGE_SIZE`: **5120**: In the default merge message for squash commits limit the size of the commit messages. Set to `-1` to have no limit.
- `DEFAULT_MERGE_MESSAGE_ALL_AUTHORS`: **false**: In the default merge message for squash commits walk all commits to include all authors in the Co-authored-by otherwise just use those in the limited list
- `DEFAULT_MERGE_MESSAGE_MAX_APPROVERS`: **10**: In default merge messages limit the number of approvers listed as `Reviewed-by:`. Set to `-1` to include all.
- `DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY`: **true**: In default merge messages only include approvers who are officially allowed to review.
### Repository - Issue (`repository.issue`)
- `LOCK_REASONS`: **Too heated,Off-topic,Resolved,Spam**: A list of reasons why a Pull Request or Issue can be locked
### Repository - Signing (`repository.signing`)
- `SIGNING_KEY`: **default**: \[none, KEYID, default \]: Key to sign with.
- `SIGNING_NAME` &amp; `SIGNING_EMAIL`: if a KEYID is provided as the `SIGNING_KEY`, use these as the Name and Email address of the signer. These should match publicized name and email address for the key.
- `INITIAL_COMMIT`: **always**: \[never, pubkey, twofa, always\]: Sign initial commit.
- `never`: Never sign
- `pubkey`: Only sign if the user has a public key
- `twofa`: Only sign if the user is logged in with twofa
- `always`: Always sign
- Options other than `never` and `always` can be combined as a comma separated list.
- `WIKI`: **never**: \[never, pubkey, twofa, always, parentsigned\]: Sign commits to wiki.
- `CRUD_ACTIONS`: **pubkey, twofa, parentsigned**: \[never, pubkey, twofa, parentsigned, always\]: Sign CRUD actions.
- Options as above, with the addition of:
- `parentsigned`: Only sign if the parent commit is signed.
- `MERGES`: **pubkey, twofa, basesigned, commitssigned**: \[never, pubkey, twofa, approved, basesigned, commitssigned, always\]: Sign merges.
- `approved`: Only sign approved merges to a protected branch.
- `basesigned`: Only sign if the parent commit in the base repo is signed.
- `headsigned`: Only sign if the head commit in the head branch is signed.
- `commitssigned`: Only sign if all the commits in the head branch to the merge point are signed.
## CORS (`cors`)
- `ENABLED`: **false**: enable cors headers (disabled by default)
- `SCHEME`: **http**: scheme of allowed requests
- `ALLOW_DOMAIN`: **\***: list of requesting domains that are allowed
- `ALLOW_SUBDOMAIN`: **false**: allow subdomains of headers listed above to request
- `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: list of methods allowed to request
- `MAX_AGE`: **10m**: max time to cache response
- `ALLOW_CREDENTIALS`: **false**: allow request with credentials
## UI (`ui`)
- `EXPLORE_PAGING_NUM`: **20**: Number of repositories that are shown in one explore page.
- `ISSUE_PAGING_NUM`: **10**: Number of issues that are shown in one page (for all pages that list issues).
- `MEMBERS_PAGING_NUM`: **20**: Number of members that are shown in organization members.
- `FEED_MAX_COMMIT_NUM`: **5**: Number of maximum commits shown in one activity feed.
- `GRAPH_MAX_COMMIT_NUM`: **100**: Number of maximum commits shown in the commit graph.
- `DEFAULT_THEME`: **gitea**: \[gitea, arc-green\]: Set the default theme for the Gitea install.
- `THEMES`: **gitea,arc-green**: All available themes. Allow users select personalized themes
regardless of the value of `DEFAULT_THEME`.
- `REACTIONS`: All available reactions users can choose on issues/prs and comments
Values can be emoji alias (:smile:) or a unicode emoji.
For custom reactions, add a tightly cropped square image to public/emoji/img/reaction_name.png
- `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
- `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page.
- `USE_SERVICE_WORKER`: **true**: Whether to enable a Service Worker to cache frontend assets.
### UI - Admin (`ui.admin`)
@@ -143,43 +82,21 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `NOTICE_PAGING_NUM`: **25**: Number of notices that are shown in one page.
- `ORG_PAGING_NUM`: **50**: Number of organizations that are shown in one page.
### UI - Notification (`ui.notification`)
- `MIN_TIMEOUT`: **10s**: These options control how often notification endpoint is polled to update the notification count. On page load the notification count will be checked after `MIN_TIMEOUT`. The timeout will increase to `MAX_TIMEOUT` by `TIMEOUT_STEP` if the notification count is unchanged. Set MIN_TIMEOUT to 0 to turn off.
- `MAX_TIMEOUT`: **60s**.
- `TIMEOUT_STEP`: **10s**.
- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource` and `SharedWorker`, a `SharedWorker` will be used in preference to polling notification endpoint. Set to **-1** to disable the `EventSource`.
## Markdown (`markdown`)
- `ENABLE_HARD_LINE_BREAK_IN_COMMENTS`: **true**: Render soft line breaks as hard line breaks in comments, which
means a single newline character between paragraphs will cause a line break and adding
trailing whitespace to paragraphs is not necessary to force a line break.
- `ENABLE_HARD_LINE_BREAK_IN_DOCUMENTS`: **false**: Render soft line breaks as hard line breaks in documents, which
means a single newline character between paragraphs will cause a line break and adding
trailing whitespace to paragraphs is not necessary to force a line break.
- `CUSTOM_URL_SCHEMES`: Use a comma separated list (ftp,git,svn) to indicate additional
URL hyperlinks to be rendered in Markdown. URLs beginning in http and https are
always displayed
- `ENABLE_HARD_LINE_BREAK`: **false**: Enable Markdown's hard line break extension.
## Server (`server`)
- `PROTOCOL`: **http**: \[http, https, fcgi, unix, fcgi+unix\]
- `PROTOCOL`: **http**: \[http, https, fcgi, unix\]
- `DOMAIN`: **localhost**: Domain name of this server.
- `ROOT_URL`: **%(PROTOCOL)s://%(DOMAIN)s:%(HTTP\_PORT)s/**:
Overwrite the automatically generated public URL.
This is useful if the internal and the external URL don't match (e.g. in Docker).
- `STATIC_URL_PREFIX`: **\<empty\>**:
Overwrite this option to request static resources from a different URL.
This includes CSS files, images, JS files and web fonts.
Avatar images are dynamic resources and still served by gitea.
The option can be just a different path, as in `/static`, or another domain, as in `https://cdn.example.com`.
Requests are then made as `%(ROOT_URL)s/static/css/index.css` and `https://cdn.example.com/css/index.css` respective.
The static files are located in the `public/` directory of the gitea source repository.
- `HTTP_ADDR`: **0.0.0.0**: HTTP listen address.
- If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket
defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings.
- If `PROTOCOL` is set to `unix` or `fcgi+unix`, this should be the name of the Unix socket file to use.
- If `PROTOCOL` is set to `unix`, this should be the name of the Unix socket file to use.
- `HTTP_PORT`: **3000**: HTTP listen port.
- If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket
defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings.
@@ -193,22 +110,18 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `START_SSH_SERVER`: **false**: When enabled, use the built-in SSH server.
- `SSH_DOMAIN`: **%(DOMAIN)s**: Domain name of this server, used for displayed clone URL.
- `SSH_PORT`: **22**: SSH port displayed in clone URL.
- `SSH_LISTEN_HOST`: **0.0.0.0**: Listen address for the built-in SSH server.
- `SSH_LISTEN_PORT`: **%(SSH\_PORT)s**: Port for the built-in SSH server.
- `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures.
- `DISABLE_ROUTER_LOG`: **false**: Mute printing of the router log.
- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. From 1.11 paths are relative to `CUSTOM_PATH`.
- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. From 1.11 paths are relative to `CUSTOM_PATH`.
- `CERT_FILE`: **custom/https/cert.pem**: Cert file path used for HTTPS.
- `KEY_FILE`: **custom/https/key.pem**: Key file path used for HTTPS.
- `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path.
- `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars.
- `ENABLE_GZIP`: **false**: Enables application-level GZIP support.
- `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login\].
- `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore\].
- `LFS_START_SERVER`: **false**: Enables git-lfs support.
- `LFS_CONTENT_PATH`: **./data/lfs**: Where to store LFS files.
- `LFS_JWT_SECRET`: **\<empty\>**: LFS authentication secret, change this a unique string.
- `LFS_HTTP_AUTH_EXPIRY`: **20m**: LFS authentication validity period in time.Duration, pushes taking longer than this may fail.
- `LFS_MAX_FILE_SIZE`: **0**: Maximum allowed LFS file size in bytes (Set to 0 for no limit).
- `LFS_LOCK_PAGING_NUM`: **50**: Maximum number of LFS Locks returned per page.
- `REDIRECT_OTHER_PORT`: **false**: If true and `PROTOCOL` is https, allows redirecting http requests on `PORT_TO_REDIRECT` to the https port Gitea listens on.
- `PORT_TO_REDIRECT`: **80**: Port for the http redirection service to listen on. Used when `REDIRECT_OTHER_PORT` is true.
- `ENABLE_LETSENCRYPT`: **false**: If enabled you must set `DOMAIN` to valid internet facing domain (ensure DNS is set and port 80 is accessible by letsencrypt validation server).
@@ -216,89 +129,25 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `LETSENCRYPT_ACCEPTTOS`: **false**: This is an explicit check that you accept the terms of service for Let's Encrypt.
- `LETSENCRYPT_DIRECTORY`: **https**: Directory that Letsencrypt will use to cache information such as certs and private keys.
- `LETSENCRYPT_EMAIL`: **email@example.com**: Email used by Letsencrypt to notify about problems with issued certificates. (No default)
- `ALLOW_GRACEFUL_RESTARTS`: **true**: Perform a graceful restart on SIGHUP
- `GRACEFUL_HAMMER_TIME`: **60s**: After a restart the parent process will stop accepting new connections and will allow requests to finish before stopping. Shutdown will be forced if it takes longer than this time.
- `STARTUP_TIMEOUT`: **0**: Shutsdown the server if startup takes longer than the provided time. On Windows setting this sends a waithint to the SVC host to tell the SVC host startup may take some time. Please note startup is determined by the opening of the listeners - HTTP/HTTPS/SSH. Indexers may take longer to startup and can have their own timeouts.
## Database (`database`)
- `DB_TYPE`: **mysql**: The database type in use \[mysql, postgres, mssql, sqlite3\].
- `HOST`: **127.0.0.1:3306**: Database host address and port or absolute path for unix socket \[mysql, postgres\] (ex: /var/run/mysqld/mysqld.sock).
- `HOST`: **127.0.0.1:3306**: Database host address and port.
- `NAME`: **gitea**: Database name.
- `USER`: **root**: Database username.
- `PASSWD`: **\<empty\>**: Database user password. Use \`your password\` for quoting if you use special characters in the password.
- `SCHEMA`: **\<empty\>**: For PostgreSQL only, schema to use if different from "public". The schema must exist beforehand,
the user must have creation privileges on it, and the user search path must be set to the look into the schema first
(e.g. `ALTER USER user SET SEARCH_PATH = schema_name,"$user",public;`).
- `SSL_MODE`: **disable**: SSL/TLS encryption mode for connecting to the database. This option is only applied for PostgreSQL and MySQL.
- Valid values for MySQL:
- `true`: Enable TLS with verification of the database server certificate against its root certificate. When selecting this option make sure that the root certificate required to validate the database server certificate (e.g. the CA certificate) is on the system certificate store of both the database and Gitea servers. See your system documentation for instructions on how to add a CA certificate to the certificate store.
- `false`: Disable TLS.
- `disable`: Alias for `false`, for compatibility with PostgreSQL.
- `skip-verify`: Enable TLS without database server certificate verification. Use this option if you have self-signed or invalid certificate on the database server.
- `prefer`: Enable TLS with fallback to non-TLS connection.
- Valid values for PostgreSQL:
- `disable`: Disable TLS.
- `require`: Enable TLS without any verifications.
- `verify-ca`: Enable TLS with verification of the database server certificate against its root certificate.
- `verify-full`: Enable TLS and verify the database server name matches the given certificate in either the `Common Name` or `Subject Alternative Name` fields.
- `CHARSET`: **utf8**: For MySQL only, either "utf8" or "utf8mb4", default is "utf8". NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this.
- `SSL_MODE`: **disable**: For PostgreSQL and MySQL only.
- `PATH`: **data/gitea.db**: For SQLite3 only, the database file path.
- `LOG_SQL`: **true**: Log the executed SQL.
- `DB_RETRIES`: **10**: How many ORM init / DB connect attempts allowed.
- `DB_RETRY_BACKOFF`: **3s**: time.Duration to wait before trying another ORM init / DB connect attempt, if failure occured.
- `MAX_OPEN_CONNS` **0**: Database maximum open connections - default is 0, meaning there is no limit.
- `MAX_IDLE_CONNS` **2**: Max idle database connections on connnection pool, default is 2 - this will be capped to `MAX_OPEN_CONNS`.
- `CONN_MAX_LIFETIME` **0 or 3s**: Sets the maximum amount of time a DB connection may be reused - default is 0, meaning there is no limit (except on MySQL where it is 3s - see #6804 & #7071).
Please see #8540 & #8273 for further discussion of the appropriate values for `MAX_OPEN_CONNS`, `MAX_IDLE_CONNS` & `CONN_MAX_LIFETIME` and their
relation to port exhaustion.
## Indexer (`indexer`)
- `ISSUE_INDEXER_TYPE`: **bleve**: Issue indexer type, currently supported: `bleve`, `db` or `elasticsearch`.
- `ISSUE_INDEXER_CONN_STR`: ****: Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch. i.e. http://elastic:changeme@localhost:9200
- `ISSUE_INDEXER_NAME`: **gitea_issues**: Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch
- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search; available when ISSUE_INDEXER_TYPE is bleve and elasticsearch.
- The next 4 configuration values are deprecated and should be set in `queue.issue_indexer` however are kept for backwards compatibility:
- `ISSUE_INDEXER_QUEUE_TYPE`: **levelqueue**: Issue indexer queue, currently supports:`channel`, `levelqueue`, `redis`.
- `ISSUE_INDEXER_QUEUE_DIR`: **indexers/issues.queue**: When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this will be the queue will be saved path.
- `ISSUE_INDEXER_QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string.
- `ISSUE_INDEXER_QUEUE_BATCH_NUMBER`: **20**: Batch queue number.
- `REPO_INDEXER_ENABLED`: **false**: Enables code search (uses a lot of disk space, about 6 times more than the repository size).
- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search.
- `REPO_INDEXER_ENABLED`: **false**: Enables code search (uses a lot of disk space).
- `REPO_INDEXER_PATH`: **indexers/repos.bleve**: Index file used for code search.
- `REPO_INDEXER_INCLUDE`: **empty**: A comma separated list of glob patterns (see https://github.com/gobwas/glob) to **include** in the index. Use `**.txt` to match any files with .txt extension. An empty list means include all files.
- `REPO_INDEXER_EXCLUDE`: **empty**: A comma separated list of glob patterns (see https://github.com/gobwas/glob) to **exclude** from the index. Files that match this list will not be indexed, even if they match in `REPO_INDEXER_INCLUDE`.
- `REPO_INDEXER_EXCLUDE_VENDORED`: **true**: Exclude vendored files from index.
- `UPDATE_BUFFER_LEN`: **20**: Buffer length of index request.
- `MAX_FILE_SIZE`: **1048576**: Maximum size in bytes of files to be indexed.
- `STARTUP_TIMEOUT`: **30s**: If the indexer takes longer than this timeout to start - fail. (This timeout will be added to the hammer time above for child processes - as bleve will not start until the previous parent is shutdown.) Set to zero to never timeout.
## Queue (`queue` and `queue.*`)
- `TYPE`: **persistable-channel**: General queue type, currently support: `persistable-channel`, `channel`, `level`, `redis`, `dummy`
- `DATADIR`: **queues/**: Base DataDir for storing persistent and level queues. `DATADIR` for inidividual queues can be set in `queue.name` sections but will default to `DATADIR/`**`name`**.
- `LENGTH`: **20**: Maximal queue size before channel queues block
- `BATCH_LENGTH`: **20**: Batch data before passing to the handler
- `CONN_STR`: **addrs=127.0.0.1:6379 db=0**: Connection string for the redis queue type.
- `QUEUE_NAME`: **_queue**: The suffix for default redis queue name. Individual queues will default to **`name`**`QUEUE_NAME` but can be overriden in the specific `queue.name` section.
- `SET_NAME`: **_unique**: The suffix that will added to the default redis
set name for unique queues. Individual queues will default to
**`name`**`QUEUE_NAME`_`SET_NAME`_ but can be overridden in the specific
`queue.name` section.
- `WRAP_IF_NECESSARY`: **true**: Will wrap queues with a timeoutable queue if the selected queue is not ready to be created - (Only relevant for the level queue.)
- `MAX_ATTEMPTS`: **10**: Maximum number of attempts to create the wrapped queue
- `TIMEOUT`: **GRACEFUL_HAMMER_TIME + 30s**: Timeout the creation of the wrapped queue if it takes longer than this to create.
- Queues by default come with a dynamically scaling worker pool. The following settings configure this:
- `WORKERS`: **1**: Number of initial workers for the queue.
- `MAX_WORKERS`: **10**: Maximum number of worker go-routines for the queue.
- `BLOCK_TIMEOUT`: **1s**: If the queue blocks for this time, boost the number of workers - the `BLOCK_TIMEOUT` will then be doubled before boosting again whilst the boost is ongoing.
- `BOOST_TIMEOUT`: **5m**: Boost workers will timeout after this long.
- `BOOST_WORKERS`: **5**: This many workers will be added to the worker pool if there is a boost.
## Admin (`admin`)
- `DEFAULT_EMAIL_NOTIFICATIONS`: **enabled**: Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled
## Security (`security`)
@@ -314,18 +163,7 @@ set name for unique queues. Individual queues will default to
authentication provided email.
- `DISABLE_GIT_HOOKS`: **false**: Set to `true` to prevent all users (including admin) from creating custom
git hooks.
- `ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET`: **true**: Set to `false` to allow local users to push to gitea-repositories without setting up the Gitea environment. This is not recommended and if you want local users to push to gitea repositories you should set the environment appropriately.
- `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server.
- `INTERNAL_TOKEN`: **\<random at every install if no uri set\>**: Secret used to validate communication within Gitea binary.
- `INTERNAL_TOKEN_URI`: **<empty>**: Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: `file:/etc/gitea/internal_token`)
- `PASSWORD_HASH_ALGO`: **pbkdf2**: The hash algorithm to use \[pbkdf2, argon2, scrypt, bcrypt\].
- `CSRF_COOKIE_HTTP_ONLY`: **true**: Set false to allow JavaScript to read CSRF cookie.
- `PASSWORD_COMPLEXITY`: **lower,upper,digit,spec**: Comma separated list of character classes required to pass minimum complexity. If left empty or no valid values are specified, the default values will be used. Possible values are:
- lower - use one or more lower latin characters
- upper - use one or more upper latin characters
- digit - use one or more digits
- spec - use one or more special characters as ``!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~``
- off - do not check password complexity
## OpenID (`openid`)
@@ -345,42 +183,22 @@ set name for unique queues. Individual queues will default to
Requires `Mailer` to be enabled.
- `DISABLE_REGISTRATION`: **false**: Disable registration, after which only admin can create
accounts for users.
- `REQUIRE_EXTERNAL_REGISTRATION_PASSWORD`: **false**: Enable this to force externally created
accounts (via GitHub, OpenID Connect, etc) to create a password. Warning: enabling this will
decrease security, so you should only enable it if you know what you're doing.
- `REQUIRE_SIGNIN_VIEW`: **false**: Enable this to force users to log in to view any page or to use API.
- `REQUIRE_SIGNIN_VIEW`: **false**: Enable this to force users to log in to view any page.
- `ENABLE_NOTIFY_MAIL`: **false**: Enable this to send e-mail to watchers of a repository when
something happens, like creating issues. Requires `Mailer` to be enabled.
- `ENABLE_BASIC_AUTHENTICATION`: **true**: Disable this to disallow authenticaton using HTTP
BASIC and the user's password. Please note if you disable this you will not be able to access the
tokens API endpoints using a password. Further, this only disables BASIC authentication using the
password - not tokens or OAuth Basic.
- `ENABLE_REVERSE_PROXY_AUTHENTICATION`: **false**: Enable this to allow reverse proxy authentication.
- `ENABLE_REVERSE_PROXY_AUTO_REGISTRATION`: **false**: Enable this to allow auto-registration
for reverse authentication.
- `ENABLE_REVERSE_PROXY_EMAIL`: **false**: Enable this to allow to auto-registration with a
provided email rather than a generated email.
- `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration.
- `REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA`: **false**: Enable this to force captcha validation
even for External Accounts (i.e. GitHub, OpenID Connect, etc). You must `ENABLE_CAPTCHA` also.
- `CAPTCHA_TYPE`: **image**: \[image, recaptcha\]
- `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha.
- `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha.
- `RECAPTCHA_URL`: **https://www.google.com/recaptcha/**: Set the recaptcha url - allows the use of recaptcha net.
- `DEFAULT_ENABLE_DEPENDENCIES`: **true**: Enable this to have dependencies enabled by default.
- `ALLOW_CROSS_REPOSITORY_DEPENDENCIES` : **true** Enable this to allow dependencies on issues from any repository where the user is granted access.
- `ENABLE_USER_HEATMAP`: **true**: Enable this to display the heatmap on users profiles.
- `DEFAULT_ENABLE_DEPENDENCIES`: **true** Enable this to have dependencies enabled by default.
- `ENABLE_USER_HEATMAP`: **true** Enable this to display the heatmap on users profiles.
- `EMAIL_DOMAIN_WHITELIST`: **\<empty\>**: If non-empty, list of domain names that can only be used to register
on this instance.
- `SHOW_REGISTRATION_BUTTON`: **! DISABLE\_REGISTRATION**: Show Registration Button
- `SHOW_MILESTONES_DASHBOARD_PAGE`: **true** Enable this to show the milestones dashboard page - a view of all the user's milestones
- `AUTO_WATCH_NEW_REPOS`: **true**: Enable this to let all organisation users watch new repos when they are created
- `AUTO_WATCH_ON_CHANGES`: **false**: Enable this to make users watch a repository after their first commit to it
- `DEFAULT_ORG_VISIBILITY`: **public**: Set default visibility mode for organisations, either "public", "limited" or "private".
- `DEFAULT_ORG_MEMBER_VISIBLE`: **false** True will make the membership of the users visible when added to the organisation.
- `ALLOW_ONLY_EXTERNAL_REGISTRATION`: **false** Set to true to force registration only using third-party services.
- `NO_REPLY_ADDRESS`: **DOMAIN** Default value for the domain part of the user's email address in the git log if he has set KeepEmailPrivate to true.
The user's email will be replaced with a concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS.
## Webhook (`webhook`)
@@ -388,8 +206,6 @@ set name for unique queues. Individual queues will default to
- `DELIVER_TIMEOUT`: **5**: Delivery timeout (sec) for shooting webhooks.
- `SKIP_TLS_VERIFY`: **false**: Allow insecure certification.
- `PAGING_NUM`: **10**: Number of webhook history events that are shown in one page.
- `PROXY_URL`: ****: Proxy server URL, support http://, https//, socks://, blank will follow environment http_proxy/https_proxy
- `PROXY_HOSTS`: ****: Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts.
## Mailer (`mailer`)
@@ -403,39 +219,25 @@ set name for unique queues. Individual queues will default to
- `PASSWD`: **\<empty\>**: Password of mailing user. Use \`your password\` for quoting if you use special characters in the password.
- `SKIP_VERIFY`: **\<empty\>**: Do not verify the self-signed certificates.
- **Note:** Gitea only supports SMTP with STARTTLS.
- `SUBJECT_PREFIX`: **\<empty\>**: Prefix to be placed before e-mail subject lines.
- `MAILER_TYPE`: **smtp**: \[smtp, sendmail, dummy\]
- **smtp** Use SMTP to send mail
- **sendmail** Use the operating system's `sendmail` command instead of SMTP.
- `USE_SENDMAIL`: **false** Use the operating system's `sendmail` command instead of SMTP.
This is common on linux systems.
- **dummy** Send email messages to the log as a testing phase.
- Note that enabling sendmail will ignore all other `mailer` settings except `ENABLED`,
`FROM`, `SUBJECT_PREFIX` and `SENDMAIL_PATH`.
- Enabling dummy will ignore all settings except `ENABLED`, `SUBJECT_PREFIX` and `FROM`.
`FROM` and `SENDMAIL_PATH`.
- `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be
command or full path).
- `SENDMAIL_TIMEOUT`: **5m**: default timeout for sending email through sendmail
- ``IS_TLS_ENABLED`` : **false** : Decide if SMTP connections should use TLS.
## Cache (`cache`)
- `ENABLED`: **true**: Enable the cache.
- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, or `memcache`.
- `INTERVAL`: **60**: Garbage Collection interval (sec), for memory cache only.
- `HOST`: **\<empty\>**: Connection string for `redis` and `memcache`.
- Redis: `network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180`
- Memcache: `127.0.0.1:9090;127.0.0.1:9091`
- `ITEM_TTL`: **16h**: Time to keep items in cache if not used, Setting it to 0 disables caching.
## Cache - LastCommitCache settings (`cache.last_commit`)
- `ENABLED`: **true**: Enable the cache.
- `ITEM_TTL`: **8760h**: Time to keep items in cache if not used, Setting it to 0 disables caching.
- `COMMITS_COUNT`: **1000**: Only enable the cache when repository's commits count great than.
- Memache: `127.0.0.1:9090;127.0.0.1:9091`
## Session (`session`)
- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, mysql, couchbase, memcache, nodb, postgres\].
- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, mysql\].
- `PROVIDER_CONFIG`: **data/sessions**: For file, the root path; for others, the connection string.
- `COOKIE_SECURE`: **false**: Enable this to force using HTTPS for all session access.
- `COOKIE_NAME`: **i\_like\_gitea**: The name of the cookie used for the session ID.
@@ -448,16 +250,7 @@ set name for unique queues. Individual queues will default to
- `DISABLE_GRAVATAR`: **false**: Enable this to use local avatars only.
- `ENABLE_FEDERATED_AVATAR`: **false**: Enable support for federated avatars (see
[http://www.libravatar.org](http://www.libravatar.org)).
- `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store user avatar image files.
- `REPOSITORY_AVATAR_UPLOAD_PATH`: **data/repo-avatars**: Path to store repository avatar image files.
- `REPOSITORY_AVATAR_FALLBACK`: **none**: How Gitea deals with missing repository avatars
- none = no avatar will be displayed
- random = random avatar will be generated
- image = default image will be used (which is set in `REPOSITORY_AVATAR_DEFAULT_IMAGE`)
- `REPOSITORY_AVATAR_FALLBACK_IMAGE`: **/img/repo_default.png**: Image used as default repository avatar (if `REPOSITORY_AVATAR_FALLBACK` is set to image and none was uploaded)
- `AVATAR_MAX_WIDTH`: **4096**: Maximum avatar image width in pixels.
- `AVATAR_MAX_HEIGHT`: **3072**: Maximum avatar image height in pixels.
- `AVATAR_MAX_FILE_SIZE`: **1048576** (1Mb): Maximum avatar image file size in bytes.
- `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store local and cached files.
## Attachment (`attachment`)
@@ -471,64 +264,8 @@ set name for unique queues. Individual queues will default to
## Log (`log`)
- `ROOT_PATH`: **\<empty\>**: Root path for log files.
- `MODE`: **console**: Logging mode. For multiple modes, use a comma to separate values. You can configure each mode in per mode log subsections `\[log.modename\]`. By default the file mode will log to `$ROOT_PATH/gitea.log`.
- `LEVEL`: **Info**: General log level. \[Trace, Debug, Info, Warn, Error, Critical, Fatal, None\]
- `STACKTRACE_LEVEL`: **None**: Default log level at which to log create stack traces. \[Trace, Debug, Info, Warn, Error, Critical, Fatal, None\]
- `REDIRECT_MACARON_LOG`: **false**: Redirects the Macaron log to its own logger or the default logger.
- `MACARON`: **file**: Logging mode for the macaron logger, use a comma to separate values. Configure each mode in per mode log subsections `\[log.modename.macaron\]`. By default the file mode will log to `$ROOT_PATH/macaron.log`. (If you set this to `,` it will log to default gitea logger.)
- `ROUTER_LOG_LEVEL`: **Info**: The log level that the router should log at. (If you are setting the access log, its recommended to place this at Debug.)
- `ROUTER`: **console**: The mode or name of the log the router should log to. (If you set this to `,` it will log to default gitea logger.)
NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` for this option to take effect. Configure each mode in per mode log subsections `\[log.modename.router\]`.
- `ENABLE_ACCESS_LOG`: **false**: Creates an access.log in NCSA common log format, or as per the following template
- `ACCESS`: **file**: Logging mode for the access logger, use a comma to separate values. Configure each mode in per mode log subsections `\[log.modename.access\]`. By default the file mode will log to `$ROOT_PATH/access.log`. (If you set this to `,` it will log to the default gitea logger.)
- `ACCESS_LOG_TEMPLATE`: **`{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`**: Sets the template used to create the access log.
- The following variables are available:
- `Ctx`: the `macaron.Context` of the request.
- `Identity`: the SignedUserName or `"-"` if not logged in.
- `Start`: the start time of the request.
- `ResponseWriter`: the responseWriter from the request.
- You must be very careful to ensure that this template does not throw errors or panics as this template runs outside of the panic/recovery script.
- `ENABLE_XORM_LOG`: **true**: Set whether to perform XORM logging. Please note SQL statement logging can be disabled by setting `LOG_SQL` to false in the `[database]` section.
### Log subsections (`log.name`, `log.name.*`)
- `LEVEL`: **log.LEVEL**: Sets the log-level of this sublogger. Defaults to the `LEVEL` set in the global `[log]` section.
- `STACKTRACE_LEVEL`: **log.STACKTRACE_LEVEL**: Sets the log level at which to log stack traces.
- `MODE`: **name**: Sets the mode of this sublogger - Defaults to the provided subsection name. This allows you to have two different file loggers at different levels.
- `EXPRESSION`: **""**: A regular expression to match either the function name, file or message. Defaults to empty. Only log messages that match the expression will be saved in the logger.
- `FLAGS`: **stdflags**: A comma separated string representing the log flags. Defaults to `stdflags` which represents the prefix: `2009/01/23 01:23:23 ...a/b/c/d.go:23:runtime.Caller() [I]: message`. `none` means don't prefix log lines. See `modules/log/base.go` for more information.
- `PREFIX`: **""**: An additional prefix for every log line in this logger. Defaults to empty.
- `COLORIZE`: **false**: Colorize the log lines by default
### Console log mode (`log.console`, `log.console.*`, or `MODE=console`)
- For the console logger `COLORIZE` will default to `true` if not on windows or the terminal is determined to be able to color.
- `STDERR`: **false**: Use Stderr instead of Stdout.
### File log mode (`log.file`, `log.file.*` or `MODE=file`)
- `FILE_NAME`: Set the file name for this logger. Defaults as described above. If relative will be relative to the `ROOT_PATH`
- `LOG_ROTATE`: **true**: Rotate the log files.
- `MAX_SIZE_SHIFT`: **28**: Maximum size shift of a single file, 28 represents 256Mb.
- `DAILY_ROTATE`: **true**: Rotate logs daily.
- `MAX_DAYS`: **7**: Delete the log file after n days
- `COMPRESS`: **true**: Compress old log files by default with gzip
- `COMPRESSION_LEVEL`: **-1**: Compression level
### Conn log mode (`log.conn`, `log.conn.*` or `MODE=conn`)
- `RECONNECT_ON_MSG`: **false**: Reconnect host for every single message.
- `RECONNECT`: **false**: Try to reconnect when connection is lost.
- `PROTOCOL`: **tcp**: Set the protocol, either "tcp", "unix" or "udp".
- `ADDR`: **:7020**: Sets the address to connect to.
### SMTP log mode (`log.smtp`, `log.smtp.*` or `MODE=smtp`)
- `USER`: User email address to send from.
- `PASSWD`: Password for the smtp server.
- `HOST`: **127.0.0.1:25**: The SMTP host to connect to.
- `RECEIVERS`: Email addresses to send to.
- `SUBJECT`: **Diagnostic message from Gitea**
- `MODE`: **console**: Logging mode. For multiple modes, use a comma to separate values.
- `LEVEL`: **Trace**: General log level. \[Trace, Debug, Info, Warn, Error, Critical\]
## Cron (`cron`)
@@ -548,7 +285,7 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false`
### Cron - Repository Health Check (`cron.repo_health_check`)
- `SCHEDULE`: **@every 24h**: Cron syntax for scheduling repository health check.
- `SCHEDULE`: **every 24h**: Cron syntax for scheduling repository health check.
- `TIMEOUT`: **60s**: Time duration syntax for health check execution timeout.
- `ARGS`: **\<empty\>**: Arguments for command `git fsck`, e.g. `--unreachable --tags`. See more on http://git-scm.com/docs/git-fsck
@@ -557,24 +294,14 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false`
- `RUN_AT_START`: **true**: Run repository statistics check at start time.
- `SCHEDULE`: **@every 24h**: Cron syntax for scheduling repository statistics check.
### Cron - Update Migration Poster ID (`cron.update_migration_poster_id`)
- `SCHEDULE`: **@every 24h** : Interval as a duration between each synchronization, it will always attempt synchronization when the instance starts.
## Git (`git`)
- `PATH`: **""**: The path of git executable. If empty, Gitea searches through the PATH environment.
- `MAX_GIT_DIFF_LINES`: **100**: Max number of lines allowed of a single file in diff view.
- `MAX_GIT_DIFF_LINE_CHARACTERS`: **5000**: Max character count per line highlighted in diff view.
- `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view.
- `GC_ARGS`: **\<empty\>**: Arguments for command `git gc`, e.g. `--aggressive --auto`. See more on http://git-scm.com/docs/git-gc/
- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1
- `PULL_REQUEST_PUSH_MESSAGE`: **true**: Respond to pushes to a non-default branch with a URL for creating a Pull Request (if the repository has them enabled)
- `VERBOSE_PUSH`: **true**: Print status information about pushes as they are being processed.
- `VERBOSE_PUSH_DELAY`: **5s**: Only print verbose information if push takes longer than this delay.
## Git - Timeout settings (`git.timeout`)
- `DEFAUlT`: **360**: Git operations default timeout seconds.
- `MIGRATE`: **600**: Migrate external repositories timeout seconds.
- `MIRROR`: **300**: Mirror external repositories timeout seconds.
- `CLONE`: **300**: Git clone from internal repositories timeout seconds.
@@ -583,30 +310,18 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false`
## Metrics (`metrics`)
- `ENABLED`: **false**: Enables /metrics endpoint for prometheus.
- `ENABLED`: **false**: Enables /metrics endpoint for prometheus.
- `TOKEN`: **\<empty\>**: You need to specify the token, if you want to include in the authorization the metrics . The same token need to be used in prometheus parameters `bearer_token` or `bearer_token_file`.
## API (`api`)
- `ENABLE_SWAGGER`: **true**: Enables /api/swagger, /api/v1/swagger etc. endpoints. True or false; default is true.
- `ENABLE_SWAGGER_ENDPOINT`: **true**: Enables /api/swagger, /api/v1/swagger etc. endpoints. True or false; default is true.
- `MAX_RESPONSE_ITEMS`: **50**: Max number of items in a page.
- `DEFAULT_PAGING_NUM`: **30**: Default paging number of API.
- `DEFAULT_GIT_TREES_PER_PAGE`: **1000**: Default and maximum number of items per page for git trees API.
- `DEFAULT_MAX_BLOB_SIZE`: **10485760**: Default max size of a blob that can be return by the blobs API.
## OAuth2 (`oauth2`)
- `ENABLE`: **true**: Enables OAuth2 provider.
- `ACCESS_TOKEN_EXPIRATION_TIME`: **3600**: Lifetime of an OAuth2 access token in seconds
- `REFRESH_TOKEN_EXPIRATION_TIME`: **730**: Lifetime of an OAuth2 access token in hours
- `INVALIDATE_REFRESH_TOKEN`: **false**: Check if refresh token got already used
- `JWT_SECRET`: **\<empty\>**: OAuth2 authentication secret for access and refresh tokens, change this a unique string.
- `MAX_TOKEN_LENGTH`: **32767**: Maximum length of token/cookie to accept from OAuth2 provider
## i18n (`i18n`)
- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR**: List of locales shown in language selector
- `NAMES`: **English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어**: Visible names corresponding to the locales
- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR**: List of locales shown in language selector
- `NAMES`: **English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어**: Visible names corresponding to the locales
### i18n - Datepicker Language (`i18n.datelang`)
Maps locales to the languages used by the datepicker plugin
@@ -623,7 +338,6 @@ Maps locales to the languages used by the datepicker plugin
- `ja-JP`: **ja**
- `es-ES`: **es**
- `pt-BR`: **pt-BR**
- `pt-PT`: **pt**
- `pl-PL`: **pl**
- `bg-BG`: **bg**
- `it-IT`: **it**
@@ -644,13 +358,13 @@ Gitea can support Markup using external tools. The example below will add a mark
```ini
[markup.asciidoc]
ENABLED = true
ENABLED = false
FILE_EXTENSIONS = .adoc,.asciidoc
RENDER_COMMAND = "asciidoc --out-file=- -"
IS_INPUT_FILE = false
```
- ENABLED: **false** Enable markup support; set to **true** to enable this renderer.
- ENABLED: **false** Enable markup support.
- FILE\_EXTENSIONS: **\<empty\>** List of file extensions that should be rendered by an external
command. Multiple extentions needs a comma as splitter.
- RENDER\_COMMAND: External command to render all matching extensions.
@@ -660,42 +374,6 @@ Two special environment variables are passed to the render command:
- `GITEA_PREFIX_SRC`, which contains the current URL prefix in the `src` path tree. To be used as prefix for links.
- `GITEA_PREFIX_RAW`, which contains the current URL prefix in the `raw` path tree. To be used as prefix for image paths.
Gitea supports customizing the sanitization policy for rendered HTML. The example below will support KaTeX output from pandoc.
```ini
[markup.sanitizer.TeX]
; Pandoc renders TeX segments as <span>s with the "math" class, optionally
; with "inline" or "display" classes depending on context.
ELEMENT = span
ALLOW_ATTR = class
REGEXP = ^\s*((math(\s+|$)|inline(\s+|$)|display(\s+|$)))+
```
- `ELEMENT`: The element this policy applies to. Must be non-empty.
- `ALLOW_ATTR`: The attribute this policy allows. Must be non-empty.
- `REGEXP`: A regex to match the contents of the attribute against. Must be present but may be empty for unconditional whitelisting of this attribute.
Multiple sanitisation rules can be defined by adding unique subsections, e.g. `[markup.sanitizer.TeX-2]`.
## Time (`time`)
- `FORMAT`: Time format to diplay on UI. i.e. RFC1123 or 2006-01-02 15:04:05
- `DEFAULT_UI_LOCATION`: Default location of time on the UI, so that we can display correct user's time on UI. i.e. Shanghai/Asia
## Task (`task`)
Task queue configuration has been moved to `queue.task`. However, the below configuration values are kept for backwards compatibility:
- `QUEUE_TYPE`: **channel**: Task queue type, could be `channel` or `redis`.
- `QUEUE_LENGTH`: **1000**: Task queue length, available only when `QUEUE_TYPE` is `channel`.
- `QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: Task queue connection string, available only when `QUEUE_TYPE` is `redis`. If redis needs a password, use `addrs=127.0.0.1:6379 password=123 db=0`.
## Migrations (`migrations`)
- `MAX_ATTEMPTS`: **3**: Max attempts per http/https request on migrations.
- `RETRY_BACKOFF`: **3**: Backoff time per http/https request retry (seconds)
## Other (`other`)
- `SHOW_FOOTER_BRANDING`: **false**: Show Gitea branding in the footer.

View File

@@ -37,8 +37,7 @@ menu:
- `EXPLORE_PAGING_NUM`: 探索页面每页显示的仓库数量。
- `ISSUE_PAGING_NUM`: 工单页面每页显示的工单数量。
- `MEMBERS_PAGING_NUM`: **20**: 组织成员页面每页显示的成员数量
- `FEED_MAX_COMMIT_NUM`: 活动流页面显示的最大提交数量。
- `FEED_MAX_COMMIT_NUM`: 活动流页面显示的最大提交树木
### UI - Admin (`ui.admin`)
@@ -66,7 +65,6 @@ menu:
- `CERT_FILE`: 启用HTTPS的证书文件。
- `KEY_FILE`: 启用HTTPS的密钥文件。
- `STATIC_ROOT_PATH`: 存放模板和静态文件的根目录,默认是 Gitea 的根目录。
- `STATIC_CACHE_TIME`: **6h**: 静态资源文件,包括 `custom/`, `public/` 和所有上传的头像的浏览器缓存时间。
- `ENABLE_GZIP`: 启用应用级别的 GZIP 压缩。
- `LANDING_PAGE`: 未登录用户的默认页面,可选 `home``explore`
- `LFS_START_SERVER`: 是否启用 git-lfs 支持. 可以为 `true``false` 默认是 `false`
@@ -80,28 +78,9 @@ menu:
- `NAME`: 数据库名称。
- `USER`: 数据库用户名。
- `PASSWD`: 数据库用户密码。
- `SSL_MODE`: MySQL 或 PostgreSQL数据库是否启用SSL模式。
- `CHARSET`: **utf8**: 仅当数据库为 MySQL 时有效, 可以为 "utf8" 或 "utf8mb4"。注意:如果使用 "utf8mb4",你的 MySQL InnoDB 版本必须在 5.6 以上。
- `SSL_MODE`: PostgreSQL数据库是否启用SSL模式。
- `PATH`: Tidb 或者 SQLite3 数据文件存放路径。
- `LOG_SQL`: **true**: 显示生成的SQL默认为真。
- `MAX_IDLE_CONNS` **0**: 最大空闲数据库连接
- `CONN_MAX_LIFETIME` **3s**: 数据库连接最大存活时间
## Indexer (`indexer`)
- `ISSUE_INDEXER_TYPE`: **bleve**: 工单索引类型,当前支持 `bleve`, `db``elasticsearch`,当为 `db` 时其它工单索引项可不用设置。
- `ISSUE_INDEXER_CONN_STR`: ****: 工单索引连接字符串,仅当 ISSUE_INDEXER_TYPE 为 `elasticsearch` 时有效。例如: http://elastic:changeme@localhost:9200
- `ISSUE_INDEXER_NAME`: **gitea_issues**: 工单索引名称,仅当 ISSUE_INDEXER_TYPE 为 `elasticsearch` 时有效。
- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: 工单索引文件存放路径,当索引类型为 `bleve` 时有效。
- `ISSUE_INDEXER_QUEUE_TYPE`: **levelqueue**: 工单索引队列类型,当前支持 `channel` `levelqueue``redis`
- `ISSUE_INDEXER_QUEUE_DIR`: **indexers/issues.queue**: 当 `ISSUE_INDEXER_QUEUE_TYPE``levelqueue` 时,保存索引队列的磁盘路径。
- `ISSUE_INDEXER_QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: 当 `ISSUE_INDEXER_QUEUE_TYPE``redis`保存Redis队列的连接字符串。
- `ISSUE_INDEXER_QUEUE_BATCH_NUMBER`: **20**: 队列处理中批量提交数量。
- `REPO_INDEXER_ENABLED`: **false**: 是否启用代码搜索(启用后会占用比较大的磁盘空间)。
- `REPO_INDEXER_PATH`: **indexers/repos.bleve**: 用于代码搜索的索引文件路径。
- `UPDATE_BUFFER_LEN`: **20**: 代码索引请求的缓冲区长度。
- `MAX_FILE_SIZE`: **1048576**: 进行解析的源代码文件的最大长度,小于该值时才会索引。
## Security (`security`)
@@ -114,7 +93,7 @@ menu:
## Service (`service`)
- `ACTIVE_CODE_LIVE_MINUTES`: 登验证码失效时间,单位分钟。
- `ACTIVE_CODE_LIVE_MINUTES`: 登验证码失效时间,单位分钟。
- `RESET_PASSWD_CODE_LIVE_MINUTES`: 重置密码失效时间,单位分钟。
- `REGISTER_EMAIL_CONFIRM`: 启用注册邮件激活,前提是 `Mailer` 已经启用。
- `DISABLE_REGISTRATION`: 禁用注册,启用后只能用管理员添加用户。
@@ -132,8 +111,6 @@ menu:
- `DELIVER_TIMEOUT`: 请求webhooks的超时时间单位秒。
- `SKIP_TLS_VERIFY`: 是否允许不安全的证书。
- `PAGING_NUM`: 每页显示的Webhook 历史数量。
- `PROXY_URL`: ****: 代理服务器网址,支持 http://, https//, socks://, 为空将使用环境变量中的 http_proxy/https_proxy 设置。
- `PROXY_HOSTS`: ****: 逗号分隔的需要代理的域名或IP地址。支持 * 号匹配符,使用 ** 匹配所有域名和IP地址。
## Mailer (`mailer`)
@@ -150,19 +127,11 @@ menu:
## Cache (`cache`)
- `ENABLED`: **true**: 是否启用
- `ADAPTER`: **memory**: 缓存引擎,可以为 `memory`, `redis``memcache`
- `INTERVAL`: **60**: 只对内存缓存有效GC间隔单位秒
- `HOST`: **\<empty\>**: 针对redis和memcache有效主机地址和端口。
- `ADAPTER`: 缓存引擎,可以为 `memory`, `redis``memcache`
- `INTERVAL`: 只对内存缓存有效GC间隔单位秒
- `HOST`: 针对redis和memcache有效主机地址和端口
- Redis: `network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180`
- Memache: `127.0.0.1:9090;127.0.0.1:9091`
- `ITEM_TTL`: **16h**: 缓存项目失效时间,设置为 0 则禁用缓存。
## Cache - LastCommitCache settings (`cache.last_commit`)
- `ENABLED`: **true**: 是否启用。
- `ITEM_TTL`: **8760h**: 缓存项目失效时间,设置为 0 则禁用缓存。
- `COMMITS_COUNT`: **1000**: 仅当仓库的提交数大于时才启用缓存。
## Session (`session`)
@@ -185,20 +154,6 @@ menu:
- `MAX_SIZE`: 附件最大限制,单位 MB比如 `4`
- `MAX_FILES`: 一次最多上传的附件数量,比如: `5`
关于 `ALLOWED_TYPES` 在 (*)unix 系统中可以使用`file -I <filename>` 来快速获得对应的 `MIME type`
```shell
$ file -I test00.tar.xz
test00.tar.xz: application/x-xz; charset=binary
$ file --mime test00.xlsx
test00.xlsx: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=binary
file -I test01.xls
test01.xls: application/vnd.ms-excel; charset=binary
```
## Log (`log`)
- `ROOT_PATH`: 日志文件根目录。
@@ -223,11 +178,7 @@ test01.xls: application/vnd.ms-excel; charset=binary
### Cron - Repository Statistics Check (`cron.check_repo_stats`)
- `RUN_AT_START`: 是否启动时自动运行仓库统计。
- `SCHEDULE`: 仓库统计时的Cron 语法,比如:`@every 24h`.
### Cron - Update Migration Poster ID (`cron.update_migration_poster_id`)
- `SCHEDULE`: **@every 24h** : 每次同步的间隔时间。此任务总是在启动时自动进行。
- `SCHEDULE`: 藏亏统计时的Cron 语法,比如:`@every 24h`.
## Git (`git`)
@@ -237,24 +188,13 @@ test01.xls: application/vnd.ms-excel; charset=binary
- `GC_ARGS`: 执行 `git gc` 命令的参数, 比如: `--aggressive --auto`
## Git - 超时设置 (`git.timeout`)
- `DEFAUlT`: **360**: Git操作默认超时时间单位秒
- `MIGRATE`: **600**: 迁移外部仓库时的超时时间,单位秒
- `MIRROR`: **300**: 镜像外部仓库的超时时间,单位秒
- `CLONE`: **300**: 内部仓库间克隆的超时时间,单位秒
- `PULL`: **300**: 内部仓库间拉取的超时时间,单位秒
- `GC`: **60**: git仓库GC的超时时间单位秒
- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: 是否根据 Git Wire Protocol协议支持情况自动切换版本当 git 版本在 2.18 及以上时会自动切换到版本2。为 `false` 则不切换。
## API (`api`)
- `ENABLE_SWAGGER`: **true**: 是否启用swagger路由 /api/swagger, /api/v1/swagger etc. endpoints. True 或 false; 默认是 true.
- `MAX_RESPONSE_ITEMS`: **50**: 一个页面最大的项目数。
- `DEFAULT_PAGING_NUM`: **30**: API中默认分页条数。
- `DEFAULT_GIT_TREES_PER_PAGE`: **1000**: GIT TREES API每页的默认最大项数.
- `DEFAULT_MAX_BLOB_SIZE`: **10485760**: BLOBS API默认最大大小.
## Markup (`markup`)
## markup (`markup`)
外部渲染工具支持,你可以用你熟悉的文档渲染工具. 比如一下将新增一个名字为 `asciidoc` 的渲染工具which is followed `markup.` ini section. And there are some config items below.
@@ -271,21 +211,7 @@ IS_INPUT_FILE = false
- RENDER_COMMAND: 工具的命令行命令及参数。
- IS_INPUT_FILE: 输入方式是最后一个参数为文件路径还是从标准输入读取。
## Time (`time`)
- `FORMAT`: 显示在界面上的时间格式。比如: RFC1123 或者 2006-01-02 15:04:05
- `DEFAULT_UI_LOCATION`: 默认显示在界面上的时区,默认为本地时区。比如: Asia/Shanghai
## Task (`task`)
- `QUEUE_TYPE`: **channel**: 任务队列类型,可以为 `channel``redis`
- `QUEUE_LENGTH`: **1000**: 任务队列长度,当 `QUEUE_TYPE``channel` 时有效。
- `QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: 任务队列连接字符串,当 `QUEUE_TYPE``redis` 时有效。如果redis有密码则可以 `addrs=127.0.0.1:6379 password=123 db=0`
## Migrations (`migrations`)
- `MAX_ATTEMPTS`: **3**: 在迁移过程中的 http/https 请求重试次数。
- `RETRY_BACKOFF`: **3**: 等待下一次重试的时间,单位秒。
## Other (`other`)

View File

@@ -9,35 +9,25 @@ menu:
sidebar:
parent: "advanced"
name: "Customizing Gitea"
identifier: "customizing-gitea"
weight: 9
identifier: "customizing-gitea"
---
# Customizing Gitea
Customizing Gitea is typically done using the `CustomPath` folder - by default this is
the `custom` folder from the running directory, but may be different if your build has
set this differently. This is the central place to override configuration settings,
templates, etc. You can check the `CustomPath` using `gitea help`. You can also find
the path on the _Configuration_ tab in the _Site Administration_ page. You can override
the `CustomPath` by setting either the `GITEA_CUSTOM` environment variable or by
using the `--custom-path` option on the `gitea` binary. (The option will override the
environment variable.)
Customizing Gitea is typically done using the `custom` folder. This is the central
place to override configuration settings, templates, etc.
If Gitea is deployed from binary, all default paths will be relative to the Gitea
If Gitea is deployed from binary, all default paths will be relative to the gitea
binary. If installed from a distribution, these paths will likely be modified to
the Linux Filesystem Standard. Gitea will attempt to create required folders, including
`custom/`. Distributions may provide a symlink for `custom` using `/etc/gitea/`.
Application settings can be found in file `CustomConf` which is by default,
`CustomPath/conf/app.ini` but may be different if your build has set this differently.
Again `gitea help` will allow you review this variable and you can override it using the
`--config` option on the `gitea` binary.
the Linux Filesystem Standard. Gitea will create required folders, including `custom/`.
Application settings are configured in `custom/conf/app.ini`. Distributions may
provide a symlink for `custom` using `/etc/gitea/`.
- [Quick Cheat Sheet](https://docs.gitea.io/en-us/config-cheat-sheet/)
- [Complete List](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.ini.sample)
If the `CustomPath` folder can't be found despite checking `gitea help`, check the `GITEA_CUSTOM`
If the `custom` folder can't be found next to the binary, check the `GITEA_CUSTOM`
environment variable; this can be used to override the default path to something else.
`GITEA_CUSTOM` might, for example, be set by an init script.
@@ -45,6 +35,11 @@ environment variable; this can be used to override the default path to something
**Note:** Gitea must perform a full restart to see configuration changes.
## Customizing /robots.txt
To make Gitea serve a custom `/robots.txt` (default: empty 404), create a file called
`robots.txt` in the `custom` folder with [expected contents](http://www.robotstxt.org/).
## Serving custom public files
To make Gitea serve custom public files (like pages and images), use the folder
@@ -55,43 +50,28 @@ the url `http://gitea.domain.tld/image.png`.
## Changing the default avatar
Place the png image at the following path: `custom/public/img/avatar_default.png`
Place the png image at the following path: `custom/public/img/avatar\_default.png`
## Customizing Gitea pages and resources
## Customizing Gitea pages
Gitea's executable contains all the resources required to run: templates, images, style-sheets
and translations. Any of them can be overridden by placing a replacement in a matching path
inside the `custom` directory. For example, to replace the default `.gitignore` provided
for C++ repositories, we want to replace `options/gitignore/C++`. To do this, a replacement
must be placed in `custom/options/gitignore/C++` (see about the location of the `custom`
directory at the top of this document).
The `custom/templates` folder allows changing every single page of Gitea. Templates
to override can be found in the `templates` directory of Gitea source. Override by
making a copy of the file under `custom/templates` using a full path structure
matching source.
Every single page of Gitea can be changed. Dynamic content is generated using [go templates](https://golang.org/pkg/html/template/),
which can be modified by placing replacements below the `custom/templates` directory.
To obtain any embedded file (including templates), the [`gitea embedded` tool]({{< relref "doc/advanced/cmd-embedded.en-us.md" >}}) can be used. Alternatively, they can be found in the [`templates`](https://github.com/go-gitea/gitea/tree/master/templates) directory of Gitea source (Note: the example link is from the `master` branch. Make sure to use templates compatible with the release you are using).
Be aware that any statement contained inside `{{` and `}}` are Gitea's template syntax and
Any statement contained inside `{{` and `}}` are Gitea's template syntax and
shouldn't be touched without fully understanding these components.
### Customizing startpage / homepage
Copy [`home.tmpl`](https://github.com/go-gitea/gitea/blob/master/templates/home.tmpl) for your version of Gitea from `templates` to `custom/templates`.
Edit as you wish.
Dont forget to restart your gitea to apply the changes.
### Adding links and tabs
If all you want is to add extra links to the top navigation bar or footer, or extra tabs to the repository view, you can put them in `extra_links.tmpl` (links added to the navbar), `extra_links_footer.tmpl` (links added to the left side of footer), and `extra_tabs.tmpl` inside your `custom/templates/custom/` directory.
If all you want is to add extra links to the top navigation bar, or extra tabs to the repository view, you can put them in `extra_links.tmpl` and `extra_tabs.tmpl` inside your `custom/templates/custom/` directory.
For instance, let's say you are in Germany and must add the famously legally-required "Impressum"/about page, listing who is responsible for the site's content:
just place it under your "custom/public/" directory (for instance `custom/public/impressum.html`) and put a link to it in either `custom/templates/custom/extra_links.tmpl` or `custom/templates/custom/extra_links_footer.tmpl`.
just place it under your "custom/public/" directory (for instance `custom/public/impressum.html`) and put a link to it in `custom/templates/custom/extra_links.tmpl`.
To match the current style, the link should have the class name "item", and you can use `{{AppSubUrl}}` to get the base URL:
`<a class="item" href="{{AppSubUrl}}/impressum.html">Impressum</a>`
For more information, see [Adding Legal Pages](https://docs.gitea.io/en-us/adding-legal-pages).
You can add new tabs in the same way, putting them in `extra_tabs.tmpl`.
The exact HTML needed to match the style of other tabs is in the file
`templates/repo/header.tmpl`
@@ -108,173 +88,6 @@ Apart from `extra_links.tmpl` and `extra_tabs.tmpl`, there are other useful temp
- `body_outer_post.tmpl`, before the bottom `<footer>` element.
- `footer.tmpl`, right before the end of the `<body>` tag, a good place for additional Javascript.
#### Example: Mermaid.js
If you would like to add [mermaid.js](https://mermaid-js.github.io/mermaid) support to Gitea's markdown you simply add:
```html
{{if .RequireHighlightJS}}
<script src="https://unpkg.com/mermaid@8.4.5/dist/mermaid.min.js"></script>
<!-- or wherever you have placed it -->
<script>mermaid.init(".language-mermaid")</script>
{{end}}
```
to `custom/footer.tmpl`. You then can add blocks
like below to your markdown:
```mermaid
stateDiagram
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
```
If you want to use Mermaid.js outside of markdown, e.g. in other templates or HTML files,
you would need to remove `{{if .RequireHighlightJS}}` and `{{end}}`.
Mermaid will detect and use tags with `class="language-mermaid"`.
#### Example: PlantUML
You can add [PlantUML](https://plantuml.com/) support to Gitea's markdown by using a PlantUML server.
The data is encoded and sent to the PlantUML server which generates the picture. There is an online
demo server at http://www.plantuml.com/plantuml, but if you (or your users) have sensitive data you
can set up your own [PlantUML server](https://plantuml.com/server) instead. To set up PlantUML rendering,
copy javascript files from https://gitea.com/davidsvantesson/plantuml-code-highlight and put them in your
`custom/public` folder. Then add the following to `custom/footer.tmpl`:
```html
{{if .RequireHighlightJS}}
<script src="https://your-server.com/deflate.js"></script>
<script src="https://your-server.com/encode.js"></script>
<script src="https://your-server.com/plantuml_codeblock_parse.js"></script>
<script>
<!-- Replace call with address to your plantuml server-->
parsePlantumlCodeBlocks("http://www.plantuml..com/plantuml")
</script>
{{end}}
```
You can then add blocks like the following to your markdown:
```plantuml
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response
Alice -> Bob: Another authentication Request
Alice <-- Bob: Another authentication Response
```
The script will detect tags with `class="language-plantuml"`, but you can change this by providing a second argument to `parsePlantumlCodeBlocks`.
#### Example: STL Preview
You can display STL file directly in Gitea by adding:
```html
<script>
function lS(src){
return new Promise(function(resolve, reject) {
let s = document.createElement('script')
s.src = src
s.addEventListener('load', () => {
resolve()
})
document.body.appendChild(s)
});
}
if($('.view-raw>a[href$=".stl" i]').length){
$('body').append('<link href="/Madeleine.js/src/css/Madeleine.css" rel="stylesheet">');
Promise.all([lS("/Madeleine.js/src/lib/stats.js"),lS("/Madeleine.js/src/lib/detector.js"), lS("/Madeleine.js/src/lib/three.min.js"), lS("/Madeleine.js/src/Madeleine.js")]).then(function() {
$('.view-raw').attr('id', 'view-raw').attr('style', 'padding: 0;margin-bottom: -10px;');
new Madeleine({
target: 'view-raw',
data: $('.view-raw>a[href$=".stl" i]').attr('href'),
path: '/Madeleine.js/src'
});
$('.view-raw>a[href$=".stl"]').remove()
});
}
</script>
```
to the file `templates/custom/footer.tmpl`
You also need to download the content of the library [Madeleine.js](https://jinjunho.github.io/Madeleine.js/) and place it under `custom/public/` folder.
You should end-up with a folder structucture similar to:
```
custom/templates
-- custom
`-- footer.tmpl
custom/public
-- Madeleine.js
|-- LICENSE
|-- README.md
|-- css
| |-- pygment_trac.css
| `-- stylesheet.css
|-- examples
| |-- ajax.html
| |-- index.html
| `-- upload.html
|-- images
| |-- bg_hr.png
| |-- blacktocat.png
| |-- icon_download.png
| `-- sprite_download.png
|-- models
| |-- dino2.stl
| |-- ducati.stl
| |-- gallardo.stl
| |-- lamp.stl
| |-- octocat.stl
| |-- skull.stl
| `-- treefrog.stl
`-- src
|-- Madeleine.js
|-- css
| `-- Madeleine.css
|-- icons
| |-- logo.png
| |-- madeleine.eot
| |-- madeleine.svg
| |-- madeleine.ttf
| `-- madeleine.woff
`-- lib
|-- MadeleineConverter.js
|-- MadeleineLoader.js
|-- detector.js
|-- stats.js
`-- three.min.js
```
Then restart gitea and open a STL file on your gitea instance.
## Customizing Gitea mails
The `custom/templates/mail` folder allows changing the body of every mail of Gitea.
Templates to override can be found in the
[`templates/mail`](https://github.com/go-gitea/gitea/tree/master/templates/mail)
directory of Gitea source.
Override by making a copy of the file under `custom/templates/mail` using a
full path structure matching source.
Any statement contained inside `{{` and `}}` are Gitea's template
syntax and shouldn't be touched without fully understanding these components.
## Adding Analytics to Gitea
Google Analytics, Matomo (previously Piwik), and other analytics services can be added to Gitea. To add the tracking code, refer to the `Other additions to the page` section of this document, and add the JavaScript to the `custom/templates/custom/header.tmpl` file.
@@ -283,54 +96,6 @@ Google Analytics, Matomo (previously Piwik), and other analytics services can be
Place custom files in corresponding sub-folder under `custom/options`.
**NOTE:** The files should not have a file extension, e.g. `Labels` rather than `Labels.txt`
### gitignores
To add custom .gitignore, add a file with existing [.gitignore rules](https://git-scm.com/docs/gitignore) in it to `custom/options/gitignore`
### Labels
To add a custom label set, add a file that follows the [label format](https://github.com/go-gitea/gitea/blob/master/options/label/Default) to `custom/options/label`
`#hex-color label name ; label description`
### Licenses
To add a custom license, add a file with the license text to `custom/options/license`
### Locales
Locales are managed via our [crowdin](https://crowdin.com/project/gitea).
You can override a locale by placing an altered locale file in `custom/options/locale`.
Gitea's default locale files can be found in the [`options/locale`](https://github.com/go-gitea/gitea/tree/master/options/locale) source folder and these should be used as examples for your changes.
To add a completely new locale, as well as placing the file in the above location, you will need to add the new lang and name to the `[i18n]` section in your `app.ini`. Keep in mind that Gitea will use those settings as **overrides**, so if you want to keep the other languages as well you will need to copy/paste the default values and add your own to them.
```
[i18n]
LANGS = en-US,foo-BAR
NAMES = English,FooBar
```
Locales may change between versions, so keeping track of your customized locales is highly encouraged.
### Readmes
To add a custom Readme, add a markdown formatted file (without an `.md` extension) to `custom/options/readme`
**NOTE:** readme templates support **variable expansion**.
currently there are `{Name}` (name of repository), `{Description}`, `{CloneURL.SSH}`, `{CloneURL.HTTPS}` and `{OwnerName}`
### Reactions
To change reaction emoji's you can set allowed reactions at app.ini
```
[ui]
REACTIONS = +1, -1, laugh, confused, heart, hooray, eyes
```
A full list of supported emoji's is at [emoji list](https://gitea.com/gitea/gitea.com/issues/8)
## Customizing the look of Gitea
As of version 1.6.0 Gitea has built-in themes. The two built-in themes are, the default theme `gitea`, and a dark theme `arc-green`. To change the look of your Gitea install change the value of `DEFAULT_THEME` in the [ui](https://docs.gitea.io/en-us/config-cheat-sheet/#ui-ui) section of `app.ini` to another one of the available options.
As of version 1.8.0 Gitea also has per-user themes. The list of themes a user can choose from can be configured with the `THEMES` value in the [ui](https://docs.gitea.io/en-us/config-cheat-sheet/#ui-ui) section of `app.ini` (defaults to `gitea` and `arc-green`, light and dark respectively)
As of version 1.6.0 Gitea has built-in themes. The two built-in themes are, the default theme `gitea`, and a dark theme `arc-green`. To change the look of your Gitea install change the value of `DEFAULT_THEME` in the [ui](https://docs.gitea.io/en-us/config-cheat-sheet/#ui-ui) section of `app.ini` to another one of the available options.

View File

@@ -16,13 +16,10 @@ menu:
# Custom files rendering configuration
Gitea supports custom file renderings (i.e., Jupyter notebooks, asciidoc, etc.) through external binaries,
it is just a matter of:
it is just matter of:
* installing external binaries
* add some configuration to your `app.ini` file
* restart your Gitea instance
This supports rendering of whole files. If you want to render code blocks in markdown you would need to do something with javascript. See some examples on the [Customizing Gitea](../customizing-gitea) page.
* restart your gitea instance
## Installing external binaries
@@ -30,13 +27,13 @@ In order to get file rendering through external binaries, their associated packa
If you're using a Docker image, your `Dockerfile` should contain something along this lines:
```
FROM gitea/gitea:{{< version >}}
FROM gitea/gitea:1.6.0
[...]
COPY custom/app.ini /data/gitea/conf/app.ini
[...]
RUN apk --no-cache add asciidoctor freetype freetype-dev gcc g++ libpng python-dev py-pip python3-dev py3-pip py3-pyzmq
RUN apk --no-cache add asciidoctor freetype freetype-dev gcc g++ libpng python-dev py-pip python3-dev py3-pip
# install any other package you need for your external renderers
RUN pip3 install --upgrade pip
@@ -53,7 +50,7 @@ add one `[markup.XXXXX]` section per external renderer on your custom `app.ini`:
[markup.asciidoc]
ENABLED = true
FILE_EXTENSIONS = .adoc,.asciidoc
RENDER_COMMAND = "asciidoctor -e -a leveloffset=-1 --out-file=- -"
RENDER_COMMAND = "asciidoctor --out-file=- -"
; Input is not a standard input but a file
IS_INPUT_FILE = false
@@ -70,27 +67,4 @@ RENDER_COMMAND = rst2html.py
IS_INPUT_FILE = false
```
If your external markup relies on additional classes and attributes on the generated HTML elements, you might need to enable custom sanitizer policies. Gitea uses the [`bluemonday`](https://godoc.org/github.com/microcosm-cc/bluemonday) package as our HTML sanitizier. The example below will support [KaTeX](https://katex.org/) output from [`pandoc`](https://pandoc.org/).
```ini
[markup.sanitizer.TeX]
; Pandoc renders TeX segments as <span>s with the "math" class, optionally
; with "inline" or "display" classes depending on context.
ELEMENT = span
ALLOW_ATTR = class
REGEXP = ^\s*((math(\s+|$)|inline(\s+|$)|display(\s+|$)))+
[markup.markdown]
ENABLED = true
FILE_EXTENSIONS = .md,.markdown
RENDER_COMMAND = pandoc -f markdown -t html --katex
```
You must define `ELEMENT`, `ALLOW_ATTR`, and `REGEXP` in each section.
To define multiple entries, add a unique alphanumeric suffix (e.g., `[markup.sanitizer.1]` and `[markup.sanitizer.something]`).
Once your configuration changes have been made, restart Gitea to have changes take effect.
**Note**: Prior to Gitea 1.12 there was a single `markup.sanitiser` section with keys that were redefined for multiple rules, however,
there were significant problems with this method of configuration necessitating configuration through multiple sections.

View File

@@ -15,278 +15,41 @@ menu:
# Hacking on Gitea
## Installing go and setting the GOPATH
Familiarity with the existing [installation instructions](https://golang.org/doc/install)
is required for this section.
You should [install go](https://golang.org/doc/install) and set up your go
environment correctly. In particular, it is recommended to set the `$GOPATH`
environment variable and to add the go bin directory or directories
`${GOPATH//://bin:}/bin` to the `$PATH`. See the Go wiki entry for
[GOPATH](https://github.com/golang/go/wiki/GOPATH).
To contribute to Gitea, fork the project and work on the `master` branch.
Next, [install Node.js with npm](https://nodejs.org/en/download/) which is
required to build the JavaScript and CSS files. The minimum supported Node.js
version is {{< min-node-version >}} and the latest LTS version is recommended.
Some internal packages are referenced using their respective Github URL. This can
become problematic. To "trick" the Go tool into thinking this is a clone from the
official repository, download the source code using "go get" and follow these instructions.
You will also need make.
<a href='{{< relref "doc/advanced/make.en-us.md" >}}'>(See here how to get Make)</a>
**Note**: When executing make tasks that require external tools, like
`make misspell-check`, Gitea will automatically download and build these as
necessary. To be able to use these you must have the `"$GOPATH"/bin` directory
on the executable path. If you don't add the go bin directory to the
executable path you will have to manage this yourself.
**Note 2**: Go version {{< min-go-version >}} or higher is required; however, it is important
to note that our continuous integration will check that the formatting of the
source code is not changed by `gofmt` using `make fmt-check`. Unfortunately,
the results of `gofmt` can differ by the version of `go`. It is therefore
recommended to install the version of Go that our continuous integration is
running. As of last update, it should be Go version {{< go-version >}}.
## Downloading and cloning the Gitea source code
The recommended method of obtaining the source code is by using `git clone`.
```bash
git clone https://github.com/go-gitea/gitea
```
go get -d code.gitea.io/gitea
```
(Since the advent of go modules, it is no longer necessary to build go projects
from within the `$GOPATH`, hence the `go get` approach is no longer recommended.)
Fork the [Gitea repository](https://github.com/go-gitea/gitea) on GitHub, it should
then be possible to switch the source directory on the command line.
## Forking Gitea
Download the master Gitea source code as above. Then, fork the
[Gitea repository](https://github.com/go-gitea/gitea) on GitHub,
and either switch the git remote origin for your fork or add your fork as another remote:
```bash
# Rename original Gitea origin to upstream
git remote rename origin upstream
git remote add origin "git@github.com:$GITHUB_USERNAME/gitea.git"
git fetch --all --prune
```
or:
```bash
# Add new remote for our fork
git remote add "$FORK_NAME" "git@github.com:$GITHUB_USERNAME/gitea.git"
git fetch --all --prune
cd $GOPATH/src/code.gitea.io/gitea
```
To be able to create pull requests, the forked repository should be added as a remote
to the Gitea sources. Otherwise, changes can't be pushed.
to the Gitea sources, otherwise changes can't be pushed.
## Building Gitea (Basic)
Take a look at our
<a href='{{< relref "doc/installation/from-source.en-us.md" >}}'>instructions</a>
for <a href='{{< relref "doc/installation/from-source.en-us.md" >}}'>building
from source</a>.
The simplest recommended way to build from source is:
```bash
TAGS="bindata sqlite sqlite_unlock_notify" make build
```
git remote rename origin upstream
git remote add origin git@github.com:<USERNAME>/gitea.git
git fetch --all --prune
```
See `make help` for all available `make` tasks. Also see [`.drone.yml`](https://github.com/go-gitea/gitea/blob/master/.drone.yml) to see how our continuous integration works.
This should provide a working development environment for Gitea. Take a look at
the `Makefile` to get an overview about the available tasks. The most common tasks
should be `make test` which will start our test environment and `make build` which
will build a `gitea` binary into the working directory. Writing test cases is not
mandatory to contribute, but it is highly encouraged and helps developers sleep
at night.
### Formatting, code analysis and spell check
Our continuous integration will reject PRs that are not properly formatted, fail
code analysis or spell check.
You should format your code with `go fmt` using:
```bash
make fmt
```
and can test whether your changes would match the results with:
```bash
make fmt-check # which runs make fmt internally
```
**Note**: The results of `go fmt` are dependent on the version of `go` present.
You should run the same version of go that is on the continuous integration
server as mentioned above. `make fmt-check` will only check if your `go` would
format differently - this may be different from the CI server version.
You should run revive, vet and spell-check on the code with:
```bash
make revive vet misspell-check
```
### Working on JS and CSS
For simple changes, edit files in `web_src`, run the build and start the server to test:
```bash
make build && ./gitea
```
`make build` runs both `make frontend` and `make backend` which can be run individually as well as long as the `bindata` tag is not used (which compiles frontend files into the binary).
For more involved changes use the `watch-frontend` task to continuously rebuild files when their sources change. The `bindata` tag must be absent. First, build and run the backend:
```bash
make backend && ./gitea
```
With the backend running, open another terminal and run:
```bash
make watch-frontend
```
Before committing, make sure the linters pass:
```bash
make lint-frontend
```
Note: When working on frontend code, set `USE_SERVICE_WORKER` to `false` in `app.ini` to prevent undesirable caching of frontend assets.
### Building Images
To build the images, ImageMagick, `inkscape` and `zopflipng` binaries must be available in
your `PATH` to run `make generate-images`.
### Updating the API
When creating new API routes or modifying existing API routes, you **MUST**
update and/or create [Swagger](https://swagger.io/docs/specification/2-0/what-is-swagger/)
documentation for these using [go-swagger](https://goswagger.io/) comments.
The structure of these comments is described in the [specification](https://goswagger.io/use/spec.html#annotation-syntax).
If you want more information about the Swagger structure, you can look at the
[Swagger 2.0 Documentation](https://swagger.io/docs/specification/2-0/basic-structure/)
or compare with a previous PR adding a new API endpoint, e.g. [PR #5483](https://github.com/go-gitea/gitea/pull/5843/files#diff-2e0a7b644cf31e1c8ef7d76b444fe3aaR20)
You should be careful not to break the API for downstream users which depend
on a stable API. In general, this means additions are acceptable, but deletions
or fundamental changes to the API will be rejected.
Once you have created or changed an API endpoint, please regenerate the Swagger
documentation using:
```bash
make generate-swagger
```
You should validate your generated Swagger file and spell-check it with:
```bash
make swagger-validate misspell-check
```
You should commit the changed swagger JSON file. The continous integration
server will check that this has been done using:
```bash
make swagger-check
```
**Note**: Please note you should use the Swagger 2.0 documentation, not the
OpenAPI 3 documentation.
### Creating new configuration options
When creating new configuration options, it is not enough to add them to the
`modules/setting` files. You should add information to `custom/conf/app.ini`
and to the
<a href='{{< relref "doc/advanced/config-cheat-sheet.en-us.md" >}}'>configuration cheat sheet</a>
found in `docs/content/doc/advanced/config-cheat-sheet.en-us.md`
### Changing the logo
When changing the Gitea logo SVG, you will need to run and commit the results
of:
```bash
make generate-images
```
This will create the necessary Gitea favicon and others.
### Database Migrations
If you make breaking changes to any of the database persisted structs in the
`models/` directory, you will need to make a new migration. These can be found
in `models/migrations/`. You can ensure that your migrations work for the main
database types using:
```bash
make test-sqlite-migration # with sqlite switched for the appropriate database
```
## Testing
There are two types of test run by Gitea: Unit tests and Integration Tests.
```bash
TAGS="bindata sqlite sqlite_unlock_notify" make test # Runs the unit tests
```
Unit tests will not and cannot completely test Gitea alone. Therefore, we
have written integration tests; however, these are database dependent.
```bash
TAGS="bindata sqlite sqlite_unlock_notify" make build test-sqlite
```
will run the integration tests in an sqlite environment. Integration tests
require `git lfs` to be installed. Other database tests are available but
may need adjustment to the local environment.
Look at
[`integrations/README.md`](https://github.com/go-gitea/gitea/blob/master/integrations/README.md)
for more information and how to run a single test.
Our continuous integration will test the code passes its unit tests and that
all supported databases will pass integration test in a Docker environment.
Migration from several recent versions of Gitea will also be tested.
Please submit your PR with additional tests and integration tests as
appropriate.
## Documentation for the website
Documentation for the website is found in `docs/`. If you change this you
can test your changes to ensure that they pass continuous integration using:
```bash
# from the docs directory within Gitea
make trans-copy clean build
```
You will require a copy of [Hugo](https://gohugo.io/) to run this task. Please
note: this may generate a number of untracked git objects, which will need to
be cleaned up.
## Visual Studio Code
A `launch.json` and `tasks.json` are provided within `contrib/ide/vscode` for
Visual Studio Code. Look at
[`contrib/ide/README.md`](https://github.com/go-gitea/gitea/blob/master/contrib/ide/README.md)
for more information.
## Submitting PRs
Once you're happy with your changes, push them up and open a pull request. It
is recommended that you allow Gitea Managers and Owners to modify your PR
branches as we will need to update it to master before merging and/or may be
able to help fix issues directly.
Any PR requires two approvals from the Gitea maintainers and needs to pass the
continous integration. Take a look at our
[`CONTRIBUTING.md`](https://github.com/go-gitea/gitea/blob/master/CONTRIBUTING.md)
document.
If you need more help pop on to [Discord](https://discord.gg/gitea) #Develop
and chat there.
That's it! You are ready to hack on Gitea.
That's it! You are ready to hack on Gitea. Test changes, push them to the repository,
and open a pull request.

View File

@@ -1,401 +0,0 @@
---
date: "2019-04-02T17:06:00+01:00"
title: "Advanced: Logging Configuration"
slug: "logging-configuration"
weight: 55
toc: true
draft: false
menu:
sidebar:
parent: "advanced"
name: "Logging Configuration"
weight: 55
identifier: "logging-configuration"
---
# Logging Configuration
The logging framework has been revamped in Gitea 1.9.0.
## Log Groups
The fundamental thing to be aware of in Gitea is that there are several
log groups:
* The "Default" logger
* The Macaron logger
* The Router logger
* The Access logger
* The XORM logger
There is also the go log logger.
### The go log logger
Go provides its own extremely basic logger in the `log` package,
however, this is not sufficient for our purposes as it does not provide
a way of logging at multiple levels, nor does it provide a good way of
controlling where these logs are logged except through setting of a
writer.
We have therefore redirected this logger to our Default logger, and we
will log anything that is logged using the go logger at the INFO level.
### The "Default" logger
Calls to `log.Info`, `log.Debug`, `log.Error` etc. from the `code.gitea.io/gitea/modules/log` package will log to this logger.
You can configure the outputs of this logger by setting the `MODE`
value in the `[log]` section of the configuration.
Each output sublogger is configured in a separate `[log.sublogger.default]`
which inherits from the sublogger `[log.sublogger]` section and from the
generic `[log]` section, but there are certain default values. These will
not be inherited from the `[log]` section:
* `FLAGS` is `stdflags` (Equal to
`date,time,medfile,shortfuncname,levelinitial`)
* `FILE_NAME` will default to `%(ROOT_PATH)/gitea.log`
* `EXPRESSION` will default to `""`
* `PREFIX` will default to `""`
The provider type of the sublogger can be set using the `MODE` value in
its subsection, but will default to the name. This allows you to have
multiple subloggers that will log to files.
### The "Macaron" logger
By default Macaron will log to its own go `log` instance. This writes
to `os.Stdout`. You can redirect this log to a Gitea configurable logger
through setting the `REDIRECT_MACARON_LOG` setting in the `[log]`
section which you can configure the outputs of by setting the `MACARON`
value in the `[log]` section of the configuration. `MACARON` defaults
to `file` if unset.
Please note, the macaron logger will log at `INFO` level, setting the
`LEVEL` of this logger to `WARN` or above will result in no macaron logs.
Each output sublogger for this logger is configured in
`[log.sublogger.macaron]` sections. There are certain default values
which will not be inherited from the `[log]` or relevant
`[log.sublogger]` sections:
* `FLAGS` is `stdflags` (Equal to
`date,time,medfile,shortfuncname,levelinitial`)
* `FILE_NAME` will default to `%(ROOT_PATH)/macaron.log`
* `EXPRESSION` will default to `""`
* `PREFIX` will default to `""`
NB: You can redirect the macaron logger to send its events to the gitea
log using the value: `MACARON = ,`
### The "Router" logger
There are two types of Router log. By default Macaron send its own
router log which will be directed to Macaron's go `log`, however if you
`REDIRECT_MACARON_LOG` you will enable Gitea's router log. You can
disable both types of Router log by setting `DISABLE_ROUTER_LOG`.
If you enable the redirect, you can configure the outputs of this
router log by setting the `ROUTER` value in the `[log]` section of the
configuration. `ROUTER` will default to `console` if unset. The Gitea
Router logs the same data as the Macaron log but has slightly different
coloring. It logs at the `Info` level by default, but this can be
changed if desired by setting the `ROUTER_LOG_LEVEL` value.
Please note, setting the `LEVEL` of this logger to a level above
`ROUTER_LOG_LEVEL` will result in no router logs.
Each output sublogger for this logger is configured in
`[log.sublogger.router]` sections. There are certain default values
which will not be inherited from the `[log]` or relevant
`[log.sublogger]` sections:
* `FILE_NAME` will default to `%(ROOT_PATH)/router.log`
* `FLAGS` defaults to `date,time`
* `EXPRESSION` will default to `""`
* `PREFIX` will default to `""`
NB: You can redirect the router logger to send its events to the Gitea
log using the value: `ROUTER = ,`
### The "Access" logger
The Access logger is a new logger for version 1.9. It provides a NCSA
Common Log compliant log format. It's highly configurable but caution
should be taken when changing its template. The main benefit of this
logger is that Gitea can now log accesses in a standard log format so
standard tools may be used.
You can enable this logger using `ENABLE_ACCESS_LOG`. Its outputs are
configured by setting the `ACCESS` value in the `[log]` section of the
configuration. `ACCESS` defaults to `file` if unset.
Each output sublogger for this logger is configured in
`[log.sublogger.access]` sections. There are certain default values
which will not be inherited from the `[log]` or relevant
`[log.sublogger]` sections:
* `FILE_NAME` will default to `%(ROOT_PATH)/access.log`
* `FLAGS` defaults to `` or None
* `EXPRESSION` will default to `""`
* `PREFIX` will default to `""`
If desired the format of the Access logger can be changed by changing
the value of the `ACCESS_LOG_TEMPLATE`.
Please note, the access logger will log at `INFO` level, setting the
`LEVEL` of this logger to `WARN` or above will result in no access logs.
NB: You can redirect the access logger to send its events to the Gitea
log using the value: `ACCESS = ,`
#### The ACCESS_LOG_TEMPLATE
This value represent a go template. It's default value is:
`{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`
The template is passed following options:
* `Ctx` is the `macaron.Context`
* `Identity` is the `SignedUserName` or `"-"` if the user is not logged
in
* `Start` is the start time of the request
* `ResponseWriter` is the `macaron.ResponseWriter`
Caution must be taken when changing this template as it runs outside of
the standard panic recovery trap. The template should also be as simple
as it runs for every request.
### The "XORM" logger
The XORM logger is a long-standing logger that exists to collect XORM
log events. It is enabled by default but can be switched off by setting
`ENABLE_XORM_LOG` to `false` in the `[log]` section. Its outputs are
configured by setting the `XORM` value in the `[log]` section of the
configuration. `XORM` defaults to `,` if unset, meaning it is redirected
to the main Gitea log.
XORM will log SQL events by default. This can be changed by setting
the `LOG_SQL` value to `false` in the `[database]` section.
Each output sublogger for this logger is configured in
`[log.sublogger.xorm]` sections. There are certain default values
which will not be inherited from the `[log]` or relevant
`[log.sublogger]` sections:
* `FILE_NAME` will default to `%(ROOT_PATH)/xorm.log`
* `FLAGS` defaults to `date,time`
* `EXPRESSION` will default to `""`
* `PREFIX` will default to `""`
## Log outputs
Gitea provides 4 possible log outputs:
* `console` - Log to `os.Stdout` or `os.Stderr`
* `file` - Log to a file
* `conn` - Log to a keep-alive TCP connection
* `smtp` - Log via email
Certain configuration is common to all modes of log output:
* `LEVEL` is the lowest level that this output will log. This value
is inherited from `[log]` and in the case of the non-default loggers
from `[log.sublogger]`.
* `STACKTRACE_LEVEL` is the lowest level that this output will print
a stacktrace. This value is inherited.
* `MODE` is the mode of the log output. It will default to the sublogger
name. Thus `[log.console.macaron]` will default to `MODE = console`.
* `COLORIZE` will default to `true` for `console` as
described, otherwise it will default to `false`.
### Non-inherited default values
There are several values which are not inherited as described above but
rather default to those specific to type of logger, these are:
`EXPRESSION`, `FLAGS`, `PREFIX` and `FILE_NAME`.
#### `EXPRESSION`
`EXPRESSION` represents a regular expression that log events must match to be logged by the sublogger. Either the log message, (with colors removed), must match or the `longfilename:linenumber:functionname` must match. NB: the whole message or string doesn't need to completely match.
Please note this expression will be run in the sublogger's goroutine
not the logging event subroutine. Therefore it can be complicated.
#### `FLAGS`
`FLAGS` represents the preceding logging context information that is
printed before each message. It is a comma-separated string set. The order of values does not matter.
Possible values are:
* `none` or `,` - No flags.
* `date` - the date in the local time zone: `2009/01/23`.
* `time` - the time in the local time zone: `01:23:23`.
* `microseconds` - microsecond resolution: `01:23:23.123123`. Assumes
time.
* `longfile` - full file name and line number: `/a/b/c/d.go:23`.
* `shortfile` - final file name element and line number: `d.go:23`.
* `funcname` - function name of the caller: `runtime.Caller()`.
* `shortfuncname` - last part of the function name. Overrides
`funcname`.
* `utc` - if date or time is set, use UTC rather than the local time
zone.
* `levelinitial` - Initial character of the provided level in brackets eg. `[I]` for info.
* `level` - Provided level in brackets `[INFO]`
* `medfile` - Last 20 characters of the filename - equivalent to
`shortfile,longfile`.
* `stdflags` - Equivalent to `date,time,medfile,shortfuncname,levelinitial`
### Console mode
For loggers in console mode, `COLORIZE` will default to `true` if not
on windows, or the windows terminal can be set into ANSI mode or is a
cygwin or Msys pipe.
If `STDERR` is set to `true` the logger will use `os.Stderr` instead of
`os.Stdout`.
### File mode
The `FILE_NAME` defaults as described above. If set it will be relative
to the provided `ROOT_PATH` in the master `[log]` section.
Other values:
* `LOG_ROTATE`: **true**: Rotate the log files.
* `MAX_SIZE_SHIFT`: **28**: Maximum size shift of a single file, 28 represents 256Mb.
* `DAILY_ROTATE`: **true**: Rotate logs daily.
* `MAX_DAYS`: **7**: Delete the log file after n days
* `COMPRESS`: **true**: Compress old log files by default with gzip
* `COMPRESSION_LEVEL`: **-1**: Compression level
### Conn mode
* `RECONNECT_ON_MSG`: **false**: Reconnect host for every single message.
* `RECONNECT`: **false**: Try to reconnect when connection is lost.
* `PROTOCOL`: **tcp**: Set the protocol, either "tcp", "unix" or "udp".
* `ADDR`: **:7020**: Sets the address to connect to.
### SMTP mode
It is not recommended to use this logger to send general logging
messages. However, you could perhaps set this logger to work on `FATAL`.
* `USER`: User email address to send from.
* `PASSWD`: Password for the smtp server.
* `HOST`: **127.0.0.1:25**: The SMTP host to connect to.
* `RECEIVERS`: Email addresses to send to.
* `SUBJECT`: **Diagnostic message from Gitea**
## Default Configuration
The default empty configuration is equivalent to:
```ini
[log]
ROOT_PATH = %(GITEA_WORK_DIR)/log
MODE = console
LEVEL = Info
STACKTRACE_LEVEL = None
REDIRECT_MACARON_LOG = false
ENABLE_ACCESS_LOG = false
ENABLE_XORM_LOG = true
XORM = ,
[log.console]
MODE = console
LEVEL = %(LEVEL)
STACKTRACE_LEVEL = %(STACKTRACE_LEVEL)
FLAGS = stdflags
PREFIX =
COLORIZE = true # Or false if your windows terminal cannot color
```
This is equivalent to sending all logs to the console, with default go log being sent to the console log too.
## Log colorization
Logs to the console will be colorized by default when not running on
Windows. Terminal sniffing will occur on Windows and if it is
determined that we are running on a terminal capable of color we will
colorize.
Further, on *nix it is becoming common to have file logs that are
colored by default. Therefore file logs will be colorised by default
when not running on Windows.
You can switch on or off colorization by using the `COLORIZE` value.
From a development point of view. If you write
`log.Info("A %s string", "formatted")` the `formatted` part of the log
message will be Bolded on colorized logs.
You can change this by either rendering the formatted string yourself.
Or you can wrap the value in a `log.ColoredValue` struct.
The `log.ColoredValue` struct contains a pointer to value, a pointer to
string of bytes which should represent a color and second set of reset
bytes. Pointers were chosen to prevent copying of large numbers of
values. There are several helper methods:
* `log.NewColoredValue` takes a value and 0 or more color attributes
that represent the color. If 0 are provided it will default to a cached
bold. Note, it is recommended that color bytes constructed from
attributes should be cached if this is a commonly used log message.
* `log.NewColoredValuePointer` takes a pointer to a value, and
0 or more color attributes that represent the color.
* `log.NewColoredValueBytes` takes a value and a pointer to an array
of bytes representing the color.
These functions will not double wrap a `log.ColoredValue`. They will
also set the `resetBytes` to the cached `resetBytes`.
The `colorBytes` and `resetBytes` are not exported to prevent
accidental overwriting of internal values.
## ColorFormat & ColorFormatted
Structs may implement the `log.ColorFormatted` interface by implementing the `ColorFormat(fmt.State)` function.
If a `log.ColorFormatted` struct is logged with `%-v` format, its `ColorFormat` will be used instead of the usual `%v`. The full `fmt.State` will be passed to allow implementers to look at additional flags.
In order to help implementers provide `ColorFormat` methods. There is a
`log.ColorFprintf(...)` function in the log module that will wrap values in `log.ColoredValue` and recognise `%-v`.
In general it is recommended not to make the results of this function too verbose to help increase its versatility. Usually this should simply be an `ID`:`Name`. If you wish to make a more verbose result, it is recommended to use `%-+v` as your marker.
## Log Spoofing protection
In order to protect the logs from being spoofed with cleverly
constructed messages. Newlines are now prefixed with a tab and control
characters except those used in an ANSI CSI are escaped with a
preceding `\` and their octal value.
## Creating a new named logger group
Should a developer wish to create a new named logger, `NEWONE`. It is
recommended to add an `ENABLE_NEWONE_LOG` value to the `[log]`
section, and to add a new `NEWONE` value for the modes.
A function like `func newNewOneLogService()` is recommended to manage
construction of the named logger. e.g.
```go
func newNewoneLogService() {
EnableNewoneLog = Cfg.Section("log").Key("ENABLE_NEWONE_LOG").MustBool(false)
Cfg.Section("log").Key("NEWONE").MustString("file") // or console? or "," if you want to send this to default logger by default
if EnableNewoneLog {
options := newDefaultLogOptions()
options.filename = filepath.Join(LogRootPath, "newone.log")
options.flags = "stdflags"
options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
generateNamedLogger("newone", options)
}
}
```
You should then add `newOneLogService` to `NewServices()` in
`modules/setting/setting.go`

View File

@@ -1,276 +0,0 @@
---
date: "2019-10-23T17:00:00-03:00"
title: "Mail templates"
slug: "mail-templates"
weight: 45
toc: true
draft: false
menu:
sidebar:
parent: "advanced"
name: "Mail templates"
weight: 45
identifier: "mail-templates"
---
# Mail templates
To craft the e-mail subject and contents for certain operations, Gitea can be customized by using templates. The templates
for these functions are located under the [`custom` directory](https://docs.gitea.io/en-us/customizing-gitea/).
Gitea has an internal template that serves as default in case there's no custom alternative.
Custom templates are loaded when Gitea starts. Changes made to them are not recognized until Gitea is restarted again.
## Mail notifications supporting templates
Currently, the following notification events make use of templates:
| Action name | Usage |
|---------------|--------------------------------------------------------------------------------------------------------------|
| `new` | A new issue or pull request was created. |
| `comment` | A new comment was created in an existing issue or pull request. |
| `close` | An issue or pull request was closed. |
| `reopen` | An issue or pull request was reopened. |
| `review` | The head comment of a review in a pull request. |
| `approve` | The head comment of a approving review for a pull request. |
| `reject` | The head comment of a review requesting changes for a pull request. |
| `code` | A single comment on the code of a pull request. |
| `assigned` | Used was assigned to an issue or pull request. |
| `default` | Any action not included in the above categories, or when the corresponding category template is not present. |
The path for the template of a particular message type is:
```
custom/templates/mail/{action type}/{action name}.tmpl
```
Where `{action type}` is one of `issue` or `pull` (for pull requests), and `{action name}` is one of the names listed above.
For example, the specific template for a mail regarding a comment in a pull request is:
```
custom/templates/mail/pull/comment.tmpl
```
However, creating templates for each and every action type/name combination is not required.
A fallback system is used to choose the appropriate template for an event. The _first existing_
template on this list is used:
* The specific template for the desired **action type** and **action name**.
* The template for action type `issue` and the desired **action name**.
* The template for the desired **action type**, action name `default`.
* The template for action type `issue`, action name `default`.
The only mandatory template is action type `issue`, action name `default`, which is already embedded in Gitea
unless it's overridden by the user in the `custom` directory.
## Template syntax
Mail templates are UTF-8 encoded text files that need to follow one of the following formats:
```
Text and macros for the subject line
------------
Text and macros for the mail body
```
or
```
Text and macros for the mail body
```
Specifying a _subject_ section is optional (and therefore also the dash line separator). When used, the separator between
_subject_ and _mail body_ templates requires at least three dashes; no other characters are allowed in the separator line.
_Subject_ and _mail body_ are parsed by [Golang's template engine](https://golang.org/pkg/text/template/) and
are provided with a _metadata context_ assembled for each notification. The context contains the following elements:
| Name | Type | Available | Usage |
|--------------------|------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| `.FallbackSubject` | string | Always | A default subject line. See Below. |
| `.Subject` | string | Only in body | The _subject_, once resolved. |
| `.Body` | string | Always | The message of the issue, pull request or comment, parsed from Markdown into HTML and sanitized. Do not confuse with the _mail body_. |
| `.Link` | string | Always | The address of the originating issue, pull request or comment. |
| `.Issue` | models.Issue | Always | The issue (or pull request) originating the notification. To get data specific to a pull request (e.g. `HasMerged`), `.Issue.PullRequest` can be used, but care should be taken as this field will be `nil` if the issue is *not* a pull request. |
| `.Comment` | models.Comment | If applicable | If the notification is from a comment added to an issue or pull request, this will contain the information about the comment. |
| `.IsPull` | bool | Always | `true` if the mail notification is associated with a pull request (i.e. `.Issue.PullRequest` is not `nil`). |
| `.Repo` | string | Always | Name of the repository, including owner name (e.g. `mike/stuff`) |
| `.User` | models.User | Always | Owner of the repository from which the event originated. To get the user name (e.g. `mike`),`.User.Name` can be used. |
| `.Doer` | models.User | Always | User that executed the action triggering the notification event. To get the user name (e.g. `rhonda`), `.Doer.Name` can be used. |
| `.IsMention` | bool | Always | `true` if this notification was only generated because the user was mentioned in the comment, while not being subscribed to the source. It will be `false` if the recipient was subscribed to the issue or repository. |
| `.SubjectPrefix` | string | Always | `Re: ` if the notification is about other than issue or pull request creation; otherwise an empty string. |
| `.ActionType` | string | Always | `"issue"` or `"pull"`. Will correspond to the actual _action type_ independently of which template was selected. |
| `.ActionName` | string | Always | It will be one of the action types described above (`new`, `comment`, etc.), and will correspond to the actual _action name_ independently of which template was selected. |
| `.ReviewComments` | []models.Comment | Always | List of code comments in a review. The comment text will be in `.RenderedContent` and the referenced code will be in `.Patch`. |
All names are case sensitive.
### The _subject_ part of the template
The template engine used for the mail _subject_ is golang's [`text/template`](https://golang.org/pkg/text/template/).
Please refer to the linked documentation for details about its syntax.
The _subject_ is built using the following steps:
* A template is selected according to the type of notification and to what templates are present.
* The template is parsed and resolved (e.g. `{{.Issue.Index}}` is converted to the number of the issue
or pull request).
* All space-like characters (e.g. `TAB`, `LF`, etc.) are converted to normal spaces.
* All leading, trailing and redundant spaces are removed.
* The string is truncated to its first 256 runes (characters).
If the end result is an empty string, **or** no subject template was available (i.e. the selected template
did not include a subject part), Gitea's **internal default** will be used.
The internal default (fallback) subject is the equivalent of:
```
{{.SubjectPrefix}}[{{.Repo}}] {{.Issue.Title}} (#.Issue.Index)
```
For example: `Re: [mike/stuff] New color palette (#38)`
Gitea's default subject can also be found in the template _metadata_ as `.FallbackSubject` from any of
the two templates, even if a valid subject template is present.
### The _mail body_ part of the template
The template engine used for the _mail body_ is golang's [`html/template`](https://golang.org/pkg/html/template/).
Please refer to the linked documentation for details about its syntax.
The _mail body_ is parsed after the mail subject, so there is an additional _metadata_ field which is
the actual rendered subject, after all considerations.
The expected result is HTML (including structural elements like`<html>`, `<body>`, etc.). Styling
through `<style>` blocks, `class` and `style` attributes is possible. However, `html/template`
does some [automatic escaping](https://golang.org/pkg/html/template/#hdr-Contexts) that should be considered.
Attachments (such as images or external style sheets) are not supported. However, other templates can
be referenced too, for example to provide the contents of a `<style>` element in a centralized fashion.
The external template must be placed under `custom/mail` and referenced relative to that directory.
For example, `custom/mail/styles/base.tmpl` can be included using `{{template styles/base}}`.
The mail is sent with `Content-Type: multipart/alternative`, so the body is sent in both HTML
and text formats. The latter is obtained by stripping the HTML markup.
## Troubleshooting
How a mail is rendered is directly dependent on the capabilities of the mail application. Many mail
clients don't even support HTML, so they show the text version included in the generated mail.
If the template fails to render, it will be noticed only at the moment the mail is sent.
A default subject is used if the subject template fails, and whatever was rendered successfully
from the the _mail body_ is used, disregarding the rest.
Please check [Gitea's logs](https://docs.gitea.io/en-us/logging-configuration/) for error messages in case of trouble.
## Example
`custom/templates/mail/issue/default.tmpl`:
```
[{{.Repo}}] @{{.Doer.Name}}
{{if eq .ActionName "new"}}
created
{{else if eq .ActionName "comment"}}
commented on
{{else if eq .ActionName "close"}}
closed
{{else if eq .ActionName "reopen"}}
reopened
{{else}}
updated
{{end}}
{{if eq .ActionType "issue"}}
issue
{{else}}
pull request
{{end}}
#{{.Issue.Index}}: {{.Issue.Title}}
------------
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{{.Subject}}</title>
</head>
<body>
{{if .IsMention}}
<p>
You are receiving this because @{{.Doer.Name}} mentioned you.
</p>
{{end}}
<p>
<p>
<a href="{{AppURL}}/{{.Doer.LowerName}}">@{{.Doer.Name}}</a>
{{if not (eq .Doer.FullName "")}}
({{.Doer.FullName}})
{{end}}
{{if eq .ActionName "new"}}
created
{{else if eq .ActionName "close"}}
closed
{{else if eq .ActionName "reopen"}}
reopened
{{else}}
updated
{{end}}
<a href="{{.Link}}">{{.Repo}}#{{.Issue.Index}}</a>.
</p>
{{if not (eq .Body "")}}
<h3>Message content:</h3>
<hr>
{{.Body | Str2html}}
{{end}}
</p>
<hr>
<p>
<a href="{{.Link}}">View it on Gitea</a>.
</p>
</body>
</html>
```
This template produces something along these lines:
#### Subject
> [mike/stuff] @rhonda commented on pull request #38: New color palette
#### Mail body
> [@rhonda](#) (Rhonda Myers) updated [mike/stuff#38](#).
>
> #### Message content:
>
> \__________________________________________________________________
>
> Mike, I think we should tone down the blues a little.
> \__________________________________________________________________
>
> [View it on Gitea](#).
## Advanced
The template system contains several functions that can be used to further process and format
the messages. Here's a list of some of them:
| Name | Parameters | Available | Usage |
|----------------------|-------------|-----------|------------------------------------------------------------------------------|
| `AppUrl` | - | Any | Gitea's URL |
| `AppName` | - | Any | Set from `app.ini`, usually "Gitea" |
| `AppDomain` | - | Any | Gitea's host name |
| `EllipsisString` | string, int | Any | Truncates a string to the specified length; adds ellipsis as needed |
| `Str2html` | string | Body only | Sanitizes text by removing any HTML tags from it. |
| `Safe` | string | Body only | Takes the input as HTML; can be used for `.ReviewComments.RenderedContent`. |
These are _functions_, not metadata, so they have to be used:
```
Like this: {{Str2html "Escape<my>text"}}
Or this: {{"Escape<my>text" | Str2html}}
Or this: {{AppUrl}}
But not like this: {{.AppUrl}}
```

View File

@@ -1,80 +0,0 @@
---
date: "2019-04-15T17:29:00+08:00"
title: "Advanced: Migrations Interfaces"
slug: "migrations-interfaces"
weight: 30
toc: true
draft: false
menu:
sidebar:
parent: "advanced"
name: "Migrations Interfaces"
weight: 55
identifier: "migrations-interfaces"
---
# Migration Features
The new migration features were introduced in Gitea 1.9.0. It defines two interfaces to support migrating
repositories data from other git host platforms to gitea or, in the future migrating gitea data to other
git host platforms. Currently, only the migrations from github via APIv3 to Gitea is implemented.
First of all, Gitea defines some standard objects in packages `modules/migrations/base`. They are
`Repository`, `Milestone`, `Release`, `Label`, `Issue`, `Comment`, `PullRequest`, `Reaction`, `Review`, `ReviewComment`.
## Downloader Interfaces
To migrate from a new git host platform, there are two steps to be updated.
- You should implement a `Downloader` which will get all kinds of repository informations.
- You should implement a `DownloaderFactory` which is used to detect if the URL matches and
create a Downloader.
- You'll need to register the `DownloaderFactory` via `RegisterDownloaderFactory` on init.
```Go
type Downloader interface {
SetContext(context.Context)
GetRepoInfo() (*Repository, error)
GetTopics() ([]string, error)
GetMilestones() ([]*Milestone, error)
GetReleases() ([]*Release, error)
GetLabels() ([]*Label, error)
GetIssues(page, perPage int) ([]*Issue, bool, error)
GetComments(issueNumber int64) ([]*Comment, error)
GetPullRequests(page, perPage int) ([]*PullRequest, error)
GetReviews(pullRequestNumber int64) ([]*Review, error)
}
```
```Go
type DownloaderFactory interface {
Match(opts MigrateOptions) (bool, error)
New(opts MigrateOptions) (Downloader, error)
}
```
## Uploader Interface
Currently, only a `GiteaLocalUploader` is implemented, so we only save downloaded
data via this `Uploader` on the local Gitea instance. Other uploaders are not supported
and will be implemented in future.
```Go
// Uploader uploads all the informations
type Uploader interface {
MaxBatchInsertSize(tp string) int
CreateRepo(repo *Repository, opts MigrateOptions) error
CreateTopics(topic ...string) error
CreateMilestones(milestones ...*Milestone) error
CreateReleases(releases ...*Release) error
SyncTags() error
CreateLabels(labels ...*Label) error
CreateIssues(issues ...*Issue) error
CreateComments(comments ...*Comment) error
CreatePullRequests(prs ...*PullRequest) error
CreateReviews(reviews ...*Review) error
Rollback() error
Close()
}
```

View File

@@ -1,92 +0,0 @@
---
date: "2019-04-19:44:00+01:00"
title: "OAuth2 provider"
slug: "oauth2-provider"
weight: 41
toc: true
draft: false
menu:
sidebar:
parent: "advanced"
name: "OAuth2 Provider"
weight: 41
identifier: "oauth2-provider"
---
# OAuth2 provider
Gitea supports acting as an OAuth2 provider to allow third party applications to access its resources with the user's consent. This feature is available since release 1.8.0.
## Endpoints
Endpoint | URL
-----------------------|----------------------------
Authorization Endpoint | `/login/oauth/authorize`
Access Token Endpoint | `/login/oauth/access_token`
## Supported OAuth2 Grants
At the moment Gitea only supports the [**Authorization Code Grant**](https://tools.ietf.org/html/rfc6749#section-1.3.1) standard with additional support of the [Proof Key for Code Exchange (PKCE)](https://tools.ietf.org/html/rfc7636) extension.
To use the Authorization Code Grant as a third party application it is required to register a new application via the "Settings" (`/user/settings/applications`) section of the settings.
## Scopes
Currently Gitea does not support scopes (see [#4300](https://github.com/go-gitea/gitea/issues/4300)) and all third party applications will be granted access to all resources of the user and his/her organizations.
## Example
**Note:** This example does not use PKCE.
1. Redirect to user to the authorization endpoint in order to get his/her consent for accessing the resources:
```curl
https://[YOUR-GITEA-URL]/login/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI& response_type=code&state=STATE
```
The `CLIENT_ID` can be obtained by registering an application in the settings. The `STATE` is a random string that will be send back to your application after the user authorizes. The `state` parameter is optional but should be used to prevent CSRF attacks.
![Authorization Page](/authorize.png)
The user will now be asked to authorize your application. If they authorize it, the user will be redirected to the `REDIRECT_URL`, for example:
```curl
https://[REDIRECT_URI]?code=RETURNED_CODE&state=STATE
```
2. Using the provided `code` from the redirect, you can request a new application and refresh token. The access token endpoints accepts POST requests with `application/json` and `application/x-www-form-urlencoded` body, for example:
```curl
POST https://[YOUR-GITEA-URL]/login/oauth/access_token
```
```json
{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"code": "RETURNED_CODE",
"grant_type": "authorization_code",
"redirect_uri": "REDIRECT_URI"
}
```
Response:
```json
{
"access_token":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJnbnQiOjIsInR0IjowLCJleHAiOjE1NTUxNzk5MTIsImlhdCI6MTU1NTE3NjMxMn0.0-iFsAwBtxuckA0sNZ6QpBQmywVPz129u75vOM7wPJecw5wqGyBkmstfJHAjEOqrAf_V5Z-1QYeCh_Cz4RiKug",
"token_type":"bearer",
"expires_in":3600,
"refresh_token":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJnbnQiOjIsInR0IjoxLCJjbnQiOjEsImV4cCI6MTU1NzgwNDMxMiwiaWF0IjoxNTU1MTc2MzEyfQ.S_HZQBy4q9r5SEzNGNIoFClT43HPNDbUdHH-GYNYYdkRfft6XptJBkUQscZsGxOW975Yk6RbgtGvq1nkEcklOw"
}
```
The `CLIENT_SECRET` is the unique secret code generated for this application. Please note that the secret will only be visible after you created/registered the application with Gitea and cannot be recovered. If you lose the secret you must regenerate the secret via the application's settings.
The `REDIRECT_URI` in the `access_token` request must match the `REDIRECT_URI` in the `authorize` request.
3. Use the `access_token` to make [API requests](https://docs.gitea.io/en-us/api-usage#oauth2) to access the user's resources.

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