Compare commits

...

81 Commits

Author SHA1 Message Date
Thomas Boerger
e2c8d6fcb2 [1.0] Added 1.0.2 to changelog (#1000)
* Added 1.0.2 to changelog

* Raised version to 1.0.2
2017-02-21 22:39:30 +08:00
Bo-Yi Wu
1a5df9e822 Security: fix XSS attack on alert (#981) 2017-02-19 22:20:15 +08:00
Lunny Xiao
21dc5996a5 Security: fix XSS attack on milestone (#977) 2017-02-19 19:09:32 +08:00
Lunny Xiao
023a6604e2 Handle SetModel error, fixes one errcheck report (#257) (#957) 2017-02-19 10:11:59 +08:00
Lunny Xiao
9a5009a2cc fix docker link on install page (#964) (#972) 2017-02-19 10:11:40 +08:00
Lunny Xiao
3121a7a037 Remove the default console logger when it is not set in the configuration (#602) (#960)
* Remove the default console logger when it is not set in the configuration

* Added comment to new function (lint failure)

* update based on PR comments (code style)

* code style fix (thanks bkcsoft)

* check if logger exists based on the l.outputs (like in l.DelLogger) instead of adapter, otherwise panic when reinstalling gitea (since the output adapter still exist, without outputs)
2017-02-18 22:25:28 +08:00
Lunny Xiao
61cdc32496 fixed bugs on Wiki and resolved #667 (#674) (#958) 2017-02-16 19:32:39 +08:00
Lunny Xiao
5fcf218ed9 Add data directory excluding sessions to dump (#587) (#959) 2017-02-16 17:30:28 +08:00
Lunny Xiao
91836614cd Security: prevent XSS attach on wiki page (#955)
Reported by Miguel Ángel Jimeno.
2017-02-16 17:02:15 +08:00
Lunny Xiao
ab4eb0daf9 bug fixed for issue count (#882) 2017-02-09 18:36:01 +08:00
Thomas Boerger
155fb93b9b Added 1.0.1 to changelog (#595)
(cherry picked from commit 0ac40cc69415aa437026f94f5f075f43dcfc3810)
2017-01-05 21:13:52 +08:00
Thomas Boerger
3a8c792303 Clone tags within drone for proper version generation (#591) (#593)
(cherry picked from commit 2d17d6bc16)
2017-01-05 19:34:59 +08:00
Lunny Xiao
807c64800c fix config session missing data row & resolved #517 (#578) 2017-01-05 08:49:49 +08:00
Lunny Xiao
6ddb2dcd57 change the default action when deleting a release to not delete tag (#579) 2017-01-05 08:49:43 +08:00
Lunny Xiao
729ab80065 resolved #517: fix admin ui data row missing (#580) 2017-01-05 08:49:32 +08:00
Lunny Xiao
a5ea9b4f30 fix installation page ssh domain unavilable (#506) 2017-01-04 14:40:44 +01:00
Lunny Xiao
8f08ccdb9f bug fixed for fork repos (#563) 2017-01-03 12:40:58 +08:00
Lunny Xiao
10d73d38e0 resolved #485: when migrate empty wiki repo, then ignore (#544) 2016-12-31 18:36:41 +08:00
Lunny Xiao
fbb424c61d fix 500 when delete orgnization and resolved #486 (#507) 2016-12-28 08:53:17 +08:00
Bwko
e8bac94d1f At the locales replaced 6 with MIN_PASSWORD_LENGTH (#501) 2016-12-27 18:44:49 +08:00
Matthias Loibl
99c6556ff3 Don't trim trailing whitespaces for markdown (#467) 2016-12-24 09:35:37 +08:00
Thomas Boerger
6aacf4d2f0 Properly handle drone tags and release/* branches (#466) 2016-12-24 00:00:48 +01:00
Thomas Boerger
7b67347104 Fixed drone tagging 2016-12-23 19:51:39 +01:00
Lunny Xiao
b0c6217c4d Fix broken godoc link and add arch in English README (#463)
* fix broken godoc link and add arch in English README

* typo
2016-12-23 22:57:18 +08:00
Lunny Xiao
eaa7b3c3f5 update zh readme (#462) 2016-12-23 22:39:24 +08:00
Thomas Boerger
770e8310bd Simplified README and added a release badge (#460)
* Dropped the status from readme, it's anway always outdated

* Added version badge

* Cleaned the install instructions

* Dropped paragraphs that should be documented on the docs

* Simplified the content, refer to the website

* Dropped the logo, lets show screenshots

* Fixed TRANSLATORS link
2016-12-23 15:05:24 +01:00
Thomas Boerger
1e6dd98d51 Integrated an initial changelog (#457) 2016-12-23 13:06:43 +01:00
Lunny Xiao
a822bba3e1 Add default values for settings (#455)
* add default values for settings

* more default values

* more default settings and labels resource

* mv locale to options
2016-12-23 15:18:05 +08:00
Ethan Koenig
ec1fe1183d Fix race condition in unit test (#456) 2016-12-23 14:31:22 +08:00
Joubert RedRat
dfb547099d Change screenshoots to Gitea (#454) 2016-12-23 07:25:55 +01:00
Lunny Xiao
a12da66dfb resolved #394 (#396) 2016-12-23 01:26:01 +01:00
Thomas Boerger
b33078fa33 Bindata is optional and over-writable on restart (#354)
* Moved conf assets into options folder

* Dropped old bindata

* Started to integrate options bindata and accessors

* Do not enforce a builtin app.ini

* Replaced bindata calls with options

* Dropped bindata task from makefile, it's the generate task now

* Always embedd app.ini to provide sane config defaults

* Use sane defaults for the configuration

* Defined default value for SSH_KEYGEN_PATH

* Dropped "NEVER EVER MODIFY THIS FILE" header from app.ini

* Fixed new paths in latest test additions

* Drop bindata with make clean task

* Set more proper default values
2016-12-22 19:12:23 +01:00
Lunny Xiao
c21e2c4151 fix tag webhook 404 error (#420) 2016-12-22 22:57:48 +08:00
Lunny Xiao
0e1392501d Check if file is a symlink with web editor (#3687) (#445)
* Check if file is a symlink with web editor (#3687)

* editor checks for symlinks

* translate file_is_a_symlink message

* credit translation author

* fix error constant
2016-12-22 13:27:32 +01:00
Lunny Xiao
e0ecd9fd93 fix bug #1122 log.smtp receiver configure error (#3602) (#451) 2016-12-22 13:27:13 +01:00
Lunny Xiao
65b1875d2b New settings option for a custom SSH host (#3763) (#446)
* New settings option for a custom SSH host (#3763)

* let default ssh listen addr empty
2016-12-22 13:26:43 +01:00
Lunny Xiao
11df7ebfc5 init script gentoo (#447)
* init script for gentoo (#3761)

* replace Gogs to Gitea

* remove override port number

* remove port
2016-12-22 10:39:17 +01:00
Lunny Xiao
47a7529d96 update code.gitea.io/git (#450) 2016-12-22 10:30:52 +01:00
Lunny Xiao
0c5c34d7dd UpdateIssueUsersByMentions was calling database write operations while (#443)
a transaction session was in progress. MailParticipants was failing
silently because of the SQLITE_LOCKED error. Make sure failures in
MailParticipants enter the log, and pass on the transaction context.

issue: let caller pass in database context, and use it
issue_comment: obtain database context to pass to UpdateIssueMentions
issue_comment: log any error from call to MailParticipants
issue_mail: pass on database context to UpdateIssueMentions
2016-12-22 17:00:39 +08:00
Ethan Koenig
4c89a9c33c Bug fixes and tests for modules/base (#442)
Also address other TODOs
2016-12-22 16:58:04 +08:00
Kim "BKC" Carlbäcker
df7fa4e995 issue comment api fix (#449)
* ListAllInRepo & Delete Issue-Comments

* Moar data in issue-comments
2016-12-22 16:29:26 +08:00
Alexander Lunegov
d5d21b67d2 Fix string format verbs (#3637) 2016-12-22 08:18:41 +01:00
Lunny Xiao
c46eb3f5b3 Fix homepage docs link broken (#417)
* fix homepage docs link broken

* fix homepage docs links after docs updated
2016-12-22 07:03:43 +01:00
Lunny Xiao
f8d94cb440 Update locales (#440)
* Update locales

* replace Gogs to Gitea
2016-12-21 23:28:42 +08:00
Lunny Xiao
2197d298cb Add Korean support (#437)
* Add Korean support

* replace Gogs to Gitea
2016-12-21 15:47:26 +01:00
Joubert RedRat
ce21ed6c34 Remove remaining Gogs reference on locales and cmd (#430) 2016-12-21 20:13:17 +08:00
Thomas Boerger
618407c018 Do not override the binary version name from drone (#436)
Signed-off-by: Thomas Boerger <tboerger@suse.de>
2016-12-21 20:00:15 +08:00
Andrey Nering
111c95ecaf Change default Android theme color meta tag (#389) 2016-12-20 21:54:22 +08:00
Andrey Nering
235eb4c3d2 Merge pull request #412 from strk/libravatar-source
Add support for using "libravatar" as the GravatarSource
2016-12-20 10:32:45 -02:00
Denis Denisov
380e32e129 Fix random string generator (#384)
* Remove unused custom-alphabet feature of random string generator

Fix random string generator

Random string generator should return error if it fails to read random data via crypto/rand

* Fixes variable (un)initialization mixed assign
Update test GetRandomString
2016-12-20 13:32:02 +01:00
Andrey Nering
952587dbae Merge pull request #422 from mjwwit/master
Change test mail subject and body to 'Gitea Test Mail!'
2016-12-20 10:15:03 -02:00
Michael de Wit
1d30457a94 change test mail subject and body to 'Gitea Test Mail!'
Signed-off-by: Michael de Wit <mjwwit@gmail.com>
2016-12-20 09:34:50 +01:00
Nico Mandery
6ade13e86e serve video files using the HTML5 video tag (#418)
* serve video files using the HTML5 video tag

* lint fix: add comment to IsVideoFile
2016-12-20 16:09:11 +08:00
Sandro Santilli
608a60fb94 Add support for using "libravatar" as the GravatarSource
Just to make it easier for administrator to configure libre avatar,
as it is done for "duoshuo" and "gravatar"
2016-12-19 17:05:30 +01:00
Lunny Xiao
8559d6f267 add ZH readme (#405) 2016-12-19 21:30:52 +08:00
Lunny Xiao
7c46667e71 fixed vulnerabilities labels (#409) 2016-12-17 19:49:17 +08:00
Richie B2B
44428fdc38 Remove fixed FIXME (#408) 2016-12-16 17:00:30 +01:00
Richie B2B
0d6e88baef Fix typo (#407) 2016-12-16 17:00:15 +01:00
Martin Hebnes Pedersen
b11843b8dc Update gitea/sdk vendor (#406) 2016-12-16 16:26:35 +01:00
Andrey Nering
578a8e258e Revert "Disable coverage report for now" (#400) 2016-12-16 12:49:54 +01:00
Lunny Xiao
15c3d14d55 fixed vulnerabilities on deleting release (#399) 2016-12-16 19:42:39 +08:00
Thomas Boerger
8aeeed0a23 Disable coverage report for now (#395)
Until aircover gets updated so that it works again I have disabled to
coverage report upload for now.
2016-12-15 12:26:34 +01:00
Thomas Boerger
c6b6a61bf1 Fixing multiple docker issues (#386)
* Added stupid docker task to makefile

* Dropped unknown option PrintLastLog from docker ssh config

* OpenSSH should log to docker stdout

* Set random pw for docker git user, otherwise it is locked

* Stop using templates and public within docker
2016-12-15 17:16:55 +08:00
Sandro Santilli
1831ee2d1d Update example install url from try.gogs.io to try.gitea.io (#385)
* Update example install url from try.gogs.io to try.gitea.io

* Ask if issue can be reproduced on try.gitea.io

* Link try.gitea.io to the README
2016-12-15 16:56:46 +08:00
Lunny Xiao
b4c794058a fixed vulnerabilities (#392) 2016-12-15 16:49:06 +08:00
Lunny Xiao
d771e978a1 Don't use custom PBKDF2 function (#382) 2016-12-15 09:24:27 +08:00
Lunny Xiao
73710c00a8 bug fixed branch name for pushupdate (#380) 2016-12-13 15:19:42 +08:00
Kim "BKC" Carlbäcker
1d1c01875d Autogenerate Version on build (#190)
* Autogenerate Version On Build

* Fixes

* Changed Version to v0.9.0

* balls

* I hate newlines

* Don't remove .VERSION-file on `make clean`

* v0.9.0 => 1.0.0

* damn new-lines...

* Always rebuild templates/.VERSION

* Delete .VERSION

* Update Makefile
2016-12-13 12:48:58 +08:00
Denis Denisov
f0a989c1d0 Correction LDAP validation (#342)
* Correction LDAP username validation

As https://msdn.microsoft.com/en-us/library/aa366101(v=vs.85).aspx describe spaces should not be in start or at the end of username but they can be inside the username. So please check my solution for it.

* Check for zero length passwords in LDAP module.

According to https://tools.ietf.org/search/rfc4513#section-5.1.2 LDAP client should always check before bind whether a password is an empty value. There are at least one LDAP implementation which does not return error if you try to bind with DN set and empty password - AD.

* Clearing the login/email spaces at the [start/end]
2016-12-12 08:46:51 +08:00
Bwko
abcd39f7d5 In the wiki title replace tab with a space (#371) 2016-12-11 11:01:26 +08:00
Bwko
cbcb4361d5 Fixes issue #283
Delete old temp local copy before we create a new temp local copy
2016-12-09 20:13:48 +01:00
Ethan Koenig
7b5b5178e1 Bug fix for edit-hook API endpoint 2016-12-09 20:11:56 +01:00
Henning Henkel
bab737bf02 Fix alignment of tooltip and add bindata - related to #359 (#364) 2016-12-08 20:59:47 +08:00
Ethan Koenig
401a8db0ed Remove stale comment in models/repo.go (#366) 2016-12-08 00:04:12 +01:00
Bwko
39d0db52de Fix for #361, renamed username to login 2016-12-07 15:56:43 +01:00
Ethan Koenig
04b9a7e7a2 Bug fixes for repo permissions in API
Also move duplicated code into repo.APIFormat(..)
2016-12-07 12:55:24 +01:00
Henning Henkel
08b9af9ad8 Added download tooltip - solves #221 (#359) 2016-12-07 09:38:20 +01:00
Bwko
026ad4aee7 Fixes panic when there's no user initialized (#358) 2016-12-06 21:58:34 +01:00
Thomas Boerger
83ed234472 Integrate templates into bindata optionally (#314)
Integrated optional bindata for the templates
2016-12-06 18:58:31 +01:00
Kim "BKC" Carlbäcker
1b5b297c39 Actually fix 'make build' (#353)
* Actually fix bloddy 'make build'
2016-12-05 18:35:22 +01:00
Thomas Boerger
2b63f32b8a Enabled bindata build tag and generate bindata (#352) 2016-12-05 23:39:45 +08:00
346 changed files with 3581 additions and 6426 deletions

View File

@@ -3,16 +3,21 @@ workspace:
path: src/code.gitea.io/gitea
pipeline:
clone:
image: plugins/git
tags: true
test:
image: webhippie/golang:edge
pull: true
environment:
CGO_ENABLED: 1
TAGS: sqlite
TAGS: sqlite bindata
GOPATH: /srv/app
commands:
- apk -U add openssh-client
- make clean
- make generate
- make vet
- make lint
- make test
@@ -25,7 +30,7 @@ pipeline:
pull: true
environment:
CGO_ENABLED: 1
TAGS: sqlite
TAGS: sqlite bindata
GOPATH: /srv/app
commands:
- make test-mysql
@@ -37,7 +42,7 @@ pipeline:
pull: true
environment:
CGO_ENABLED: 1
TAGS: sqlite
TAGS: sqlite bindata
GOPATH: /srv/app
commands:
- make test-pgsql
@@ -49,13 +54,13 @@ pipeline:
pull: true
environment:
CGO_ENABLED: 1
TAGS: sqlite
TAGS: sqlite bindata
GOPATH: /srv/app
commands:
- make release
when:
event: [ push, tag ]
branch: [ master, refs/tags/* ]
branch: [ master, release/*, refs/tags/* ]
coverage:
image: plugins/coverage
@@ -66,11 +71,19 @@ pipeline:
docker:
image: plugins/docker
repo: gitea/gitea
tags: [ '${TAG}' ]
tags: [ '${DRONE_TAG##v}' ]
when:
event: [ tag ]
branch: [ refs/tags/* ]
docker:
image: plugins/docker
repo: gitea/gitea
tags: [ '${DRONE_BRANCH##release/v}' ]
when:
event: [ push ]
branch: [ release/* ]
docker:
image: plugins/docker
repo: gitea/gitea
@@ -84,20 +97,30 @@ pipeline:
path_style: true
strip_prefix: dist/release/
source: dist/release/*
target: /gitea/master
target: /gitea/${DRONE_TAG##v}
when:
event: [ push ]
branch: [ master ]
event: [ tag ]
branch: [ refs/tags/* ]
release:
image: plugins/s3
path_style: true
strip_prefix: dist/release/
source: dist/release/*
target: /gitea/$$TAG
target: /gitea/${DRONE_BRANCH##release/v}
when:
event: [ tag ]
branch: [ refs/tags/* ]
event: [ push ]
branch: [ release/* ]
release:
image: plugins/s3
path_style: true
strip_prefix: dist/release/
source: dist/release/*
target: /gitea/master
when:
event: [ push ]
branch: [ master ]
github:
image: plugins/github-release

View File

@@ -1 +1 @@
eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9zcnYvYXBwCiAgcGF0aDogc3JjL2NvZGUuZ2l0ZWEuaW8vZ2l0ZWEKCnBpcGVsaW5lOgogIHRlc3Q6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgQ0dPX0VOQUJMRUQ6IDEKICAgICAgVEFHUzogc3FsaXRlCiAgICAgIEdPUEFUSDogL3Nydi9hcHAKICAgIGNvbW1hbmRzOgogICAgICAtIGFwayAtVSBhZGQgb3BlbnNzaC1jbGllbnQKICAgICAgLSBtYWtlIGNsZWFuCiAgICAgIC0gbWFrZSB2ZXQKICAgICAgLSBtYWtlIGxpbnQKICAgICAgLSBtYWtlIHRlc3QKICAgICAgLSBtYWtlIGJ1aWxkCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIHRlc3QtbXlzcWw6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgQ0dPX0VOQUJMRUQ6IDEKICAgICAgVEFHUzogc3FsaXRlCiAgICAgIEdPUEFUSDogL3Nydi9hcHAKICAgIGNvbW1hbmRzOgogICAgICAtIG1ha2UgdGVzdC1teXNxbAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCgogIHRlc3QtcGdzcWw6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgQ0dPX0VOQUJMRUQ6IDEKICAgICAgVEFHUzogc3FsaXRlCiAgICAgIEdPUEFUSDogL3Nydi9hcHAKICAgIGNvbW1hbmRzOgogICAgICAtIG1ha2UgdGVzdC1wZ3NxbAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCgogIHVwZGF0ZXI6CiAgICBpbWFnZToga2FyYWxhYmUveGdvLWxhdGVzdDpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGVudmlyb25tZW50OgogICAgICBDR09fRU5BQkxFRDogMQogICAgICBUQUdTOiBzcWxpdGUKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gbWFrZSByZWxlYXNlCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcgXQogICAgICBicmFuY2g6IFsgbWFzdGVyLCByZWZzL3RhZ3MvKiBdCgogIGNvdmVyYWdlOgogICAgaW1hZ2U6IHBsdWdpbnMvY292ZXJhZ2UKICAgIHNlcnZlcjogaHR0cHM6Ly9jb3ZlcmFnZS5naXRlYS5pbwogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICBkb2NrZXI6CiAgICBpbWFnZTogcGx1Z2lucy9kb2NrZXIKICAgIHJlcG86IGdpdGVhL2dpdGVhCiAgICB0YWdzOiBbICcke1RBR30nIF0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHRhZyBdCiAgICAgIGJyYW5jaDogWyByZWZzL3RhZ3MvKiBdCgogIGRvY2tlcjoKICAgIGltYWdlOiBwbHVnaW5zL2RvY2tlcgogICAgcmVwbzogZ2l0ZWEvZ2l0ZWEKICAgIHRhZ3M6IFsgJ2xhdGVzdCcgXQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCiAgICAgIGJyYW5jaDogWyBtYXN0ZXIgXQoKICByZWxlYXNlOgogICAgaW1hZ2U6IHBsdWdpbnMvczMKICAgIHBhdGhfc3R5bGU6IHRydWUKICAgIHN0cmlwX3ByZWZpeDogZGlzdC9yZWxlYXNlLwogICAgc291cmNlOiBkaXN0L3JlbGVhc2UvKgogICAgdGFyZ2V0OiAvZ2l0ZWEvbWFzdGVyCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIG1hc3RlciBdCgogIHJlbGVhc2U6CiAgICBpbWFnZTogcGx1Z2lucy9zMwogICAgcGF0aF9zdHlsZTogdHJ1ZQogICAgc3RyaXBfcHJlZml4OiBkaXN0L3JlbGVhc2UvCiAgICBzb3VyY2U6IGRpc3QvcmVsZWFzZS8qCiAgICB0YXJnZXQ6IC9naXRlYS8kJFRBRwogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgdGFnIF0KICAgICAgYnJhbmNoOiBbIHJlZnMvdGFncy8qIF0KCiAgZ2l0aHViOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0aHViLXJlbGVhc2UKICAgIGZpbGVzOgogICAgICAtIGRpc3QvcmVsZWFzZS8qCiAgICB3aGVuOgogICAgICBldmVudDogWyB0YWcgXQogICAgICBicmFuY2g6IFsgcmVmcy90YWdzLyogXQoKICBnaXR0ZXI6CiAgICBpbWFnZTogcGx1Z2lucy9naXR0ZXIKCnNlcnZpY2VzOgogIG15c3FsOgogICAgaW1hZ2U6IG15c3FsOjUuNwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gTVlTUUxfREFUQUJBU0U9dGVzdAogICAgICAtIE1ZU1FMX0FMTE9XX0VNUFRZX1BBU1NXT1JEPXllcwogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCgogIHBnc3FsOgogICAgaW1hZ2U6IHBvc3RncmVzOjkuNQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfREI9dGVzdAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCg.LjU9u_DQ4fD2CytUu9RwwSimdcS3-KzR6nO4ff4edNU
eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9zcnYvYXBwCiAgcGF0aDogc3JjL2NvZGUuZ2l0ZWEuaW8vZ2l0ZWEKCnBpcGVsaW5lOgogIGNsb25lOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0CiAgICB0YWdzOiB0cnVlCgogIHRlc3Q6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgQ0dPX0VOQUJMRUQ6IDEKICAgICAgVEFHUzogc3FsaXRlIGJpbmRhdGEKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gYXBrIC1VIGFkZCBvcGVuc3NoLWNsaWVudAogICAgICAtIG1ha2UgY2xlYW4KICAgICAgLSBtYWtlIGdlbmVyYXRlCiAgICAgIC0gbWFrZSB2ZXQKICAgICAgLSBtYWtlIGxpbnQKICAgICAgLSBtYWtlIHRlc3QKICAgICAgLSBtYWtlIGJ1aWxkCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIHRlc3QtbXlzcWw6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgQ0dPX0VOQUJMRUQ6IDEKICAgICAgVEFHUzogc3FsaXRlIGJpbmRhdGEKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gbWFrZSB0ZXN0LW15c3FsCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KCiAgdGVzdC1wZ3NxbDoKICAgIGltYWdlOiB3ZWJoaXBwaWUvZ29sYW5nOmVkZ2UKICAgIHB1bGw6IHRydWUKICAgIGVudmlyb25tZW50OgogICAgICBDR09fRU5BQkxFRDogMQogICAgICBUQUdTOiBzcWxpdGUgYmluZGF0YQogICAgICBHT1BBVEg6IC9zcnYvYXBwCiAgICBjb21tYW5kczoKICAgICAgLSBtYWtlIHRlc3QtcGdzcWwKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQoKICB1cGRhdGVyOgogICAgaW1hZ2U6IGthcmFsYWJlL3hnby1sYXRlc3Q6bGF0ZXN0CiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgQ0dPX0VOQUJMRUQ6IDEKICAgICAgVEFHUzogc3FsaXRlIGJpbmRhdGEKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gbWFrZSByZWxlYXNlCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcgXQogICAgICBicmFuY2g6IFsgbWFzdGVyLCByZWxlYXNlLyosIHJlZnMvdGFncy8qIF0KCiAgY292ZXJhZ2U6CiAgICBpbWFnZTogcGx1Z2lucy9jb3ZlcmFnZQogICAgc2VydmVyOiBodHRwczovL2NvdmVyYWdlLmdpdGVhLmlvCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIGRvY2tlcjoKICAgIGltYWdlOiBwbHVnaW5zL2RvY2tlcgogICAgcmVwbzogZ2l0ZWEvZ2l0ZWEKICAgIHRhZ3M6IFsgJyR7RFJPTkVfVEFHIyN2fScgXQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgdGFnIF0KICAgICAgYnJhbmNoOiBbIHJlZnMvdGFncy8qIF0KCiAgZG9ja2VyOgogICAgaW1hZ2U6IHBsdWdpbnMvZG9ja2VyCiAgICByZXBvOiBnaXRlYS9naXRlYQogICAgdGFnczogWyAnJHtEUk9ORV9CUkFOQ0gjI3JlbGVhc2Uvdn0nIF0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQogICAgICBicmFuY2g6IFsgcmVsZWFzZS8qIF0KCiAgZG9ja2VyOgogICAgaW1hZ2U6IHBsdWdpbnMvZG9ja2VyCiAgICByZXBvOiBnaXRlYS9naXRlYQogICAgdGFnczogWyAnbGF0ZXN0JyBdCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIG1hc3RlciBdCgogIHJlbGVhc2U6CiAgICBpbWFnZTogcGx1Z2lucy9zMwogICAgcGF0aF9zdHlsZTogdHJ1ZQogICAgc3RyaXBfcHJlZml4OiBkaXN0L3JlbGVhc2UvCiAgICBzb3VyY2U6IGRpc3QvcmVsZWFzZS8qCiAgICB0YXJnZXQ6IC9naXRlYS8ke0RST05FX1RBRyMjdn0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHRhZyBdCiAgICAgIGJyYW5jaDogWyByZWZzL3RhZ3MvKiBdCgogIHJlbGVhc2U6CiAgICBpbWFnZTogcGx1Z2lucy9zMwogICAgcGF0aF9zdHlsZTogdHJ1ZQogICAgc3RyaXBfcHJlZml4OiBkaXN0L3JlbGVhc2UvCiAgICBzb3VyY2U6IGRpc3QvcmVsZWFzZS8qCiAgICB0YXJnZXQ6IC9naXRlYS8ke0RST05FX0JSQU5DSCMjcmVsZWFzZS92fQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCiAgICAgIGJyYW5jaDogWyByZWxlYXNlLyogXQoKICByZWxlYXNlOgogICAgaW1hZ2U6IHBsdWdpbnMvczMKICAgIHBhdGhfc3R5bGU6IHRydWUKICAgIHN0cmlwX3ByZWZpeDogZGlzdC9yZWxlYXNlLwogICAgc291cmNlOiBkaXN0L3JlbGVhc2UvKgogICAgdGFyZ2V0OiAvZ2l0ZWEvbWFzdGVyCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIG1hc3RlciBdCgogIGdpdGh1YjoKICAgIGltYWdlOiBwbHVnaW5zL2dpdGh1Yi1yZWxlYXNlCiAgICBmaWxlczoKICAgICAgLSBkaXN0L3JlbGVhc2UvKgogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgdGFnIF0KICAgICAgYnJhbmNoOiBbIHJlZnMvdGFncy8qIF0KCiAgZ2l0dGVyOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0dGVyCgpzZXJ2aWNlczoKICBteXNxbDoKICAgIGltYWdlOiBteXNxbDo1LjcKICAgIGVudmlyb25tZW50OgogICAgICAtIE1ZU1FMX0RBVEFCQVNFPXRlc3QKICAgICAgLSBNWVNRTF9BTExPV19FTVBUWV9QQVNTV09SRD15ZXMKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQoKICBwZ3NxbDoKICAgIGltYWdlOiBwb3N0Z3Jlczo5LjUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX0RCPXRlc3QKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQo.NGE3UiNBappXiPimJXv1DzgjT3k2hofGPsCPhw7KsSM

View File

@@ -25,3 +25,6 @@ indent_size = 4
[Makefile]
indent_style = tab
[*.md]
trim_trailing_whitespace = false

View File

@@ -12,6 +12,10 @@
- [ ] PostgreSQL
- [ ] MySQL
- [ ] SQLite
- Can you reproduce the bug at https://try.gitea.io:
- [ ] Yes (provide example URL)
- [ ] No
- [ ] Not relevant
- Log gist:
## Description

2
.gitignore vendored
View File

@@ -28,7 +28,9 @@ _testmain.go
coverage.out
/modules/options/bindata.go
/modules/public/bindata.go
/modules/templates/bindata.go
*.db
*.log

69
CHANGELOG.md Normal file
View File

@@ -0,0 +1,69 @@
# Changelog
## [1.0.2](https://github.com/go-gitea/gitea/releases/tag/v1.0.2) - 2017-02-21
* BUGFIXES
* Fixed issue counter [#882](https://github.com/go-gitea/gitea/pull/882)
* Fixed XSS vulnerability on wiki page [#955](https://github.com/go-gitea/gitea/pull/955)
* Add data dir without session to dump [#587](https://github.com/go-gitea/gitea/pull/587)
* Fixed wiki page renaming [#958](https://github.com/go-gitea/gitea/pull/958)
* Drop default console logger if not required [#960](https://github.com/go-gitea/gitea/pull/960)
* Fixed docker docs link on install page [#972](https://github.com/go-gitea/gitea/pull/972)
* Handle SetModel errors [#957](https://github.com/go-gitea/gitea/pull/957)
* Fixed XSS vulnerability on milestones [#977](https://github.com/go-gitea/gitea/pull/977)
* Fixed XSS vulnerability on alerts [#981](https://github.com/go-gitea/gitea/pull/981)
## [1.0.1](https://github.com/go-gitea/gitea/releases/tag/v1.0.1) - 2017-01-05
* BUGFIXES
* Fixed localized MIN_PASSWORD_LENGTH [#501](https://github.com/go-gitea/gitea/pull/501)
* Fixed 500 error on organization delete [#507](https://github.com/go-gitea/gitea/pull/507)
* Ignore empty wiki repo on migrate [#544](https://github.com/go-gitea/gitea/pull/544)
* Proper check access for forking [#563](https://github.com/go-gitea/gitea/pull/563)
* Fix SSH domain on installer [#506](https://github.com/go-gitea/gitea/pull/506)
* Fix missing data rows on admin UI [#580](https://github.com/go-gitea/gitea/pull/580)
* Do not delete tags with releases by default [#579](https://github.com/go-gitea/gitea/pull/579)
* Fix missing session config data on admin UI [#578](https://github.com/go-gitea/gitea/pull/578)
* Properly show the version within footer on the UI [#593](https://github.com/go-gitea/gitea/pull/593)
## [1.0.0](https://github.com/go-gitea/gitea/releases/tag/v1.0.0) - 2016-12-23
* BREAKING
* We have various changes on the API, scripting against API must be updated
* FEATURE
* Show last login for admins [#121](https://github.com/go-gitea/gitea/pull/121)
* BUGFIXES
* Fixed sender of notifications [#2](https://github.com/go-gitea/gitea/pull/2)
* Fixed keyword hijacking vulnerability [#20](https://github.com/go-gitea/gitea/pull/20)
* Fixed non-markdown readme rendering [#95](https://github.com/go-gitea/gitea/pull/95)
* Allow updating draft releases [#169](https://github.com/go-gitea/gitea/pull/169)
* GitHub API compliance [#227](https://github.com/go-gitea/gitea/pull/227)
* Added commit SHA to tag webhook [#286](https://github.com/go-gitea/gitea/issues/286)
* Secured links via noopener [#315](https://github.com/go-gitea/gitea/issues/315)
* Replace tabs with spaces on wiki title [#371](https://github.com/go-gitea/gitea/pull/371)
* Fixed vulnerability on labels and releases [#409](https://github.com/go-gitea/gitea/pull/409)
* Fixed issue comment API [#449](https://github.com/go-gitea/gitea/pull/449)
* ENHANCEMENT
* Use proper import path for libravatar [#3](https://github.com/go-gitea/gitea/pull/3)
* Integrated DroneCI for tests and builds [#24](https://github.com/go-gitea/gitea/issues/24)
* Integrated dependency manager [#29](https://github.com/go-gitea/gitea/issues/29)
* Embedded bindata optionally [#30](https://github.com/go-gitea/gitea/issues/30)
* Integrated pagination for releases [#73](https://github.com/go-gitea/gitea/pull/73)
* Autogenerate version on every build [#91](https://github.com/go-gitea/gitea/issues/91)
* Refactored Docker container [#104](https://github.com/go-gitea/gitea/issues/104)
* Added short-hash support for downloads [#211](https://github.com/go-gitea/gitea/issues/211)
* Display tooltip for downloads [#221](https://github.com/go-gitea/gitea/issues/221)
* Improved HTTP headers for issue attachments [#270](https://github.com/go-gitea/gitea/pull/270)
* Integrate public as bindata optionally [#293](https://github.com/go-gitea/gitea/pull/293)
* Integrate templates as bindata optionally [#314](https://github.com/go-gitea/gitea/pull/314)
* Inject more ENV variables into custom hooks [#316](https://github.com/go-gitea/gitea/issues/316)
* Correct LDAP login validation [#342](https://github.com/go-gitea/gitea/pull/342)
* Integrate conf as bindata optionally [#354](https://github.com/go-gitea/gitea/pull/354)
* Serve video files in browser [#418](https://github.com/go-gitea/gitea/pull/418)
* Configurable SSH host binding [#431](https://github.com/go-gitea/gitea/issues/431)
* MISC
* Forked from Gogs and renamed to Gitea
* Catching more errors with logs
* Fixed all linting errors
* Made the go linter entirely happy
* Really integrated vendoring

View File

@@ -26,7 +26,8 @@ RUN apk update && \
-s /bin/bash \
-u 1000 \
-G git \
git
git && \
echo "git:$(date +%s | sha256sum | base64 | head -c 32)" | chpasswd
ENV USER git
ENV GITEA_CUSTOM /data/gitea
@@ -38,7 +39,4 @@ ENTRYPOINT ["/usr/bin/entrypoint"]
CMD ["/bin/s6-svscan", "/etc/s6"]
COPY docker /
COPY public /app/gitea/public
COPY templates /app/gitea/templates
COPY gitea /app/gitea/gitea

View File

@@ -2,26 +2,23 @@ DIST := dist
EXECUTABLE := gitea
IMPORT := code.gitea.io/gitea
SHA := $(shell git rev-parse --short HEAD)
DATE := $(shell date -u '+%Y-%m-%d %I:%M:%S %Z')
BINDATA := $(shell find conf | sed 's/ /\\ /g')
BINDATA := modules/{options,public,templates}/bindata.go
STYLESHEETS := $(wildcard public/less/index.less public/less/_*.less)
JAVASCRIPTS :=
LDFLAGS += -X "code.gitea.io/gitea/modules/setting.BuildTime=$(DATE)"
LDFLAGS += -X "code.gitea.io/gitea/modules/setting.BuildGitHash=$(SHA)"
LDFLAGS += -X "main.Version=$(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')"
TARGETS ?= linux/*,darwin/*,windows/*
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
SOURCES ?= $(shell find . -name "*.go" -type f)
TAGS ?=
ifneq ($(DRONE_TAG),)
VERSION ?= $(DRONE_TAG)
VERSION ?= $(subst v,,$(DRONE_TAG))
else
ifneq ($(DRONE_BRANCH),)
VERSION ?= $(DRONE_BRANCH)
VERSION ?= $(subst release/v,,$(DRONE_BRANCH))
else
VERSION ?= master
endif
@@ -33,7 +30,7 @@ all: build
.PHONY: clean
clean:
go clean -i ./...
rm -rf $(EXECUTABLE) $(DIST)
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA)
.PHONY: fmt
fmt:
@@ -86,10 +83,14 @@ install: $(wildcard *.go)
.PHONY: build
build: $(EXECUTABLE)
.PHONY: $(EXECUTABLE)
$(EXECUTABLE): $(wildcard *.go)
$(EXECUTABLE): $(SOURCES)
go build -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
.PHONY: docker
docker:
docker run -ti --rm -v $(CURDIR):/srv/app/src/code.gitea.io/gitea -w /srv/app/src/code.gitea.io/gitea -e TAGS="$(TAGS)" webhippie/golang:edge make clean generate build
docker build -t gitea/gitea:latest .
.PHONY: release
release: release-dirs release-build release-copy release-check
@@ -115,19 +116,6 @@ release-copy:
release-check:
cd $(DIST)/release; $(foreach file,$(wildcard $(DIST)/release/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
.PHONY: bindata
bindata: modules/bindata/bindata.go
.IGNORE: modules/bindata/bindata.go
modules/bindata/bindata.go: $(BINDATA)
@which go-bindata > /dev/null; if [ $$? -ne 0 ]; then \
go get -u github.com/jteeuwen/go-bindata/...; \
fi
go-bindata -o=$@ -ignore="\\.go|README.md|TRANSLATORS" -pkg=bindata conf/...
go fmt $@
sed -i.bak 's/confLocaleLocale_/confLocaleLocale/' $@
rm $@.bak
.PHONY: javascripts
javascripts: public/js/index.js
@@ -143,4 +131,4 @@ public/css/index.css: $(STYLESHEETS)
lessc $< $@
.PHONY: assets
assets: bindata javascripts stylesheets
assets: javascripts stylesheets

124
README.md
View File

@@ -1,3 +1,5 @@
[简体中文](https://github.com/go-gitea/gitea/blob/master/README_ZH.md)
# Gitea - Git with a cup of tea
[![Build Status](http://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](http://drone.gitea.io/go-gitea/gitea)
@@ -6,122 +8,28 @@
[![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)
[![Release](http://github-release-version.herokuapp.com/github/go-gitea/gitea/release.svg?style=flat)](https://github.com/go-gitea/gitea/releases/latest)
[![](public/img/gitea-large-resize.png)](https://github.com/go-gitea/gitea)
##### Status
**Current version**: (see [Releases](https://github.com/go-gitea/gitea/releases))
| Web | UI | Preview |
||||
|:-------------:|:-------:|:-------:|
|![Dashboard](https://gogs.io/img/screenshots/1.png)|![Repository](https://gogs.io/img/screenshots/2.png)|![Commits History](https://gogs.io/img/screenshots/3.png)|
|![Profile](https://gogs.io/img/screenshots/4.png)|![Admin Dashboard](https://gogs.io/img/screenshots/5.png)|![Diff](https://gogs.io/img/screenshots/6.png)|
|![Issues](https://gogs.io/img/screenshots/7.png)|![Releases](https://gogs.io/img/screenshots/8.png)|![Organization](https://gogs.io/img/screenshots/9.png)|
### Important Notes
1. **YOU MUST READ THE [Contributors Guide](CONTRIBUTING.md) BEFORE STARTING TO WORK ON A PULL REQUEST**.
2. If you think there are vulnerabilities in the project, please talk privately to **security@gitea.io**. Thanks!
3. If you're interested in using APIs, we have experimental support with [documentation](https://godoc.org/github.com/go-gitea/go-sdk).
|![Dashboard](https://i.imgur.com/3iEQsux.jpg)|![Repository](https://i.imgur.com/glqFnj8.jpg)|![Commits History](https://i.imgur.com/ad1FEpi.jpg)|
|![Profile](https://i.imgur.com/q81EcGa.jpg)|![Admin Dashboard](https://i.imgur.com/L2CQeN0.jpg)|![Diff](https://i.imgur.com/cNuvMum.jpg)|
|![Issues](https://i.imgur.com/xCYRqaF.jpg)|![Releases](https://i.imgur.com/ILpRBCe.jpg)|![Organization](https://i.imgur.com/0BHnrcL.jpg)|
||||
## Purpose
The goal of this project is to make the easiest, fastest, and most painless way of setting up a self-hosted Git service. With Go, this can be done with an independent binary distribution across **ALL platforms** that Go supports, including Linux, Mac OS X, Windows and ARM.
The goal of this project is to make the easiest, fastest, and most painless way of setting up a self-hosted Git service. With Go, this can be done with an independent binary distribution across **all platforms** that Go supports, including Linux, macOS, and Windows on x86, amd64, ARM and PowerPC architectures. Want to try it before doing anything else? Do it [online](https://try.gitea.io/)!
## Features
## Notes
- Activity timeline
- SSH and HTTP/HTTPS protocols
- SMTP/LDAP/Reverse proxy authentication
- Reverse proxy with sub-path
- Account/Organization/Repository management
- Add/Remove repository collaborators
- Repository/Organization webhooks (including Slack)
- Repository Git hooks/deploy keys
- Repository issues, pull requests and wiki
- Migrate and mirror repository and its wiki
- Web editor for repository files and wiki
- Gravatar and Federated avatar with custom source
- Mail service
- Administration panel
- Supports MySQL, PostgreSQL, SQLite3 and [TiDB](https://github.com/pingcap/tidb) (experimental)
- Multi-language support ([20 languages](https://crowdin.com/project/gogs))
1. **YOU MUST READ THE [CONTRIBUTORS GUIDE](CONTRIBUTING.md) BEFORE STARTING TO WORK ON A PULL REQUEST.**
2. If you found a vulnerability in the project, please write privately to **security@gitea.io**. Thanks!
3. If you're interested in using our APIs, we have experimental support with [documentation](https://godoc.org/code.gitea.io/sdk/gitea).
## System Requirements
- A cheap Raspberry Pi is powerful enough for basic functionality.
- 2 CPU cores and 1GB RAM would be the baseline for teamwork.
## Browser Support
- Please see [Semantic UI](https://github.com/Semantic-Org/Semantic-UI#browser-support) for specific versions of supported browsers.
- The official support minimal size is **1024*768**, UI may still looks right in smaller size but no promises and fixes.
## Installation
**Note: As Gitea is a [Gogs](https://github.com/gogits/gogs) fork, tutorials and documentation related to gogs applies to Gitea too**
How to install Gitea:
- go get code.gitea.io/gitea
- [Ship with Docker](https://github.com/go-gitea/gitea/tree/master/docker)
- [Install with Vagrant](https://github.com/go-gitea/examples/tree/master/vagrant)
**Note: binary release will be available soon**
### Tutorials
- [How To Set Up Gogs on Ubuntu 14.04](https://www.digitalocean.com/community/tutorials/how-to-set-up-gogs-on-ubuntu-14-04)
- [Run your own GitHub-like service with the help of Docker](http://blog.hypriot.com/post/run-your-own-github-like-service-with-docker/)
- [Dockerized Gogs git server and alpine postgres in 20 minutes or less](http://garthwaite.org/docker-gogs.html)
- [Host Your Own Private GitHub with Gogs.io](https://eladnava.com/host-your-own-private-github-with-gogs-io/)
- [使用 Gogs 搭建自己的 Git 服务器](https://mynook.info/blog/post/host-your-own-git-server-using-gogs) (Chinese)
- [阿里云上 Ubuntu 14.04 64 位安装 Gogs](http://my.oschina.net/luyao/blog/375654) (Chinese)
- [Installing Gogs on FreeBSD](https://www.codejam.info/2015/03/installing-gogs-on-freebsd.html)
- [Gogs on Raspberry Pi](http://blog.meinside.pe.kr/Gogs-on-Raspberry-Pi/)
- [Cloudflare Full SSL with GOGS (Go Git Service) using NGINX](http://www.listekconsulting.com/articles/cloudflare-full-ssl-with-gogs-go-git-service-using-nginx/)
### Screencasts
- [How to install Gogs on a Linux Server (DigitalOcean)](https://www.youtube.com/watch?v=deSfX0gqefE)
- [Instalando Gogs no Ubuntu](https://www.youtube.com/watch?v=4UkHAR1F7ZA) (Português)
### Deploy to Cloud
- [OpenShift](https://github.com/tkisme/gogs-openshift)
- [Cloudron](https://cloudron.io/appstore.html#io.gogs.cloudronapp)
- [Scaleway](https://www.scaleway.com/imagehub/gogs/)
- [Portal](https://portaldemo.xyz/cloud/)
- [Sandstorm](https://github.com/cem/gogs-sandstorm)
- [sloppy.io](https://github.com/sloppyio/quickstarters/tree/master/gogs)
- [YunoHost](https://github.com/mbugeia/gogs_ynh)
- [DPlatform](https://github.com/j8r/DPlatform)
## Software and Service Support
- [Drone](https://github.com/drone/drone) (CI)
- [Fabric8](http://fabric8.io/) (DevOps)
- [Taiga](https://taiga.io/) (Project Management)
- [Puppet](https://forge.puppetlabs.com/Siteminds/gogs) (IT)
- [Kanboard](http://kanboard.net/plugin/gogs-webhook) (Project Management)
- [BearyChat](https://bearychat.com/) (Team Communication)
- [HiWork](http://www.hiwork.cc/) (Team Communication)
### Product Support
- [Synology](https://www.synology.com) (Docker)
- [One Space](http://www.onespace.cc) (App Store)
## Acknowledgments
- Router and middleware mechanism of [Macaron](https://github.com/go-macaron/macaron).
- System Monitor Status is inspired by [GoBlog](https://github.com/fuxiaohei/goblog).
- Thanks [Rocker](http://weibo.com/rocker1989) for designing Logo.
- Thanks [Crowdin](https://crowdin.com/project/gogs) for providing open source translation plan.
- Thanks [DigitalOcean](https://www.digitalocean.com) for hosting home and demo sites.
- Thanks [KeyCDN](https://www.keycdn.com/) and [QiNiu](http://www.qiniu.com/) for providing CDN service.
## Docs
For further information or instructions how to install Gitea please take a look at our [documentation](https://docs.gitea.io/en-us/), if you can not find some specific information just head over to our [Gitter](https://gitter.im/go-gitea/gitea) channel to have a chat with us.
## Contributing
@@ -131,7 +39,7 @@ Fork -> Patch -> Push -> Pull Request
* [Maintainers](https://github.com/orgs/go-gitea/people)
* [Contributors](https://github.com/go-gitea/gitea/graphs/contributors)
* [Translators](conf/locale/TRANSLATORS)
* [Translators](options/locale/TRANSLATORS)
## License

48
README_ZH.md Normal file
View File

@@ -0,0 +1,48 @@
[English](https://github.com/go-gitea/gitea/blob/master/README.md)
# Gitea - Git with a cup of tea
[![Build Status](http://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](http://drone.gitea.io/go-gitea/gitea)
[![Join the chat at https://gitter.im/go-gitea/gitea](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-gitea/gitea?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![](https://images.microbadger.com/badges/image/gitea/gitea.svg)](http://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com")
[![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)
[![Release](http://github-release-version.herokuapp.com/github/go-gitea/gitea/release.svg?style=flat)](https://github.com/go-gitea/gitea/releases/latest)
||||
|:-------------:|:-------:|:-------:|
|![Dashboard](https://i.imgur.com/3iEQsux.jpg)|![Repository](https://i.imgur.com/glqFnj8.jpg)|![Commits History](https://i.imgur.com/ad1FEpi.jpg)|
|![Profile](https://i.imgur.com/q81EcGa.jpg)|![Admin Dashboard](https://i.imgur.com/L2CQeN0.jpg)|![Diff](https://i.imgur.com/cNuvMum.jpg)|
|![Issues](https://i.imgur.com/xCYRqaF.jpg)|![Releases](https://i.imgur.com/ILpRBCe.jpg)|![Organization](https://i.imgur.com/0BHnrcL.jpg)|
||||
## 目标
Gitea的首要目标是创建一个极易安装运行非常快速安装和使用体验良好的自建 Git 服务。我们采用Go作为后端语言这使我们只要生成一个可执行程序即可。并且他还支持跨平台支持 Linux, macOS 和 Windows 以及各种架构除了x86amd64还包括 ARM 和 PowerPC。
如果您想试用一下,请访问 [在线Demo](https://try.gitea.io/)
## 提示
1. **开始贡献代码之前请确保你已经看过了 [贡献者向导(英文)](CONTRIBUTING.md)**.
2. 所有的安全问题,请私下发送邮件给 **security@gitea.io**。谢谢!
3. 如果你要使用API请参见 [API 文档](https://godoc.org/code.gitea.io/sdk/gitea).
## 文档
关于如何安装请访问我们的 [文档站](https://docs.gitea.io/zh-cn/),如果没有找到对应的文档,你也可以通过 [Gitter - 英文](https://gitter.im/go-gitea/gitea) 和 QQ群 328432459 来和我们交流。
## 贡献流程
Fork -> Patch -> Push -> Pull Request
## 作者
* [Maintainers](https://github.com/orgs/go-gitea/people)
* [Contributors](https://github.com/go-gitea/gitea/graphs/contributors)
* [Translators](options/locale/TRANSLATORS)
## 授权许可
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/go-gitea/gitea/blob/master/LICENSE) 文件中。

View File

@@ -1,4 +1,5 @@
// Copyright 2016 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
@@ -18,7 +19,7 @@ var (
CmdAdmin = cli.Command{
Name: "admin",
Usage: "Preform admin operations on command line",
Description: `Allow using internal logic of Gogs without hacking into the source code
Description: `Allow using internal logic of Gitea without hacking into the source code
to make automatic initialization process more smoothly`,
Subcommands: []cli.Command{
subcmdCreateUser,
@@ -73,7 +74,9 @@ func runCreateUser(c *cli.Context) error {
setting.NewContext()
models.LoadConfigs()
models.SetEngine()
if err := models.SetEngine(); err != nil {
return fmt.Errorf("models.SetEngine: %v", err)
}
if err := models.CreateUser(&models.User{
Name: c.String("name"),

View File

@@ -137,7 +137,7 @@ func runCert(ctx *cli.Context) error {
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Acme Co"},
CommonName: "Gogs",
CommonName: "Gitea",
},
NotBefore: notBefore,
NotAfter: notAfter,

View File

@@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
@@ -10,6 +11,7 @@ import (
"log"
"os"
"path"
"path/filepath"
"time"
"code.gitea.io/gitea/models"
@@ -21,9 +23,9 @@ import (
// CmdDump represents the available dump sub-command.
var CmdDump = cli.Command{
Name: "dump",
Usage: "Dump Gogs files and database",
Usage: "Dump Gitea files and database",
Description: `Dump compresses all related files and database into zip file.
It can be used for backup and capture Gogs server image to send to maintainer`,
It can be used for backup and capture Gitea server image to send to maintainer`,
Action: runDump,
Flags: []cli.Flag{
cli.StringFlag{
@@ -48,6 +50,7 @@ func runDump(ctx *cli.Context) error {
setting.CustomConf = ctx.String("config")
}
setting.NewContext()
setting.NewServices() // cannot access session settings otherwise
models.LoadConfigs()
models.SetEngine()
@@ -55,14 +58,14 @@ func runDump(ctx *cli.Context) error {
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
log.Fatalf("Path does not exist: %s", tmpDir)
}
TmpWorkDir, err := ioutil.TempDir(tmpDir, "gogs-dump-")
TmpWorkDir, err := ioutil.TempDir(tmpDir, "gitea-dump-")
if err != nil {
log.Fatalf("Fail to create tmp work directory: %v", err)
}
log.Printf("Creating tmp work dir: %s", TmpWorkDir)
reposDump := path.Join(TmpWorkDir, "gogs-repo.zip")
dbDump := path.Join(TmpWorkDir, "gogs-db.sql")
reposDump := path.Join(TmpWorkDir, "gitea-repo.zip")
dbDump := path.Join(TmpWorkDir, "gitea-db.sql")
log.Printf("Dumping local repositories...%s", setting.RepoRootPath)
zip.Verbose = ctx.Bool("verbose")
@@ -75,18 +78,18 @@ func runDump(ctx *cli.Context) error {
log.Fatalf("Fail to dump database: %v", err)
}
fileName := fmt.Sprintf("gogs-dump-%d.zip", time.Now().Unix())
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("Fail to create %s: %v", fileName, err)
}
if err := z.AddFile("gogs-repo.zip", reposDump); err != nil {
log.Fatalf("Fail to include gogs-repo.zip: %v", err)
if err := z.AddFile("gitea-repo.zip", reposDump); err != nil {
log.Fatalf("Fail to include gitea-repo.zip: %v", err)
}
if err := z.AddFile("gogs-db.sql", dbDump); err != nil {
log.Fatalf("Fail to include gogs-db.sql: %v", err)
if err := z.AddFile("gitea-db.sql", dbDump); err != nil {
log.Fatalf("Fail to include gitea-db.sql: %v", err)
}
customDir, err := os.Stat(setting.CustomPath)
if err == nil && customDir.IsDir() {
@@ -96,6 +99,20 @@ func runDump(ctx *cli.Context) error {
} else {
log.Printf("Custom dir %s doesn't exist, skipped", setting.CustomPath)
}
log.Printf("Packing data directory...%s", setting.AppDataPath)
var sessionAbsPath string
if setting.SessionConfig.Provider == "file" {
if len(setting.SessionConfig.ProviderConfig) == 0 {
setting.SessionConfig.ProviderConfig = "data/sessions"
}
sessionAbsPath, _ = filepath.Abs(setting.SessionConfig.ProviderConfig)
}
if err := zipAddDirectoryExclude(z, "data", setting.AppDataPath, sessionAbsPath); err != nil {
log.Fatalf("Fail to include data directory: %v", err)
}
if err := z.AddDir("log", setting.LogRootPath); err != nil {
log.Fatalf("Fail to include log: %v", err)
}
@@ -118,3 +135,40 @@ func runDump(ctx *cli.Context) error {
return nil
}
// zipAddDirectoryExclude zips absPath to specified zipPath inside z excluding excludeAbsPath
func zipAddDirectoryExclude(zip *zip.ZipArchive, zipPath, absPath string, excludeAbsPath string) error {
absPath, err := filepath.Abs(absPath)
if err != nil {
return err
}
dir, err := os.Open(absPath)
if err != nil {
return err
}
defer dir.Close()
zip.AddEmptyDir(zipPath)
files, err := dir.Readdir(0)
if err != nil {
return err
}
for _, file := range files {
currentAbsPath := path.Join(absPath, file.Name())
currentZipPath := path.Join(zipPath, file.Name())
if file.IsDir() {
if currentAbsPath != excludeAbsPath {
if err = zipAddDirectoryExclude(zip, currentZipPath, currentAbsPath, excludeAbsPath); err != nil {
return err
}
}
} else {
if err = zip.AddFile(currentZipPath, currentAbsPath); err != nil {
return err
}
}
}
return nil
}

View File

@@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
@@ -76,7 +77,7 @@ var (
)
func fail(userMessage, logMessage string, args ...interface{}) {
fmt.Fprintln(os.Stderr, "Gogs:", userMessage)
fmt.Fprintln(os.Stderr, "Gitea:", userMessage)
if len(logMessage) > 0 {
if !setting.ProdMode {
@@ -120,7 +121,7 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
// Ask for running deliver hook and test pull request tasks.
reqURL := setting.LocalURL + repoUser.Name + "/" + reponame + "/tasks/trigger?branch=" +
strings.TrimPrefix(task.RefName, git.BRANCH_PREFIX) + "&secret=" + base.EncodeMD5(repoUser.Salt) + "&pusher=" + com.ToStr(user.ID)
strings.TrimPrefix(task.RefName, git.BranchPrefix) + "&secret=" + base.EncodeMD5(repoUser.Salt) + "&pusher=" + com.ToStr(user.ID)
log.GitLogger.Trace("Trigger task: %s", reqURL)
resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
@@ -144,7 +145,7 @@ func runServ(c *cli.Context) error {
setup("serv.log")
if setting.SSH.Disabled {
println("Gogs: SSH has been disabled")
println("Gitea: SSH has been disabled")
return nil
}
@@ -154,8 +155,8 @@ func runServ(c *cli.Context) error {
cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
if len(cmd) == 0 {
println("Hi there, You've successfully authenticated, but Gogs does not provide shell access.")
println("If this is unexpected, please log in with password and setup Gogs under another user.")
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
}
@@ -255,11 +256,11 @@ func runServ(c *cli.Context) error {
"User %s does not have level %v access to repository %s",
user.Name, requestedMode, repoPath)
}
os.Setenv("GITEA_PUSHER_NAME", user.Name)
}
}
os.Setenv("GITEA_PUSHER_NAME", user.Name)
uuid := gouuid.NewV4().String()
os.Setenv("GITEA_UUID", uuid)
// Keep the old env variable name for backward compability

View File

@@ -7,7 +7,6 @@ package cmd
import (
"crypto/tls"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/http/fcgi"
@@ -15,15 +14,14 @@ import (
"path"
"strings"
"code.gitea.io/git"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/bindata"
"code.gitea.io/gitea/modules/context"
"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/template"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/admin"
apiv1 "code.gitea.io/gitea/routers/api/v1"
@@ -39,18 +37,15 @@ import (
"github.com/go-macaron/i18n"
"github.com/go-macaron/session"
"github.com/go-macaron/toolbox"
"github.com/go-xorm/xorm"
version "github.com/mcuadros/go-version"
"github.com/urfave/cli"
ini "gopkg.in/ini.v1"
macaron "gopkg.in/macaron.v1"
)
// CmdWeb represents the available web sub-command.
var CmdWeb = cli.Command{
Name: "web",
Usage: "Start Gogs web server",
Description: `Gogs web server is the only thing you need to run,
Usage: "Start Gitea web server",
Description: `Gitea web server is the only thing you need to run,
and it takes care of all the other things for you`,
Action: runWeb,
Flags: []cli.Flag{
@@ -74,45 +69,6 @@ type VerChecker struct {
Expected string
}
// checkVersion checks if binary matches the version of templates files.
func checkVersion() {
// Templates.
data, err := ioutil.ReadFile(setting.StaticRootPath + "/templates/.VERSION")
if err != nil {
log.Fatal(4, "Fail to read 'templates/.VERSION': %v", err)
}
tplVer := string(data)
if tplVer != setting.AppVer {
if version.Compare(tplVer, setting.AppVer, ">") {
log.Fatal(4, "Binary version is lower than template file version, did you forget to recompile Gogs?")
} else {
log.Fatal(4, "Binary version is higher than template file version, did you forget to update template files?")
}
}
// Check dependency version.
checkers := []VerChecker{
{"github.com/go-xorm/xorm", func() string { return xorm.Version }, "0.5.5"},
{"github.com/go-macaron/binding", binding.Version, "0.3.2"},
{"github.com/go-macaron/cache", cache.Version, "0.1.2"},
{"github.com/go-macaron/csrf", csrf.Version, "0.1.0"},
{"github.com/go-macaron/i18n", i18n.Version, "0.3.0"},
{"github.com/go-macaron/session", session.Version, "0.1.6"},
{"github.com/go-macaron/toolbox", toolbox.Version, "0.1.0"},
{"gopkg.in/ini.v1", ini.Version, "1.8.4"},
{"gopkg.in/macaron.v1", macaron.Version, "1.1.7"},
{"code.gitea.io/git", git.Version, "0.4.1"},
}
for _, c := range checkers {
if !version.Compare(c.Version(), c.Expected, ">=") {
log.Fatal(4, `Dependency outdated!
Package '%s' current version (%s) is below requirement (%s),
please use following command to update this package and recompile Gogs:
go get -u %[1]s`, c.ImportPath, c.Version(), c.Expected)
}
}
}
// newMacaron initializes Macaron instance.
func newMacaron() *macaron.Macaron {
m := macaron.New()
@@ -140,32 +96,32 @@ func newMacaron() *macaron.Macaron {
},
))
funcMap := template.NewFuncMap()
m.Use(macaron.Renderer(macaron.RenderOptions{
Directory: path.Join(setting.StaticRootPath, "templates"),
AppendDirectories: []string{path.Join(setting.CustomPath, "templates")},
Funcs: funcMap,
IndentJSON: macaron.Env != macaron.PROD,
}))
models.InitMailRender(path.Join(setting.StaticRootPath, "templates/mail"),
path.Join(setting.CustomPath, "templates/mail"), funcMap)
m.Use(templates.Renderer())
models.InitMailRender(templates.Mailer())
localeNames, err := options.Dir("locale")
localeNames, err := bindata.AssetDir("conf/locale")
if err != nil {
log.Fatal(4, "Fail to list locale files: %v", err)
}
localFiles := make(map[string][]byte)
for _, name := range localeNames {
localFiles[name] = bindata.MustAsset("conf/locale/" + name)
localFiles[name], err = options.Locale(name)
if err != nil {
log.Fatal(4, "Failed to load %s locale file. %v", name, err)
}
}
m.Use(i18n.I18n(i18n.Options{
SubURL: setting.AppSubURL,
Files: localFiles,
CustomDirectory: path.Join(setting.CustomPath, "conf/locale"),
Langs: setting.Langs,
Names: setting.Names,
DefaultLang: "en-US",
Redirect: true,
SubURL: setting.AppSubURL,
Files: localFiles,
Langs: setting.Langs,
Names: setting.Names,
DefaultLang: "en-US",
Redirect: true,
}))
m.Use(cache.Cacher(cache.Options{
Adapter: setting.CacheAdapter,
@@ -200,7 +156,6 @@ func runWeb(ctx *cli.Context) error {
setting.CustomConf = ctx.String("config")
}
routers.GlobalInit()
checkVersion()
m := newMacaron()

View File

@@ -1,3 +0,0 @@
Execute following command in ROOT directory when anything is changed:
$ make bindata

View File

@@ -1,6 +1,3 @@
# NEVER EVER MODIFY THIS FILE
# PLEASE MAKE CHANGES ON CORRESPONDING CUSTOM CONFIG FILE
; App name that shows on every page title
APP_NAME = Gitea: Git with a cup of tea
; Change it if you run locally
@@ -57,7 +54,7 @@ FEED_MAX_COMMIT_NUM = 5
; Value of `theme-color` meta tag, used by Android >= 5.0
; An invalid color like "none" or "disable" will have the default style
; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
THEME_COLOR_META_TAG = `#ff5343`
THEME_COLOR_META_TAG = `#6cc644`
; Max size of files to be displayed (defaults is 8MiB)
MAX_DISPLAY_FILE_SIZE = 8388608
@@ -103,6 +100,8 @@ DISABLE_SSH = false
START_SSH_SERVER = false
; Domain name to be exposed in clone URL
SSH_DOMAIN = %(DOMAIN)s
; Network interface builtin SSH server listens on
SSH_LISTEN_HOST =
; Port number to be exposed in clone URL
SSH_PORT = 22
; Port number builtin SSH server listens on
@@ -336,7 +335,7 @@ HOST =
; Mailer user name and password
USER =
PASSWD =
; Receivers, can be one or more, e.g. ["1@example.com","2@example.com"]
; Receivers, can be one or more, e.g. 1@example.com,2@example.com
RECEIVERS =
; For "database" mode only
@@ -400,8 +399,8 @@ DEFAULT_INTERVAL = 8
MAX_RESPONSE_ITEMS = 50
[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,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE
NAMES = English,简体中文,繁體中文(香港),繁體中文(台湾),Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen,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,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,Suomalainen,Türkçe,čeština,Српски,Svenska,한국어
; Used for datetimepicker
[i18n.datelang]
@@ -425,6 +424,7 @@ tr-TR = tr
cs-CZ = cs-CZ
sr-SP = sr
sv-SE = sv
ko-KR = ko
; Extension mapping to highlight class
; e.g. .toml=ini

View File

@@ -2,5 +2,5 @@
[[ -f ./setup ]] && source ./setup
pushd /root > /dev/null
exec su-exec root /usr/sbin/sshd -E /var/log/sshd.log -D
exec su-exec root /usr/sbin/sshd -D
popd

View File

@@ -18,7 +18,6 @@ UseDNS no
AllowAgentForwarding no
AllowTcpForwarding no
PrintMotd no
PrintLastLog no
PermitUserEnvironment yes
PermitRootLogin no

View File

@@ -1,5 +1,5 @@
// Copyright 2016 The Gitea Authors. All rights reserved.
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
@@ -18,7 +18,7 @@ import (
)
// Version holds the current Gitea version
const Version = "0.9.99.0915"
var Version = "1.0.2+dev"
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())

View File

@@ -494,12 +494,12 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
isNewBranch := false
opType := ActionCommitRepo
// Check it's tag push or branch.
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
opType = ActionPushTag
opts.Commits = &PushCommits{}
} else {
// if not the first commit, set the compare URL.
if opts.OldCommitID == git.EMPTY_SHA {
if opts.OldCommitID == git.EmptySHA {
isNewBranch = true
} else {
opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
@@ -539,7 +539,7 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
}()
apiPusher := pusher.APIFormat()
apiRepo := repo.APIFormat(nil)
apiRepo := repo.APIFormat(AccessModeNone)
var shaSum string
switch opType {
@@ -562,7 +562,7 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
if err != nil {
log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err)
}
shaSum, err = gitRepo.GetBranchCommitID(opts.RefFullName)
shaSum, err = gitRepo.GetBranchCommitID(refName)
if err != nil {
log.Error(4, "GetBranchCommitID[%s]: %v", opts.RefFullName, err)
}
@@ -580,7 +580,7 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
if err != nil {
log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err)
}
shaSum, err = gitRepo.GetTagCommitID(opts.RefFullName)
shaSum, err = gitRepo.GetTagCommitID(refName)
if err != nil {
log.Error(4, "GetTagCommitID[%s]: %v", opts.RefFullName, err)
}

View File

@@ -18,10 +18,10 @@ import (
"code.gitea.io/git"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/highlight"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/template/highlight"
"github.com/Unknwon/com"
"github.com/sergi/go-diff/diffmatchpatch"
"golang.org/x/net/html/charset"

View File

@@ -87,13 +87,20 @@ func (issue *Issue) AfterSet(colName string, _ xorm.Cell) {
}
}
func (issue *Issue) loadAttributes(e Engine) (err error) {
func (issue *Issue) loadRepo(e Engine) (err error) {
if issue.Repo == nil {
issue.Repo, err = getRepositoryByID(e, issue.RepoID)
if err != nil {
return fmt.Errorf("getRepositoryByID [%d]: %v", issue.RepoID, err)
}
}
return nil
}
func (issue *Issue) loadAttributes(e Engine) (err error) {
if err := issue.loadRepo(e); err != nil {
return err
}
if issue.Poster == nil {
issue.Poster, err = getUserByID(e, issue.PosterID)
@@ -265,7 +272,7 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
Action: api.HookIssueLabelUpdated,
Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(),
Repository: issue.Repo.APIFormat(nil),
Repository: issue.Repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
})
}
@@ -322,6 +329,16 @@ func (issue *Issue) removeLabel(e *xorm.Session, label *Label) error {
// RemoveLabel removes a label from issue by given ID.
func (issue *Issue) RemoveLabel(doer *User, label *Label) error {
if err := issue.loadRepo(x); err != nil {
return err
}
if has, err := HasAccess(doer, issue.Repo, AccessModeWrite); err != nil {
return err
} else if !has {
return ErrLabelNotExist{}
}
if err := DeleteIssueLabel(issue, label); err != nil {
return err
}
@@ -353,6 +370,16 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
return err
}
if err := issue.loadRepo(sess); err != nil {
return err
}
if has, err := hasAccess(sess, doer, issue.Repo, AccessModeWrite); err != nil {
return err
} else if !has {
return ErrLabelNotExist{}
}
if err = issue.clearLabels(sess); err != nil {
return err
}
@@ -371,7 +398,7 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
Action: api.HookIssueLabelCleared,
Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(),
Repository: issue.Repo.APIFormat(nil),
Repository: issue.Repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
})
}
@@ -493,7 +520,7 @@ func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (e
apiPullRequest := &api.PullRequestPayload{
Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(),
Repository: repo.APIFormat(nil),
Repository: repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
}
if isClosed {
@@ -531,7 +558,7 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
},
},
PullRequest: issue.PullRequest.APIFormat(),
Repository: issue.Repo.APIFormat(nil),
Repository: issue.Repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
})
}
@@ -563,7 +590,7 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
},
},
PullRequest: issue.PullRequest.APIFormat(),
Repository: issue.Repo.APIFormat(nil),
Repository: issue.Repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
})
}
@@ -596,7 +623,7 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
apiPullRequest := &api.PullRequestPayload{
Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(),
Repository: issue.Repo.APIFormat(nil),
Repository: issue.Repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
}
if isRemoveAssignee {
@@ -888,7 +915,10 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
}
if len(opts.Labels) > 0 && opts.Labels != "0" {
labelIDs := base.StringsToInt64s(strings.Split(opts.Labels, ","))
labelIDs, err := base.StringsToInt64s(strings.Split(opts.Labels, ","))
if err != nil {
return nil, err
}
if len(labelIDs) > 0 {
sess.
Join("INNER", "issue_label", "issue.id = issue_label.issue_id").
@@ -1055,7 +1085,7 @@ func GetIssueUserPairsByMode(uid, rid int64, isClosed bool, page, filterMode int
// UpdateIssueMentions extracts mentioned people from content and
// updates issue-user relations for them.
func UpdateIssueMentions(issueID int64, mentions []string) error {
func UpdateIssueMentions(e Engine, issueID int64, mentions []string) error {
if len(mentions) == 0 {
return nil
}
@@ -1065,7 +1095,7 @@ func UpdateIssueMentions(issueID int64, mentions []string) error {
}
users := make([]*User, 0, len(mentions))
if err := x.In("lower_name", mentions).Asc("lower_name").Find(&users); err != nil {
if err := e.In("lower_name", mentions).Asc("lower_name").Find(&users); err != nil {
return fmt.Errorf("find mentioned users: %v", err)
}
@@ -1089,7 +1119,7 @@ func UpdateIssueMentions(issueID int64, mentions []string) error {
ids = append(ids, memberIDs...)
}
if err := UpdateIssueUsersByMentions(issueID, ids); err != nil {
if err := UpdateIssueUsersByMentions(e, issueID, ids); err != nil {
return fmt.Errorf("UpdateIssueUsersByMentions: %v", err)
}
@@ -1144,10 +1174,11 @@ func GetIssueStats(opts *IssueStatsOptions) *IssueStats {
And("is_pull = ?", opts.IsPull)
if len(opts.Labels) > 0 && opts.Labels != "0" {
labelIDs := base.StringsToInt64s(strings.Split(opts.Labels, ","))
if len(labelIDs) > 0 {
sess.
Join("INNER", "issue_label", "issue.id = issue_id").
labelIDs, err := base.StringsToInt64s(strings.Split(opts.Labels, ","))
if err != nil {
log.Warn("Malformed Labels argument: %s", opts.Labels)
} else if len(labelIDs) > 0 {
sess.Join("INNER", "issue_label", "issue.id = issue_id").
In("label_id", labelIDs)
}
}
@@ -1248,7 +1279,7 @@ func GetUserIssueStats(repoID, uid int64, repoIDs []int64, filterMode int, isPul
func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen int64, numClosed int64) {
countSession := func(isClosed, isPull bool, repoID int64) *xorm.Session {
sess := x.
Where("issue.repo_id = ?", isClosed).
Where("is_closed = ?", isClosed).
And("is_pull = ?", isPull).
And("repo_id = ?", repoID)
@@ -1330,22 +1361,22 @@ func UpdateIssueUserByRead(uid, issueID int64) error {
}
// UpdateIssueUsersByMentions updates issue-user pairs by mentioning.
func UpdateIssueUsersByMentions(issueID int64, uids []int64) error {
func UpdateIssueUsersByMentions(e Engine, issueID int64, uids []int64) error {
for _, uid := range uids {
iu := &IssueUser{
UID: uid,
IssueID: issueID,
}
has, err := x.Get(iu)
has, err := e.Get(iu)
if err != nil {
return err
}
iu.IsMentioned = true
if has {
_, err = x.Id(iu.ID).AllCols().Update(iu)
_, err = e.Id(iu.ID).AllCols().Update(iu)
} else {
_, err = x.Insert(iu)
_, err = e.Insert(iu)
}
if err != nil {
return err

View File

@@ -123,14 +123,55 @@ func (c *Comment) AfterDelete() {
}
}
// HTMLURL formats a URL-string to the issue-comment
func (c *Comment) HTMLURL() string {
issue, err := GetIssueByID(c.IssueID)
if err != nil { // Silently dropping errors :unamused:
log.Error(4, "GetIssueByID(%d): %v", c.IssueID, err)
return ""
}
return fmt.Sprintf("%s#issuecomment-%d", issue.HTMLURL(), c.ID)
}
// IssueURL formats a URL-string to the issue
func (c *Comment) IssueURL() string {
issue, err := GetIssueByID(c.IssueID)
if err != nil { // Silently dropping errors :unamused:
log.Error(4, "GetIssueByID(%d): %v", c.IssueID, err)
return ""
}
if issue.IsPull {
return ""
}
return issue.HTMLURL()
}
// PRURL formats a URL-string to the pull-request
func (c *Comment) PRURL() string {
issue, err := GetIssueByID(c.IssueID)
if err != nil { // Silently dropping errors :unamused:
log.Error(4, "GetIssueByID(%d): %v", c.IssueID, err)
return ""
}
if !issue.IsPull {
return ""
}
return issue.HTMLURL()
}
// APIFormat converts a Comment to the api.Comment format
func (c *Comment) APIFormat() *api.Comment {
return &api.Comment{
ID: c.ID,
Poster: c.Poster.APIFormat(),
Body: c.Content,
Created: c.Created,
Updated: c.Updated,
ID: c.ID,
Poster: c.Poster.APIFormat(),
HTMLURL: c.HTMLURL(),
IssueURL: c.IssueURL(),
PRURL: c.PRURL(),
Body: c.Content,
Created: c.Created,
Updated: c.Updated,
}
}
@@ -146,9 +187,9 @@ func (c *Comment) EventTag() string {
// MailParticipants sends new comment emails to repository watchers
// and mentioned people.
func (c *Comment) MailParticipants(opType ActionType, issue *Issue) (err error) {
func (c *Comment) MailParticipants(e Engine, opType ActionType, issue *Issue) (err error) {
mentions := markdown.FindAllMentions(c.Content)
if err = UpdateIssueMentions(c.IssueID, mentions); err != nil {
if err = UpdateIssueMentions(e, c.IssueID, mentions); err != nil {
return fmt.Errorf("UpdateIssueMentions [%d]: %v", c.IssueID, err)
}
@@ -262,7 +303,9 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
if err = notifyWatchers(e, act); err != nil {
log.Error(4, "notifyWatchers: %v", err)
}
comment.MailParticipants(act.OpType, opts.Issue)
if err = comment.MailParticipants(e, act.OpType, opts.Issue); err != nil {
log.Error(4, "MailParticipants: %v", err)
}
}
return comment, nil
@@ -375,6 +418,15 @@ func getCommentsByIssueIDSince(e Engine, issueID, since int64) ([]*Comment, erro
return comments, sess.Find(&comments)
}
func getCommentsByRepoIDSince(e Engine, repoID, since int64) ([]*Comment, error) {
comments := make([]*Comment, 0, 10)
sess := e.Where("issue.repo_id = ?", repoID).Join("INNER", "issue", "issue.id = comment.issue_id", repoID).Asc("created_unix")
if since > 0 {
sess.And("updated_unix >= ?", since)
}
return comments, sess.Find(&comments)
}
func getCommentsByIssueID(e Engine, issueID int64) ([]*Comment, error) {
return getCommentsByIssueIDSince(e, issueID, -1)
}
@@ -389,6 +441,11 @@ func GetCommentsByIssueIDSince(issueID, since int64) ([]*Comment, error) {
return getCommentsByIssueIDSince(x, issueID, since)
}
// GetCommentsByRepoIDSince returns a list of comments for all issues in a repo since a given time point.
func GetCommentsByRepoIDSince(repoID, since int64) ([]*Comment, error) {
return getCommentsByRepoIDSince(x, repoID, since)
}
// UpdateComment updates information of comment.
func UpdateComment(c *Comment) error {
_, err := x.Id(c.ID).AllCols().Update(c)

View File

@@ -69,7 +69,7 @@ func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string)
// and mentioned people.
func (issue *Issue) MailParticipants() (err error) {
mentions := markdown.FindAllMentions(issue.Content)
if err = UpdateIssueMentions(issue.ID, mentions); err != nil {
if err = UpdateIssueMentions(x, issue.ID, mentions); err != nil {
return fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err)
}

View File

@@ -548,9 +548,9 @@ func ExternalUserLogin(user *User, login, password string, source *LoginSource,
func UserSignIn(username, password string) (*User, error) {
var user *User
if strings.Contains(username, "@") {
user = &User{Email: strings.ToLower(username)}
user = &User{Email: strings.ToLower(strings.TrimSpace(username))}
} else {
user = &User{LowerName: strings.ToLower(username)}
user = &User{LowerName: strings.ToLower(strings.TrimSpace(username))}
}
hasUser, err := x.Get(user)

View File

@@ -5,18 +5,18 @@
package models
import (
"bytes"
"fmt"
"html/template"
"path"
"gopkg.in/gomail.v2"
"gopkg.in/macaron.v1"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/mailer"
"code.gitea.io/gitea/modules/markdown"
"code.gitea.io/gitea/modules/setting"
"gopkg.in/gomail.v2"
"gopkg.in/macaron.v1"
)
const (
@@ -31,32 +31,16 @@ const (
mailNotifyCollaborator base.TplName = "notify/collaborator"
)
type mailRenderInterface interface {
HTMLString(string, interface{}, ...macaron.HTMLOptions) (string, error)
}
var mailRender mailRenderInterface
var templates *template.Template
// InitMailRender initializes the macaron mail renderer
func InitMailRender(dir, appendDir string, funcMap []template.FuncMap) {
opt := &macaron.RenderOptions{
Directory: dir,
AppendDirectories: []string{appendDir},
Funcs: funcMap,
Extensions: []string{".tmpl", ".html"},
}
ts := macaron.NewTemplateSet()
ts.Set(macaron.DEFAULT_TPL_SET_NAME, opt)
mailRender = &macaron.TplRender{
TemplateSet: ts,
Opt: opt,
}
func InitMailRender(tmpls *template.Template) {
templates = tmpls
}
// SendTestMail sends a test mail
func SendTestMail(email string) error {
return gomail.Send(&mailer.Sender{}, mailer.NewMessage([]string{email}, "Gogs Test Email!", "Gogs Test Email!").Message)
return gomail.Send(&mailer.Sender{}, mailer.NewMessage([]string{email}, "Gitea Test Email!", "Gitea Test Email!").Message)
}
// SendUserMail sends a mail to the user
@@ -67,13 +51,15 @@ func SendUserMail(c *macaron.Context, u *User, tpl base.TplName, code, subject,
"ResetPwdCodeLives": setting.Service.ResetPwdCodeLives / 60,
"Code": code,
}
body, err := mailRender.HTMLString(string(tpl), data)
if err != nil {
log.Error(3, "HTMLString: %v", err)
var content bytes.Buffer
if err := templates.ExecuteTemplate(&content, string(tpl), data); err != nil {
log.Error(3, "Template: %v", err)
return
}
msg := mailer.NewMessage([]string{u.Email}, subject, body)
msg := mailer.NewMessage([]string{u.Email}, subject, content.String())
msg.Info = fmt.Sprintf("UID: %d, %s", u.ID, info)
mailer.SendAsync(msg)
@@ -97,13 +83,15 @@ func SendActivateEmailMail(c *macaron.Context, u *User, email *EmailAddress) {
"Code": u.GenerateEmailActivateCode(email.Email),
"Email": email.Email,
}
body, err := mailRender.HTMLString(string(mailAuthActivateEmail), data)
if err != nil {
log.Error(3, "HTMLString: %v", err)
var content bytes.Buffer
if err := templates.ExecuteTemplate(&content, string(mailAuthActivateEmail), data); err != nil {
log.Error(3, "Template: %v", err)
return
}
msg := mailer.NewMessage([]string{email.Email}, c.Tr("mail.activate_email"), body)
msg := mailer.NewMessage([]string{email.Email}, c.Tr("mail.activate_email"), content.String())
msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID)
mailer.SendAsync(msg)
@@ -114,13 +102,15 @@ func SendRegisterNotifyMail(c *macaron.Context, u *User) {
data := map[string]interface{}{
"Username": u.DisplayName(),
}
body, err := mailRender.HTMLString(string(mailAuthRegisterNotify), data)
if err != nil {
log.Error(3, "HTMLString: %v", err)
var content bytes.Buffer
if err := templates.ExecuteTemplate(&content, string(mailAuthRegisterNotify), data); err != nil {
log.Error(3, "Template: %v", err)
return
}
msg := mailer.NewMessage([]string{u.Email}, c.Tr("mail.register_notify"), body)
msg := mailer.NewMessage([]string{u.Email}, c.Tr("mail.register_notify"), content.String())
msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID)
mailer.SendAsync(msg)
@@ -136,13 +126,15 @@ func SendCollaboratorMail(u, doer *User, repo *Repository) {
"RepoName": repoName,
"Link": repo.HTMLURL(),
}
body, err := mailRender.HTMLString(string(mailNotifyCollaborator), data)
if err != nil {
log.Error(3, "HTMLString: %v", err)
var content bytes.Buffer
if err := templates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil {
log.Error(3, "Template: %v", err)
return
}
msg := mailer.NewMessage([]string{u.Email}, subject, body)
msg := mailer.NewMessage([]string{u.Email}, subject, content.String())
msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.ID)
mailer.SendAsync(msg)
@@ -161,11 +153,14 @@ func composeIssueMessage(issue *Issue, doer *User, tplName base.TplName, tos []s
body := string(markdown.RenderSpecialLink([]byte(issue.Content), issue.Repo.HTMLURL(), issue.Repo.ComposeMetas()))
data := composeTplData(subject, body, issue.HTMLURL())
data["Doer"] = doer
content, err := mailRender.HTMLString(string(tplName), data)
if err != nil {
log.Error(3, "HTMLString (%s): %v", tplName, err)
var content bytes.Buffer
if err := templates.ExecuteTemplate(&content, string(tplName), data); err != nil {
log.Error(3, "Template: %v", err)
}
msg := mailer.NewMessageFrom(tos, fmt.Sprintf(`"%s" <%s>`, doer.DisplayName(), setting.MailService.FromEmail), subject, content)
msg := mailer.NewMessageFrom(tos, fmt.Sprintf(`"%s" <%s>`, doer.DisplayName(), setting.MailService.FromEmail), subject, content.String())
msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info)
return msg
}

View File

@@ -457,8 +457,12 @@ func generateOrgRandsAndSalt(x *xorm.Engine) (err error) {
}
for _, org := range orgs {
org.Rands = base.GetRandomString(10)
org.Salt = base.GetRandomString(10)
if org.Rands, err = base.GetRandomString(10); err != nil {
return err
}
if org.Salt, err = base.GetRandomString(10); err != nil {
return err
}
if _, err = sess.Id(org.ID).Update(org); err != nil {
return err
}

View File

@@ -109,8 +109,12 @@ func CreateOrganization(org, owner *User) (err error) {
}
org.LowerName = strings.ToLower(org.Name)
org.Rands = GetUserSalt()
org.Salt = GetUserSalt()
if org.Rands, err = GetUserSalt(); err != nil {
return err
}
if org.Salt, err = GetUserSalt(); err != nil {
return err
}
org.UseCustomAvatar = true
org.MaxRepoCreation = -1
org.NumTeams = 1
@@ -202,12 +206,9 @@ func Organizations(page, pageSize int) ([]*User, error) {
// DeleteOrganization completely and permanently deletes everything of organization.
func DeleteOrganization(org *User) (err error) {
if err := DeleteUser(org); err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
@@ -224,7 +225,11 @@ func DeleteOrganization(org *User) (err error) {
return fmt.Errorf("deleteUser: %v", err)
}
return sess.Commit()
if err = sess.Commit(); err != nil {
return err
}
return RewriteAllPublicKeys()
}
// ________ ____ ___

View File

@@ -160,14 +160,14 @@ func (pr *PullRequest) APIFormat() *api.PullRequest {
Ref: pr.BaseBranch,
Sha: baseCommit.ID.String(),
RepoID: pr.BaseRepoID,
Repository: pr.BaseRepo.APIFormat(nil),
Repository: pr.BaseRepo.APIFormat(AccessModeNone),
}
apiHeadBranchInfo := &api.PRBranchInfo{
Name: pr.HeadBranch,
Ref: pr.HeadBranch,
Sha: headCommit.ID.String(),
RepoID: pr.HeadRepoID,
Repository: pr.HeadRepo.APIFormat(nil),
Repository: pr.HeadRepo.APIFormat(AccessModeNone),
}
apiPullRequest := &api.PullRequest{
ID: pr.ID,
@@ -355,7 +355,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
Action: api.HookIssueClosed,
Index: pr.Index,
PullRequest: pr.APIFormat(),
Repository: pr.Issue.Repo.APIFormat(nil),
Repository: pr.Issue.Repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
}); err != nil {
log.Error(4, "PrepareWebhooks: %v", err)
@@ -380,12 +380,12 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
l.PushFront(mergeCommit)
p := &api.PushPayload{
Ref: git.BRANCH_PREFIX + pr.BaseBranch,
Ref: git.BranchPrefix + pr.BaseBranch,
Before: pr.MergeBase,
After: pr.MergedCommitID,
CompareURL: setting.AppURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
Commits: ListToPushCommits(l).ToAPIPayloadCommits(pr.BaseRepo.HTMLURL()),
Repo: pr.BaseRepo.APIFormat(nil),
Repo: pr.BaseRepo.APIFormat(AccessModeNone),
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
Sender: doer.APIFormat(),
}
@@ -404,7 +404,6 @@ var patchConflicts = []string{
}
// testPatch checks if patch can be merged to base repository without conflict.
// FIXME: make a mechanism to clean up stable local copies.
func (pr *PullRequest) testPatch() (err error) {
if pr.BaseRepo == nil {
pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID)
@@ -429,6 +428,9 @@ func (pr *PullRequest) testPatch() (err error) {
log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)
// Delete old temp local copy before we create a new temp local copy
RemoveAllWithNotice("Deleting old local copy", pr.BaseRepo.LocalCopyPath())
if err := pr.BaseRepo.UpdateLocalCopyBranch(pr.BaseBranch); err != nil {
return fmt.Errorf("UpdateLocalCopy: %v", err)
}
@@ -514,7 +516,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
Action: api.HookIssueOpened,
Index: pull.Index,
PullRequest: pr.APIFormat(),
Repository: repo.APIFormat(nil),
Repository: repo.APIFormat(AccessModeNone),
Sender: pull.Poster.APIFormat(),
}); err != nil {
log.Error(4, "PrepareWebhooks: %v", err)
@@ -840,7 +842,7 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool
Action: api.HookIssueSynchronized,
Index: pr.Issue.Index,
PullRequest: pr.Issue.PullRequest.APIFormat(),
Repository: pr.Issue.Repo.APIFormat(nil),
Repository: pr.Issue.Repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
}); err != nil {
log.Error(4, "PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
@@ -927,7 +929,7 @@ func TestPullRequests() {
pr, err := GetPullRequestByID(com.StrTo(prID).MustInt64())
if err != nil {
log.Error(4, "GetPullRequestByID[%d]: %v", prID, err)
log.Error(4, "GetPullRequestByID[%s]: %v", prID, err)
continue
} else if err = pr.testPatch(); err != nil {
log.Error(4, "testPatch[%d]: %v", pr.ID, err)

View File

@@ -189,7 +189,7 @@ func UpdateRelease(gitRepo *git.Repository, rel *Release) (err error) {
}
// DeleteReleaseByID deletes a release and corresponding Git tag by given ID.
func DeleteReleaseByID(id int64) error {
func DeleteReleaseByID(id int64, u *User, delTag bool) error {
rel, err := GetReleaseByID(id)
if err != nil {
return fmt.Errorf("GetReleaseByID: %v", err)
@@ -200,11 +200,20 @@ func DeleteReleaseByID(id int64) error {
return fmt.Errorf("GetRepositoryByID: %v", err)
}
_, stderr, err := process.ExecDir(-1, repo.RepoPath(),
fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
"git", "tag", "-d", rel.TagName)
if err != nil && !strings.Contains(stderr, "not found") {
return fmt.Errorf("git tag -d: %v - %s", err, stderr)
has, err := HasAccess(u, repo, AccessModeWrite)
if err != nil {
return fmt.Errorf("HasAccess: %v", err)
} else if !has {
return fmt.Errorf("DeleteReleaseByID: permission denied")
}
if delTag {
_, stderr, err := process.ExecDir(-1, repo.RepoPath(),
fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
"git", "tag", "-d", rel.TagName)
if err != nil && !strings.Contains(stderr, "not found") {
return fmt.Errorf("git tag -d: %v - %s", err, stderr)
}
}
if _, err = x.Id(rel.ID).Delete(new(Release)); err != nil {

View File

@@ -20,9 +20,9 @@ import (
"time"
"code.gitea.io/git"
"code.gitea.io/gitea/modules/bindata"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markdown"
"code.gitea.io/gitea/modules/options"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/sync"
@@ -80,11 +80,11 @@ func LoadRepoConfig() {
types := []string{"gitignore", "license", "readme", "label"}
typeFiles := make([][]string, 4)
for i, t := range types {
files, err := bindata.AssetDir("conf/" + t)
files, err := options.Dir(t)
if err != nil {
log.Fatal(4, "Fail to get %s files: %v", t, err)
}
customPath := path.Join(setting.CustomPath, "conf", t)
customPath := path.Join(setting.CustomPath, "options", t)
if com.IsDir(customPath) {
customFiles, err := com.StatDir(customPath)
if err != nil {
@@ -276,9 +276,13 @@ func (repo *Repository) HTMLURL() string {
}
// APIFormat converts a Repository to api.Repository
// Arguments that are allowed to be nil: permission
func (repo *Repository) APIFormat(permission *api.Permission) *api.Repository {
func (repo *Repository) APIFormat(mode AccessMode) *api.Repository {
cloneLink := repo.CloneLink()
permission := &api.Permission{
Admin: mode >= AccessModeAdmin,
Push: mode >= AccessModeWrite,
Pull: mode >= AccessModeRead,
}
return &api.Repository{
ID: repo.ID,
Owner: repo.Owner.APIFormat(),
@@ -506,7 +510,7 @@ func (repo *Repository) DescriptionHTML() template.HTML {
// LocalCopyPath returns the local repository copy path
func (repo *Repository) LocalCopyPath() string {
return path.Join(setting.AppDataPath, "tmp/local-rpeo", com.ToStr(repo.ID))
return path.Join(setting.AppDataPath, "tmp/local-repo", com.ToStr(repo.ID))
}
// UpdateLocalCopyBranch pulls latest changes of given branch from repoPath to localPath.
@@ -687,7 +691,6 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
wikiRemotePath := wikiRemoteURL(opts.RemoteAddr)
if len(wikiRemotePath) > 0 {
if err := os.RemoveAll(wikiPath); err != nil {
return repo, fmt.Errorf("Fail to remove %s: %v", wikiPath, err)
}
@@ -696,8 +699,12 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
Branch: "master",
}); err != nil {
log.Info("Clone wiki: %v", err)
log.Warn("Clone wiki: %v", err)
if err := os.RemoveAll(wikiPath); err != nil {
return repo, fmt.Errorf("Fail to remove %s: %v", wikiPath, err)
}
}
}
@@ -823,14 +830,27 @@ type CreateRepoOptions struct {
}
func getRepoInitFile(tp, name string) ([]byte, error) {
relPath := path.Join("conf", tp, strings.TrimLeft(name, "./"))
cleanedName := strings.TrimLeft(name, "./")
relPath := path.Join("options", tp, cleanedName)
// Use custom file when available.
customPath := path.Join(setting.CustomPath, relPath)
if com.IsFile(customPath) {
return ioutil.ReadFile(customPath)
}
return bindata.Asset(relPath)
switch tp {
case "readme":
return options.Readme(cleanedName)
case "gitignore":
return options.Gitignore(cleanedName)
case "license":
return options.License(cleanedName)
case "label":
return options.Labels(cleanedName)
default:
return []byte{}, fmt.Errorf("Invalid init file type")
}
}
func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRepoOptions) error {

View File

@@ -158,13 +158,13 @@ func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (
}
oldCommitID := opts.LastCommitID
if opts.NewBranch != opts.OldBranch {
oldCommitID = git.EMPTY_SHA
oldCommitID = git.EmptySHA
}
if err := CommitRepoAction(CommitRepoActionOptions{
PusherName: doer.Name,
RepoOwnerID: repo.MustOwner().ID,
RepoName: repo.Name,
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
RefFullName: git.BranchPrefix + opts.NewBranch,
OldCommitID: oldCommitID,
NewCommitID: commit.ID.String(),
Commits: pushCommits,
@@ -297,7 +297,7 @@ func (repo *Repository) DeleteRepoFile(doer *User, opts DeleteRepoFileOptions) (
PusherName: doer.Name,
RepoOwnerID: repo.MustOwner().ID,
RepoName: repo.Name,
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
RefFullName: git.BranchPrefix + opts.NewBranch,
OldCommitID: opts.LastCommitID,
NewCommitID: commit.ID.String(),
Commits: pushCommits,
@@ -533,7 +533,7 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
PusherName: doer.Name,
RepoOwnerID: repo.MustOwner().ID,
RepoName: repo.Name,
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
RefFullName: git.BranchPrefix + opts.NewBranch,
OldCommitID: opts.LastCommitID,
NewCommitID: commit.ID.String(),
Commits: pushCommits,

View File

@@ -231,7 +231,7 @@ func SyncMirrors() {
m, err := GetMirrorByRepoID(com.StrTo(repoID).MustInt64())
if err != nil {
log.Error(4, "GetMirrorByRepoID [%d]: %v", repoID, err)
log.Error(4, "GetMirrorByRepoID [%s]: %v", repoID, err)
continue
}
@@ -241,7 +241,7 @@ func SyncMirrors() {
m.ScheduleNextUpdate()
if err = UpdateMirror(m); err != nil {
log.Error(4, "UpdateMirror [%d]: %v", repoID, err)
log.Error(4, "UpdateMirror [%s]: %v", repoID, err)
continue
}
}

View File

@@ -88,7 +88,14 @@ func UpdateAccessToken(t *AccessToken) error {
}
// DeleteAccessTokenByID deletes access token by given ID.
func DeleteAccessTokenByID(id int64) error {
_, err := x.Id(id).Delete(new(AccessToken))
return err
func DeleteAccessTokenByID(id, userID int64) error {
cnt, err := x.Id(id).Delete(&AccessToken{
UID: userID,
})
if err != nil {
return err
} else if cnt != 1 {
return ErrAccessTokenNotExist{}
}
return nil
}

View File

@@ -91,10 +91,10 @@ type PushUpdateOptions struct {
// PushUpdate must be called for any push actions in order to
// generates necessary push action history feeds.
func PushUpdate(opts PushUpdateOptions) (err error) {
isNewRef := opts.OldCommitID == git.EMPTY_SHA
isDelRef := opts.NewCommitID == git.EMPTY_SHA
isNewRef := opts.OldCommitID == git.EmptySHA
isDelRef := opts.NewCommitID == git.EmptySHA
if isNewRef && isDelRef {
return fmt.Errorf("Old and new revisions are both %s", git.EMPTY_SHA)
return fmt.Errorf("Old and new revisions are both %s", git.EmptySHA)
}
repoPath := RepoPath(opts.RepoUserName, opts.RepoName)
@@ -106,7 +106,7 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
}
if isDelRef {
log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %d",
log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %s",
opts.RefFullName, opts.RepoUserName, opts.RepoName, opts.PusherName)
return nil
}
@@ -127,7 +127,7 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
}
// Push tags.
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
if err := CommitRepoAction(CommitRepoActionOptions{
PusherName: opts.PusherName,
RepoOwnerID: owner.ID,

View File

@@ -25,6 +25,7 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/nfnt/resize"
"golang.org/x/crypto/pbkdf2"
"code.gitea.io/git"
api "code.gitea.io/sdk/gitea"
@@ -361,7 +362,7 @@ func (u *User) NewGitSig() *git.Signature {
// EncodePasswd encodes password to safe format.
func (u *User) EncodePasswd() {
newPasswd := base.PBKDF2([]byte(u.Passwd), []byte(u.Salt), 10000, 50, sha256.New)
newPasswd := pbkdf2.Key([]byte(u.Passwd), []byte(u.Salt), 10000, 50, sha256.New)
u.Passwd = fmt.Sprintf("%x", newPasswd)
}
@@ -531,7 +532,7 @@ func IsUserExist(uid int64, name string) (bool, error) {
}
// GetUserSalt returns a ramdom user salt token.
func GetUserSalt() string {
func GetUserSalt() (string, error) {
return base.GetRandomString(10)
}
@@ -603,8 +604,12 @@ func CreateUser(u *User) (err error) {
u.LowerName = strings.ToLower(u.Name)
u.AvatarEmail = u.Email
u.Avatar = base.HashEmail(u.AvatarEmail)
u.Rands = GetUserSalt()
u.Salt = GetUserSalt()
if u.Rands, err = GetUserSalt(); err != nil {
return err
}
if u.Salt, err = GetUserSalt(); err != nil {
return err
}
u.EncodePasswd()
u.MaxRepoCreation = -1
@@ -880,8 +885,10 @@ func deleteUser(e *xorm.Session, u *User) error {
}
avatarPath := u.CustomAvatarPath()
if err := os.Remove(avatarPath); err != nil {
return fmt.Errorf("Fail to remove %s: %v", avatarPath, err)
if com.IsExist(avatarPath) {
if err := os.Remove(avatarPath); err != nil {
return fmt.Errorf("Fail to remove %s: %v", avatarPath, err)
}
}
return nil

View File

@@ -5,10 +5,16 @@
package models
import (
"errors"
"fmt"
"strings"
)
var (
// ErrEmailAddressNotExist email address not exist
ErrEmailAddressNotExist = errors.New("Email address does not exist")
)
// EmailAddress is the list of all email addresses of a user. Can contain the
// primary email address, but is not obligatory.
type EmailAddress struct {
@@ -116,7 +122,9 @@ func (email *EmailAddress) Activate() error {
if err != nil {
return err
}
user.Rands = GetUserSalt()
if user.Rands, err = GetUserSalt(); err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
@@ -139,14 +147,25 @@ func (email *EmailAddress) Activate() error {
// DeleteEmailAddress deletes an email address of given user.
func DeleteEmailAddress(email *EmailAddress) (err error) {
if email.ID > 0 {
_, err = x.Id(email.ID).Delete(new(EmailAddress))
} else {
_, err = x.
Where("email=?", email.Email).
Delete(new(EmailAddress))
var deleted int64
// ask to check UID
var address = EmailAddress{
UID: email.UID,
}
return err
if email.ID > 0 {
deleted, err = x.Id(email.ID).Delete(&address)
} else {
deleted, err = x.
Where("email=?", email.Email).
Delete(&address)
}
if err != nil {
return err
} else if deleted != 1 {
return ErrEmailAddressNotExist
}
return nil
}
// DeleteEmailAddresses deletes multiple email addresses

View File

@@ -634,7 +634,7 @@ func DeliverHooks() {
tasks = make([]*HookTask, 0, 5)
if err := x.Where("repo_id=? AND is_delivered=?", repoID, false).Find(&tasks); err != nil {
log.Error(4, "Get repository [%d] hook tasks: %v", repoID, err)
log.Error(4, "Get repository [%s] hook tasks: %v", repoID, err)
continue
}
for _, t := range tasks {

View File

@@ -33,6 +33,7 @@ func ToWikiPageURL(name string) string {
// that are not belong to wiki repository.
func ToWikiPageName(urlString string) string {
name, _ := url.QueryUnescape(strings.Replace(urlString, "-", " ", -1))
name = strings.Replace(name, "\t", " ", -1)
return strings.Replace(strings.TrimLeft(name, "./"), "/", " ", -1)
}
@@ -88,7 +89,7 @@ func discardLocalWikiChanges(localPath string) error {
}
// updateWikiPage adds new page to repository wiki.
func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, message string, isNew bool) (err error) {
func (repo *Repository) updateWikiPage(doer *User, oldWikiPath, wikiPath, content, message string, isNew bool) (err error) {
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
@@ -103,8 +104,8 @@ func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, mes
return fmt.Errorf("UpdateLocalWiki: %v", err)
}
title = ToWikiPageName(title)
filename := path.Join(localPath, title+".md")
title := ToWikiPageName(wikiPath)
filename := path.Join(localPath, wikiPath+".md")
// If not a new file, show perform update not create.
if isNew {
@@ -112,7 +113,7 @@ func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, mes
return ErrWikiAlreadyExist{filename}
}
} else {
file := path.Join(localPath, oldTitle+".md")
file := path.Join(localPath, oldWikiPath+".md")
if err := os.Remove(file); err != nil {
return fmt.Errorf("Fail to remove %s: %v", file, err)
@@ -148,19 +149,19 @@ func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, mes
return nil
}
// AddWikiPage adds a new wiki page with a given title.
func (repo *Repository) AddWikiPage(doer *User, title, content, message string) error {
return repo.updateWikiPage(doer, "", title, content, message, true)
// AddWikiPage adds a new wiki page with a given wikiPath.
func (repo *Repository) AddWikiPage(doer *User, wikiPath, content, message string) error {
return repo.updateWikiPage(doer, "", wikiPath, content, message, true)
}
// EditWikiPage updates a wiki page identified by its title,
// optionally also changing title.
func (repo *Repository) EditWikiPage(doer *User, oldTitle, title, content, message string) error {
return repo.updateWikiPage(doer, oldTitle, title, content, message, false)
// EditWikiPage updates a wiki page identified by its wikiPath,
// optionally also changing wikiPath.
func (repo *Repository) EditWikiPage(doer *User, oldWikiPath, wikiPath, content, message string) error {
return repo.updateWikiPage(doer, oldWikiPath, wikiPath, content, message, false)
}
// DeleteWikiPage deletes a wiki page identified by its title.
func (repo *Repository) DeleteWikiPage(doer *User, title string) (err error) {
// DeleteWikiPage deletes a wiki page identified by its wikiPath.
func (repo *Repository) DeleteWikiPage(doer *User, wikiPath string) (err error) {
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
@@ -171,13 +172,13 @@ func (repo *Repository) DeleteWikiPage(doer *User, title string) (err error) {
return fmt.Errorf("UpdateLocalWiki: %v", err)
}
title = ToWikiPageName(title)
filename := path.Join(localPath, title+".md")
filename := path.Join(localPath, wikiPath+".md")
if err := os.Remove(filename); err != nil {
return fmt.Errorf("Fail to remove %s: %v", filename, err)
}
title := ToWikiPageName(wikiPath)
message := "Delete page '" + title + "'"
if err = git.AddChanges(localPath, true); err != nil {

View File

@@ -151,6 +151,11 @@ func bindUser(l *ldap.Conn, userDN, passwd string) error {
// SearchEntry : search an LDAP source if an entry (name, passwd) is valid and in the specific filter
func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, string, string, string, bool, bool) {
// See https://tools.ietf.org/search/rfc4513#section-5.1.2
if len(passwd) == 0 {
log.Debug("Auth. failed for %s, password cannot be empty")
return "", "", "", "", false, false
}
l, err := dial(ls)
if err != nil {
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)

View File

@@ -5,16 +5,15 @@
package base
import (
"crypto/hmac"
"crypto/md5"
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"fmt"
"hash"
"html/template"
"math"
"math/big"
"net/http"
"strconv"
"strings"
@@ -57,6 +56,9 @@ func DetectEncoding(content []byte) (string, error) {
}
result, err := chardet.NewTextDetector().DetectBest(content)
if err != nil {
return "", err
}
if result.Charset != "UTF-8" && len(setting.Repository.AnsiCharset) > 0 {
log.Debug("Using default AnsiCharset: %s", setting.Repository.AnsiCharset)
return setting.Repository.AnsiCharset, err
@@ -83,57 +85,31 @@ func BasicAuthEncode(username, password string) string {
}
// GetRandomString generate random string by specify chars.
func GetRandomString(n int, alphabets ...byte) string {
func GetRandomString(n int) (string, error) {
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
var bytes = make([]byte, n)
rand.Read(bytes)
for i, b := range bytes {
if len(alphabets) == 0 {
bytes[i] = alphanum[b%byte(len(alphanum))]
} else {
bytes[i] = alphabets[b%byte(len(alphabets))]
buffer := make([]byte, n)
max := big.NewInt(int64(len(alphanum)))
for i := 0; i < n; i++ {
index, err := randomInt(max)
if err != nil {
return "", err
}
buffer[i] = alphanum[index]
}
return string(bytes)
return string(buffer), nil
}
// PBKDF2 http://code.google.com/p/go/source/browse/pbkdf2/pbkdf2.go?repo=crypto
// FIXME: use https://godoc.org/golang.org/x/crypto/pbkdf2?
func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
prf := hmac.New(h, password)
hashLen := prf.Size()
numBlocks := (keyLen + hashLen - 1) / hashLen
var buf [4]byte
dk := make([]byte, 0, numBlocks*hashLen)
U := make([]byte, hashLen)
for block := 1; block <= numBlocks; block++ {
// N.B.: || means concatenation, ^ means XOR
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
// U_1 = PRF(password, salt || uint(i))
prf.Reset()
prf.Write(salt)
buf[0] = byte(block >> 24)
buf[1] = byte(block >> 16)
buf[2] = byte(block >> 8)
buf[3] = byte(block)
prf.Write(buf[:4])
dk = prf.Sum(dk)
T := dk[len(dk)-hashLen:]
copy(U, T)
// U_n = PRF(password, U_(n-1))
for n := 2; n <= iter; n++ {
prf.Reset()
prf.Write(U)
U = U[:0]
U = prf.Sum(U)
for x := range U {
T[x] ^= U[x]
}
}
func randomInt(max *big.Int) (int, error) {
rand, err := rand.Int(rand.Reader, max)
if err != nil {
return 0, err
}
return dk[:keyLen]
return int(rand.Int64()), nil
}
// VerifyTimeLimitCode verify time limit code
@@ -283,19 +259,25 @@ func computeTimeDiff(diff int64) (int64, string) {
diffStr = "1 year"
default:
diffStr = fmt.Sprintf("%d years", diff/Year)
diff = 0
diff -= (diff / Year) * Year
}
return diff, diffStr
}
// TimeSincePro calculates the time interval and generate full user-friendly string.
func TimeSincePro(then time.Time) string {
now := time.Now()
return timeSincePro(then, time.Now())
}
func timeSincePro(then, now time.Time) string {
diff := now.Unix() - then.Unix()
if then.After(now) {
return "future"
}
if diff == 0 {
return "now"
}
var timeStr, diffStr string
for {
@@ -309,9 +291,7 @@ func TimeSincePro(then time.Time) string {
return strings.TrimPrefix(timeStr, ", ")
}
func timeSince(then time.Time, lang string) string {
now := time.Now()
func timeSince(then, now time.Time, lang string) string {
lbl := i18n.Tr(lang, "tool.ago")
diff := now.Unix() - then.Unix()
if then.After(now) {
@@ -322,7 +302,7 @@ func timeSince(then time.Time, lang string) string {
switch {
case diff <= 0:
return i18n.Tr(lang, "tool.now")
case diff <= 2:
case diff <= 1:
return i18n.Tr(lang, "tool.1s", lbl)
case diff < 1*Minute:
return i18n.Tr(lang, "tool.seconds", diff, lbl)
@@ -361,12 +341,18 @@ func timeSince(then time.Time, lang string) string {
// RawTimeSince retrieves i18n key of time since t
func RawTimeSince(t time.Time, lang string) string {
return timeSince(t, lang)
return timeSince(t, time.Now(), lang)
}
// TimeSince calculates the time interval and generate user-friendly string.
func TimeSince(t time.Time, lang string) template.HTML {
return template.HTML(fmt.Sprintf(`<span class="time-since" title="%s">%s</span>`, t.Format(setting.TimeFormat), timeSince(t, lang)))
func TimeSince(then time.Time, lang string) template.HTML {
return htmlTimeSince(then, time.Now(), lang)
}
func htmlTimeSince(then, now time.Time, lang string) template.HTML {
return template.HTML(fmt.Sprintf(`<span class="time-since" title="%s">%s</span>`,
then.Format(setting.TimeFormat),
timeSince(then, now, lang)))
}
// Storage space size types
@@ -451,10 +437,10 @@ func Subtract(left interface{}, right interface{}) interface{} {
case int64:
rright = right.(int64)
case float32:
fright = float64(left.(float32))
fright = float64(right.(float32))
isInt = false
case float64:
fleft = left.(float64)
fright = right.(float64)
isInt = false
}
@@ -486,12 +472,16 @@ func TruncateString(str string, limit int) string {
}
// StringsToInt64s converts a slice of string to a slice of int64.
func StringsToInt64s(strs []string) []int64 {
func StringsToInt64s(strs []string) ([]int64, error) {
ints := make([]int64, len(strs))
for i := range strs {
ints[i] = com.StrTo(strs[i]).MustInt64()
n, err := com.StrTo(strs[i]).Int64()
if err != nil {
return ints, err
}
ints[i] = n
}
return ints
return ints, nil
}
// Int64sToStrings converts a slice of int64 to a slice of string.
@@ -535,3 +525,8 @@ func IsImageFile(data []byte) bool {
func IsPDFFile(data []byte) bool {
return strings.Index(http.DetectContentType(data), "application/pdf") != -1
}
// IsVideoFile detectes if data is an video format
func IsVideoFile(data []byte) bool {
return strings.Index(http.DetectContentType(data), "video/") != -1
}

View File

@@ -4,10 +4,40 @@ import (
"testing"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/i18n"
macaroni18n "github.com/go-macaron/i18n"
"github.com/stretchr/testify/assert"
"os"
"strk.kbt.io/projects/go/libravatar"
"time"
)
var BaseDate time.Time
// time durations
const (
DayDur = 24 * time.Hour
WeekDur = 7 * DayDur
MonthDur = 30 * DayDur
YearDur = 12 * MonthDur
)
func TestMain(m *testing.M) {
// setup
macaroni18n.I18n(macaroni18n.Options{
Directory: "../../options/locale/",
DefaultLang: "en-US",
Langs: []string{"en-US"},
Names: []string{"english"},
})
BaseDate = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
// run the tests
retVal := m.Run()
os.Exit(retVal)
}
func TestEncodeMD5(t *testing.T) {
assert.Equal(t,
"3858f62230ac3c915f300c664312c63f",
@@ -26,7 +56,41 @@ func TestShortSha(t *testing.T) {
assert.Equal(t, "veryverylo", ShortSha("veryverylong"))
}
// TODO: Test DetectEncoding()
func TestDetectEncoding(t *testing.T) {
testSuccess := func(b []byte, expected string) {
encoding, err := DetectEncoding(b)
assert.NoError(t, err)
assert.Equal(t, expected, encoding)
}
// utf-8
b := []byte("just some ascii")
testSuccess(b, "UTF-8")
// utf-8-sig: "hey" (with BOM)
b = []byte{0xef, 0xbb, 0xbf, 0x68, 0x65, 0x79}
testSuccess(b, "UTF-8")
// utf-16: "hey<accented G>"
b = []byte{0xff, 0xfe, 0x68, 0x00, 0x65, 0x00, 0x79, 0x00, 0xf4, 0x01}
testSuccess(b, "UTF-16LE")
// iso-8859-1: d<accented e>cor<newline>
b = []byte{0x44, 0xe9, 0x63, 0x6f, 0x72, 0x0a}
encoding, err := DetectEncoding(b)
assert.NoError(t, err)
// due to a race condition in `chardet` library, it could either detect
// "ISO-8859-1" or "IS0-8859-2" here. Technically either is correct, so
// we accept either.
assert.Contains(t, encoding, "ISO-8859")
setting.Repository.AnsiCharset = "placeholder"
testSuccess(b, "placeholder")
// invalid bytes
b = []byte{0xfa}
_, err = DetectEncoding(b)
assert.Error(t, err)
}
func TestBasicAuthDecode(t *testing.T) {
_, _, err := BasicAuthDecode("?")
@@ -43,7 +107,9 @@ func TestBasicAuthEncode(t *testing.T) {
}
func TestGetRandomString(t *testing.T) {
assert.Len(t, GetRandomString(4), 4)
randomString, err := GetRandomString(4)
assert.NoError(t, err)
assert.Len(t, randomString, 4)
}
// TODO: Test PBKDF2()
@@ -86,11 +152,112 @@ func TestAvatarLink(t *testing.T) {
)
}
// TODO: computeTimeDiff()
// TODO: TimeSincePro()
// TODO: timeSince()
// TODO: RawTimeSince()
// TODO: TimeSince()
func TestComputeTimeDiff(t *testing.T) {
// test that for each offset in offsets,
// computeTimeDiff(base + offset) == (offset, str)
test := func(base int64, str string, offsets ...int64) {
for _, offset := range offsets {
diff, diffStr := computeTimeDiff(base + offset)
assert.Equal(t, offset, diff)
assert.Equal(t, str, diffStr)
}
}
test(0, "now", 0)
test(1, "1 second", 0)
test(2, "2 seconds", 0)
test(Minute, "1 minute", 0, 1, 30, Minute-1)
test(2*Minute, "2 minutes", 0, Minute-1)
test(Hour, "1 hour", 0, 1, Hour-1)
test(5*Hour, "5 hours", 0, Hour-1)
test(Day, "1 day", 0, 1, Day-1)
test(5*Day, "5 days", 0, Day-1)
test(Week, "1 week", 0, 1, Week-1)
test(3*Week, "3 weeks", 0, 4*Day+25000)
test(Month, "1 month", 0, 1, Month-1)
test(10*Month, "10 months", 0, Month-1)
test(Year, "1 year", 0, Year-1)
test(3*Year, "3 years", 0, Year-1)
}
func TestTimeSince(t *testing.T) {
assert.Equal(t, "now", timeSince(BaseDate, BaseDate, "en"))
// test that each diff in `diffs` yields the expected string
test := func(expected string, diffs ...time.Duration) {
ago := i18n.Tr("en", "tool.ago")
fromNow := i18n.Tr("en", "tool.from_now")
for _, diff := range diffs {
actual := timeSince(BaseDate, BaseDate.Add(diff), "en")
assert.Equal(t, expected+" "+ago, actual)
actual = timeSince(BaseDate.Add(diff), BaseDate, "en")
assert.Equal(t, expected+" "+fromNow, actual)
}
}
test("1 second", time.Second, time.Second+50*time.Millisecond)
test("2 seconds", 2*time.Second, 2*time.Second+50*time.Millisecond)
test("1 minute", time.Minute, time.Minute+30*time.Second)
test("2 minutes", 2*time.Minute, 2*time.Minute+30*time.Second)
test("1 hour", time.Hour, time.Hour+30*time.Minute)
test("2 hours", 2*time.Hour, 2*time.Hour+30*time.Minute)
test("1 day", DayDur, DayDur+12*time.Hour)
test("2 days", 2*DayDur, 2*DayDur+12*time.Hour)
test("1 week", WeekDur, WeekDur+3*DayDur)
test("2 weeks", 2*WeekDur, 2*WeekDur+3*DayDur)
test("1 month", MonthDur, MonthDur+15*DayDur)
test("2 months", 2*MonthDur, 2*MonthDur+15*DayDur)
test("1 year", YearDur, YearDur+6*MonthDur)
test("2 years", 2*YearDur, 2*YearDur+6*MonthDur)
}
func TestTimeSincePro(t *testing.T) {
assert.Equal(t, "now", timeSincePro(BaseDate, BaseDate))
// test that a difference of `diff` yields the expected string
test := func(expected string, diff time.Duration) {
actual := timeSincePro(BaseDate, BaseDate.Add(diff))
assert.Equal(t, expected, actual)
assert.Equal(t, "future", timeSincePro(BaseDate.Add(diff), BaseDate))
}
test("1 second", time.Second)
test("2 seconds", 2*time.Second)
test("1 minute", time.Minute)
test("1 minute, 1 second", time.Minute+time.Second)
test("1 minute, 59 seconds", time.Minute+59*time.Second)
test("2 minutes", 2*time.Minute)
test("1 hour", time.Hour)
test("1 hour, 1 second", time.Hour+time.Second)
test("1 hour, 59 minutes, 59 seconds", time.Hour+59*time.Minute+59*time.Second)
test("2 hours", 2*time.Hour)
test("1 day", DayDur)
test("1 day, 23 hours, 59 minutes, 59 seconds",
DayDur+23*time.Hour+59*time.Minute+59*time.Second)
test("2 days", 2*DayDur)
test("1 week", WeekDur)
test("2 weeks", 2*WeekDur)
test("1 month", MonthDur)
test("3 months", 3*MonthDur)
test("1 year", YearDur)
test("2 years, 3 months, 1 week, 2 days, 4 hours, 12 minutes, 17 seconds",
2*YearDur+3*MonthDur+WeekDur+2*DayDur+4*time.Hour+
12*time.Minute+17*time.Second)
}
func TestHtmlTimeSince(t *testing.T) {
setting.TimeFormat = time.UnixDate
// test that `diff` yields a result containing `expected`
test := func(expected string, diff time.Duration) {
actual := htmlTimeSince(BaseDate, BaseDate.Add(diff), "en")
assert.Contains(t, actual, `title="Sat Jan 1 00:00:00 UTC 2000"`)
assert.Contains(t, actual, expected)
}
test("1 second", time.Second)
test("3 minutes", 3*time.Minute+5*time.Second)
test("1 day", DayDur+18*time.Hour)
test("1 week", WeekDur+6*DayDur)
test("3 months", 3*MonthDur+3*WeekDur)
test("2 years", 2*YearDur)
test("3 years", 3*YearDur+11*MonthDur+4*WeekDur)
}
func TestFileSize(t *testing.T) {
var size int64
@@ -106,11 +273,48 @@ func TestFileSize(t *testing.T) {
assert.Equal(t, "512TB", FileSize(size))
size = size * 1024
assert.Equal(t, "512PB", FileSize(size))
//size = size * 1024 TODO: Fix bug for EB
//assert.Equal(t, "512EB", FileSize(size))
size = size * 4
assert.Equal(t, "2.0EB", FileSize(size))
}
// TODO: Subtract()
func TestSubtract(t *testing.T) {
toFloat64 := func(n interface{}) float64 {
switch n.(type) {
case int:
return float64(n.(int))
case int8:
return float64(n.(int8))
case int16:
return float64(n.(int16))
case int32:
return float64(n.(int32))
case int64:
return float64(n.(int64))
case float32:
return float64(n.(float32))
case float64:
return n.(float64)
default:
return 0.0
}
}
values := []interface{}{
int(-3),
int8(14),
int16(81),
int32(-156),
int64(1528),
float32(3.5),
float64(-15.348),
}
for _, left := range values {
for _, right := range values {
expected := toFloat64(left) - toFloat64(right)
sub := Subtract(left, right)
assert.InDelta(t, expected, sub, 1e-3)
}
}
}
func TestEllipsisString(t *testing.T) {
assert.Equal(t, "...", EllipsisString("foobar", 0))
@@ -135,14 +339,18 @@ func TestTruncateString(t *testing.T) {
}
func TestStringsToInt64s(t *testing.T) {
assert.Equal(t, []int64{}, StringsToInt64s([]string{}))
assert.Equal(t,
[]int64{1, 4, 16, 64, 256},
StringsToInt64s([]string{"1", "4", "16", "64", "256"}),
)
testSuccess := func(input []string, expected []int64) {
result, err := StringsToInt64s(input)
assert.NoError(t, err)
assert.Equal(t, expected, result)
}
testSuccess([]string{}, []int64{})
testSuccess([]string{"-1234"}, []int64{-1234})
testSuccess([]string{"1", "4", "16", "64", "256"},
[]int64{1, 4, 16, 64, 256})
// TODO: StringsToInt64s should return ([]int64, error)
assert.Equal(t, []int64{-1, 0, 0}, StringsToInt64s([]string{"-1", "a", "$"}))
_, err := StringsToInt64s([]string{"-1", "a", "$"})
assert.Error(t, err)
}
func TestInt64sToStrings(t *testing.T) {

File diff suppressed because one or more lines are too long

View File

@@ -39,6 +39,17 @@ func NewLogger(bufLen int64, mode, config string) {
}
}
// DelLogger removes loggers that are for the given mode
func DelLogger(mode string) error {
for _, l := range loggers {
if _, ok := l.outputs[mode]; ok {
return l.DelLogger(mode)
}
}
Trace("Log adapter %s not found, no need to delete", mode)
return nil
}
// NewGitLogger create a logger for git
// FIXME: use same log level as other loggers.
func NewGitLogger(logPath string) {

View File

@@ -0,0 +1,99 @@
// +build !bindata
// 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 options
import (
"fmt"
"io/ioutil"
"path"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/com"
)
var (
directories = make(directorySet)
)
// Dir returns all files from static or custom directory.
func Dir(name string) ([]string, error) {
if directories.Filled(name) {
return directories.Get(name), nil
}
var (
result []string
)
customDir := path.Join(setting.CustomPath, "options", name)
if com.IsDir(customDir) {
files, err := com.StatDir(customDir, true)
if err != nil {
return []string{}, fmt.Errorf("Failed to read custom directory. %v", err)
}
result = append(result, files...)
}
staticDir := path.Join(setting.StaticRootPath, "options", name)
if com.IsDir(staticDir) {
files, err := com.StatDir(staticDir, true)
if err != nil {
return []string{}, fmt.Errorf("Failed to read static directory. %v", err)
}
result = append(result, files...)
}
return directories.AddAndGet(name, result), nil
}
// Locale reads the content of a specific locale from static or custom path.
func Locale(name string) ([]byte, error) {
return fileFromDir(path.Join("locale", name))
}
// Readme reads the content of a specific readme from static or custom path.
func Readme(name string) ([]byte, error) {
return fileFromDir(path.Join("readme", name))
}
// Gitignore reads the content of a specific gitignore from static or custom path.
func Gitignore(name string) ([]byte, error) {
return fileFromDir(path.Join("gitignore", name))
}
// License reads the content of a specific license from static or custom path.
func License(name string) ([]byte, error) {
return fileFromDir(path.Join("license", name))
}
// Labels eads the content of a specific labels from static or custom path.
func Labels(name string) ([]byte, error) {
return fileFromDir(path.Join("label", name))
}
// fileFromDir is a helper to read files from static or custom path.
func fileFromDir(name string) ([]byte, error) {
customPath := path.Join(setting.CustomPath, "options", name)
if com.IsFile(customPath) {
return ioutil.ReadFile(customPath)
}
staticPath := path.Join(setting.StaticRootPath, "options", name)
if com.IsFile(staticPath) {
return ioutil.ReadFile(staticPath)
}
return []byte{}, fmt.Errorf("Asset file does not exist: %s", name)
}

View File

@@ -0,0 +1,51 @@
// 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 options
//go:generate go-bindata -tags "bindata" -ignore "TRANSLATORS" -pkg "options" -o "bindata.go" ../../options/...
//go:generate go fmt bindata.go
//go:generate sed -i.bak s/..\/..\/options\/// bindata.go
//go:generate rm -f bindata.go.bak
type directorySet map[string][]string
func (s directorySet) Add(key string, value []string) {
_, ok := s[key]
if !ok {
s[key] = make([]string, 0, len(value))
}
s[key] = append(s[key], value...)
}
func (s directorySet) Get(key string) []string {
_, ok := s[key]
if ok {
result := []string{}
seen := map[string]string{}
for _, val := range s[key] {
if _, ok := seen[val]; !ok {
result = append(result, val)
seen[val] = val
}
}
return result
}
return []string{}
}
func (s directorySet) AddAndGet(key string, value []string) []string {
s.Add(key, value)
return s.Get(key)
}
func (s directorySet) Filled(key string) bool {
return len(s[key]) > 0
}

89
modules/options/static.go Normal file
View File

@@ -0,0 +1,89 @@
// +build bindata
// 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 options
import (
"fmt"
"io/ioutil"
"path"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/com"
)
var (
directories = make(directorySet)
)
// Dir returns all files from bindata or custom directory.
func Dir(name string) ([]string, error) {
if directories.Filled(name) {
return directories.Get(name), nil
}
var (
result []string
)
customDir := path.Join(setting.CustomPath, "options", name)
if com.IsDir(customDir) {
files, err := com.StatDir(customDir, true)
if err != nil {
return []string{}, fmt.Errorf("Failed to read custom directory. %v", err)
}
result = append(result, files...)
}
files, err := AssetDir(path.Join("..", "..", "options", name))
if err != nil {
return []string{}, fmt.Errorf("Failed to read embedded directory. %v", err)
}
result = append(result, files...)
return directories.AddAndGet(name, result), nil
}
// Locale reads the content of a specific locale from bindata or custom path.
func Locale(name string) ([]byte, error) {
return fileFromDir(path.Join("locale", name))
}
// Readme reads the content of a specific readme from bindata or custom path.
func Readme(name string) ([]byte, error) {
return fileFromDir(path.Join("readme", name))
}
// Gitignore reads the content of a gitignore locale from bindata or custom path.
func Gitignore(name string) ([]byte, error) {
return fileFromDir(path.Join("gitignore", name))
}
// License reads the content of a specific license from bindata or custom path.
func License(name string) ([]byte, error) {
return fileFromDir(path.Join("license", name))
}
// Labels eads the content of a specific labels from static or custom path.
func Labels(name string) ([]byte, error) {
return fileFromDir(path.Join("label", name))
}
// fileFromDir is a helper to read files from bindata or custom path.
func fileFromDir(name string) ([]byte, error) {
customPath := path.Join(setting.CustomPath, "options", name)
if com.IsFile(customPath) {
return ioutil.ReadFile(customPath)
}
return Asset(name)
}

View File

@@ -6,6 +6,8 @@ package public
//go:generate go-bindata -tags "bindata" -ignore "\\.go|\\.less" -pkg "public" -o "bindata.go" ../../public/...
//go:generate go fmt bindata.go
//go:generate sed -i.bak s/..\/..\/public\/// bindata.go
//go:generate rm -f bindata.go.bak
// Options represents the available options to configure the macaron handler.
type Options struct {

View File

@@ -22,7 +22,7 @@ func Static(opts *Options) macaron.Handler {
AssetDir: AssetDir,
AssetInfo: AssetInfo,
AssetNames: AssetNames,
Prefix: "../../public",
Prefix: "",
}),
},
)

View File

@@ -0,0 +1,10 @@
package setting
import (
"strings"
)
var (
defaultLangs = strings.Split("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", ",")
defaultLangNames = strings.Split("English,简体中文,繁體中文(香港),繁體中文(台湾),Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen,Türkçe,čeština,Српски,Svenska,한국어", ",")
)

View File

@@ -17,6 +17,8 @@ import (
"strings"
"time"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/user"
"github.com/Unknwon/com"
_ "github.com/go-macaron/cache/memcache" // memcache plugin for cache
_ "github.com/go-macaron/cache/redis"
@@ -25,10 +27,6 @@ import (
_ "github.com/kardianos/minwinsvc" // import minwinsvc for windows services
"gopkg.in/ini.v1"
"strk.kbt.io/projects/go/libravatar"
"code.gitea.io/gitea/modules/bindata"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/user"
)
// Scheme describes protocol types
@@ -53,10 +51,6 @@ const (
// settings
var (
// BuildTime information should only be set by -ldflags.
BuildTime string
BuildGitHash string
// AppVer settings
AppVer string
AppName string
@@ -86,6 +80,7 @@ var (
StartBuiltinServer bool `ini:"START_SSH_SERVER"`
Domain string `ini:"SSH_DOMAIN"`
Port int `ini:"SSH_PORT"`
ListenHost string `ini:"SSH_LISTEN_HOST"`
ListenPort int `ini:"SSH_LISTEN_PORT"`
RootPath string `ini:"SSH_ROOT_PATH"`
KeyTestPath string `ini:"SSH_KEY_TEST_PATH"`
@@ -109,16 +104,21 @@ var (
UseTiDB bool
// Webhook settings
Webhook struct {
Webhook = struct {
QueueLength int
DeliverTimeout int
SkipTLSVerify bool
Types []string
PagingNum int
}{
QueueLength: 1000,
DeliverTimeout: 5,
SkipTLSVerify: false,
PagingNum: 10,
}
// Repository settings
Repository struct {
Repository = struct {
AnsiCharset string
ForcePrivate bool
MaxCreationLimit int
@@ -141,12 +141,44 @@ var (
FileMaxSize int64
MaxFiles int
} `ini:"-"`
}{
AnsiCharset: "",
ForcePrivate: false,
MaxCreationLimit: -1,
MirrorQueueLength: 1000,
PullRequestQueueLength: 1000,
PreferredLicenses: []string{"Apache License 2.0,MIT License"},
DisableHTTPGit: false,
// Repository editor settings
Editor: struct {
LineWrapExtensions []string
PreviewableFileModes []string
}{
LineWrapExtensions: strings.Split(".txt,.md,.markdown,.mdown,.mkd,", ","),
PreviewableFileModes: []string{"markdown"},
},
// Repository upload settings
Upload: struct {
Enabled bool
TempPath string
AllowedTypes []string `delim:"|"`
FileMaxSize int64
MaxFiles int
}{
Enabled: true,
TempPath: "data/tmp/uploads",
AllowedTypes: []string{},
FileMaxSize: 3,
MaxFiles: 5,
},
}
RepoRootPath string
ScriptType string
ScriptType = "bash"
// UI settings
UI struct {
UI = struct {
ExplorePagingNum int
IssuePagingNum int
FeedMaxCommitNum int
@@ -162,13 +194,38 @@ var (
User struct {
RepoPagingNum int
} `ini:"ui.user"`
}{
ExplorePagingNum: 20,
IssuePagingNum: 10,
FeedMaxCommitNum: 5,
ThemeColorMetaTag: `#6cc644`,
MaxDisplayFileSize: 8388608,
Admin: struct {
UserPagingNum int
RepoPagingNum int
NoticePagingNum int
OrgPagingNum int
}{
UserPagingNum: 50,
RepoPagingNum: 50,
NoticePagingNum: 25,
OrgPagingNum: 50,
},
User: struct {
RepoPagingNum int
}{
RepoPagingNum: 15,
},
}
// Markdown sttings
Markdown struct {
Markdown = struct {
EnableHardLineBreak bool
CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
FileExtensions []string
}{
EnableHardLineBreak: false,
FileExtensions: strings.Split(".md,.markdown,.mdown,.mkd", ","),
}
// Picture settings
@@ -203,7 +260,7 @@ var (
CSRFCookieName = "_csrf"
// Cron tasks
Cron struct {
Cron = struct {
UpdateMirror struct {
Enabled bool
RunAtStart bool
@@ -221,10 +278,37 @@ var (
RunAtStart bool
Schedule string
} `ini:"cron.check_repo_stats"`
}{
UpdateMirror: struct {
Enabled bool
RunAtStart bool
Schedule string
}{
Schedule: "@every 10m",
},
RepoHealthCheck: struct {
Enabled bool
RunAtStart bool
Schedule string
Timeout time.Duration
Args []string `delim:" "`
}{
Schedule: "@every 24h",
Timeout: 60 * time.Second,
Args: []string{},
},
CheckRepoStats: struct {
Enabled bool
RunAtStart bool
Schedule string
}{
RunAtStart: true,
Schedule: "@every 24h",
},
}
// Git settings
Git struct {
Git = struct {
DisableDiffHighlight bool
MaxGitDiffLines int
MaxGitDiffLineCharacters int
@@ -237,16 +321,39 @@ var (
Pull int
GC int `ini:"GC"`
} `ini:"git.timeout"`
}{
DisableDiffHighlight: false,
MaxGitDiffLines: 1000,
MaxGitDiffLineCharacters: 500,
MaxGitDiffFiles: 100,
GCArgs: []string{},
Timeout: struct {
Migrate int
Mirror int
Clone int
Pull int
GC int `ini:"GC"`
}{
Migrate: 600,
Mirror: 300,
Clone: 300,
Pull: 300,
GC: 60,
},
}
// Mirror settings
Mirror struct {
Mirror = struct {
DefaultInterval int
}{
DefaultInterval: 8,
}
// API settings
API struct {
API = struct {
MaxResponseItems int
}{
MaxResponseItems: 50,
}
// I18n settings
@@ -352,9 +459,10 @@ func NewContext() {
log.Fatal(4, "Fail to get work directory: %v", err)
}
Cfg, err = ini.Load(bindata.MustAsset("conf/app.ini"))
Cfg = ini.Empty()
if err != nil {
log.Fatal(4, "Fail to parse 'conf/app.ini': %v", err)
log.Fatal(4, "Fail to parse 'app.ini': %v", err)
}
CustomPath = os.Getenv("GITEA_CUSTOM")
@@ -447,6 +555,10 @@ please consider changing to GITEA_CUSTOM`)
if err = Cfg.Section("server").MapTo(&SSH); err != nil {
log.Fatal(4, "Fail to map SSH settings: %v", err)
}
SSH.KeygenPath = sec.Key("SSH_KEYGEN_PATH").MustString("ssh-keygen")
SSH.Port = sec.Key("SSH_PORT").MustInt(22)
// When disable SSH, start builtin server value is ignored.
if SSH.Disabled {
SSH.StartBuiltinServer = false
@@ -470,11 +582,11 @@ please consider changing to GITEA_CUSTOM`)
}
sec = Cfg.Section("security")
InstallLock = sec.Key("INSTALL_LOCK").MustBool()
SecretKey = sec.Key("SECRET_KEY").String()
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt()
CookieUserName = sec.Key("COOKIE_USERNAME").String()
CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String()
InstallLock = sec.Key("INSTALL_LOCK").MustBool(false)
SecretKey = sec.Key("SECRET_KEY").MustString("!#@FDEWREWR&*(")
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7)
CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome")
CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible")
ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
sec = Cfg.Section("attachment")
@@ -505,7 +617,7 @@ please consider changing to GITEA_CUSTOM`)
"StampNano": time.StampNano,
}[Cfg.Section("time").Key("FORMAT").MustString("RFC1123")]
RunUser = Cfg.Section("").Key("RUN_USER").String()
RunUser = Cfg.Section("").Key("RUN_USER").MustString(user.CurrentUsername())
// Does not check run user when the install lock is off.
if InstallLock {
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
@@ -548,6 +660,8 @@ please consider changing to GITEA_CUSTOM`)
GravatarSource = "http://gravatar.duoshuo.com/avatar/"
case "gravatar":
GravatarSource = "https://secure.gravatar.com/avatar/"
case "libravatar":
GravatarSource = "https://seccdn.libravatar.org/avatar/"
default:
GravatarSource = source
}
@@ -594,12 +708,18 @@ please consider changing to GITEA_CUSTOM`)
}
Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
if len(Langs) == 0 {
Langs = defaultLangs
}
Names = Cfg.Section("i18n").Key("NAMES").Strings(",")
if len(Names) == 0 {
Names = defaultLangNames
}
dateLangs = Cfg.Section("i18n.datelang").KeysHash()
ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool()
ShowFooterVersion = Cfg.Section("other").Key("SHOW_FOOTER_VERSION").MustBool()
ShowFooterTemplateLoadTime = Cfg.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool()
ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool(false)
ShowFooterVersion = Cfg.Section("other").Key("SHOW_FOOTER_VERSION").MustBool(true)
ShowFooterTemplateLoadTime = Cfg.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool(true)
HasRobotsTxt = com.IsFile(path.Join(CustomPath, "robots.txt"))
}
@@ -640,21 +760,28 @@ var logLevels = map[string]string{
}
func newLogService() {
log.Info("%s %s", AppName, AppVer)
log.Info("Gitea v%s", AppVer)
if len(BuildTime) > 0 {
log.Info("Build Time: %s", BuildTime)
log.Info("Build Git Hash: %s", BuildGitHash)
}
// Get and check log mode.
LogModes = strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
LogConfigs = make([]string, len(LogModes))
useConsole := false
for _, mode := range LogModes {
if mode == "console" {
useConsole = true
}
}
if (!useConsole) {
log.DelLogger("console")
}
for i, mode := range LogModes {
mode = strings.TrimSpace(mode)
sec, err := Cfg.GetSection("log." + mode)
if err != nil {
log.Fatal(4, "Unknown log mode: %s", mode)
sec, _ = Cfg.NewSection("log." + mode)
}
validLevels := []string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"}
@@ -692,11 +819,11 @@ func newLogService() {
sec.Key("PROTOCOL").In("tcp", []string{"tcp", "unix", "udp"}),
sec.Key("ADDR").MustString(":7020"))
case "smtp":
LogConfigs[i] = fmt.Sprintf(`{"level":%s,"username":"%s","password":"%s","host":"%s","sendTos":"%s","subject":"%s"}`, level,
LogConfigs[i] = fmt.Sprintf(`{"level":%s,"username":"%s","password":"%s","host":"%s","sendTos":["%s"],"subject":"%s"}`, level,
sec.Key("USER").MustString("example@example.com"),
sec.Key("PASSWD").MustString("******"),
sec.Key("HOST").MustString("127.0.0.1:25"),
sec.Key("RECEIVERS").MustString("[]"),
strings.Replace(sec.Key("RECEIVERS").MustString("example@example.com"), ",", "\",\"", -1),
sec.Key("SUBJECT").MustString("Diagnostic message from serve"))
case "database":
LogConfigs[i] = fmt.Sprintf(`{"level":%s,"driver":"%s","conn":"%s"}`, level,
@@ -729,7 +856,7 @@ func newSessionService() {
SessionConfig.ProviderConfig = strings.Trim(Cfg.Section("session").Key("PROVIDER_CONFIG").String(), "\" ")
SessionConfig.CookieName = Cfg.Section("session").Key("COOKIE_NAME").MustString("i_like_gogits")
SessionConfig.CookiePath = AppSubURL
SessionConfig.Secure = Cfg.Section("session").Key("COOKIE_SECURE").MustBool()
SessionConfig.Secure = Cfg.Section("session").Key("COOKIE_SECURE").MustBool(false)
SessionConfig.Gclifetime = Cfg.Section("session").Key("GC_INTERVAL_TIME").MustInt64(86400)
SessionConfig.Maxlifetime = Cfg.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)

View File

@@ -110,10 +110,10 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
}
}
func listen(config *ssh.ServerConfig, port int) {
listener, err := net.Listen("tcp", "0.0.0.0:"+com.ToStr(port))
func listen(config *ssh.ServerConfig, host string, port int) {
listener, err := net.Listen("tcp", host+":"+com.ToStr(port))
if err != nil {
panic(err)
log.Fatal(4, "Fail to start SSH server: %v", err)
}
for {
// Once a ServerConfig has been configured, connections can be accepted.
@@ -148,7 +148,7 @@ func listen(config *ssh.ServerConfig, port int) {
}
// Listen starts a SSH server listens on given port.
func Listen(port int) {
func Listen(host string, port int) {
config := &ssh.ServerConfig{
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key))))
@@ -185,5 +185,5 @@ func Listen(port int) {
}
config.AddHostKey(private)
go listen(config, port)
go listen(config, host, port)
}

View File

@@ -0,0 +1,103 @@
// +build !bindata
// 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 templates
import (
"html/template"
"io/ioutil"
"path"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/com"
"gopkg.in/macaron.v1"
)
var (
templates = template.New("")
)
// Renderer implements the macaron handler for serving the templates.
func Renderer() macaron.Handler {
return macaron.Renderer(macaron.RenderOptions{
Funcs: NewFuncMap(),
Directory: path.Join(setting.StaticRootPath, "templates"),
AppendDirectories: []string{
path.Join(setting.CustomPath, "templates"),
},
})
}
// Mailer provides the templates required for sending notification mails.
func Mailer() *template.Template {
for _, funcs := range NewFuncMap() {
templates.Funcs(funcs)
}
staticDir := path.Join(setting.StaticRootPath, "templates", "mail")
if com.IsDir(staticDir) {
files, err := com.StatDir(staticDir)
if err != nil {
log.Warn("Failed to read %s templates dir. %v", staticDir, err)
} else {
for _, filePath := range files {
if !strings.HasSuffix(filePath, ".tmpl") {
continue
}
content, err := ioutil.ReadFile(path.Join(staticDir, filePath))
if err != nil {
log.Warn("Failed to read static %s template. %v", filePath, err)
continue
}
templates.New(
strings.TrimSuffix(
filePath,
".tmpl",
),
).Parse(string(content))
}
}
}
customDir := path.Join(setting.CustomPath, "templates", "mail")
if com.IsDir(customDir) {
files, err := com.StatDir(customDir)
if err != nil {
log.Warn("Failed to read %s templates dir. %v", customDir, err)
} else {
for _, filePath := range files {
if !strings.HasSuffix(filePath, ".tmpl") {
continue
}
content, err := ioutil.ReadFile(path.Join(customDir, filePath))
if err != nil {
log.Warn("Failed to read custom %s template. %v", filePath, err)
continue
}
templates.New(
strings.TrimSuffix(
filePath,
".tmpl",
),
).Parse(string(content))
}
}
}
return templates
}

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package template
package templates
import (
"container/list"
@@ -15,6 +15,7 @@ import (
"strings"
"time"
"github.com/microcosm-cc/bluemonday"
"golang.org/x/net/html/charset"
"golang.org/x/text/transform"
"gopkg.in/editorconfig/editorconfig-core-go.v1"
@@ -61,6 +62,7 @@ func NewFuncMap() []template.FuncMap {
},
"AvatarLink": base.AvatarLink,
"Safe": Safe,
"Sanitize": bluemonday.UGCPolicy().Sanitize,
"Str2html": Str2html,
"TimeSince": base.TimeSince,
"RawTimeSince": base.RawTimeSince,

109
modules/templates/static.go Normal file
View File

@@ -0,0 +1,109 @@
// +build bindata
// 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 templates
import (
"html/template"
"io/ioutil"
"path"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/com"
"github.com/go-macaron/bindata"
"gopkg.in/macaron.v1"
)
var (
templates = template.New("")
)
// Renderer implements the macaron handler for serving the templates.
func Renderer() macaron.Handler {
return macaron.Renderer(macaron.RenderOptions{
Funcs: NewFuncMap(),
AppendDirectories: []string{
path.Join(setting.CustomPath, "templates"),
},
TemplateFileSystem: bindata.Templates(
bindata.Options{
Asset: Asset,
AssetDir: AssetDir,
AssetInfo: AssetInfo,
AssetNames: AssetNames,
Prefix: "",
},
),
})
}
// Mailer provides the templates required for sending notification mails.
func Mailer() *template.Template {
for _, funcs := range NewFuncMap() {
templates.Funcs(funcs)
}
for _, assetPath := range AssetNames() {
if !strings.HasPrefix(assetPath, "mail/") {
continue
}
if !strings.HasSuffix(assetPath, ".tmpl") {
continue
}
content, err := Asset(assetPath)
if err != nil {
log.Warn("Failed to read embedded %s template. %v", assetPath, err)
continue
}
templates.New(
strings.TrimPrefix(
strings.TrimSuffix(
assetPath,
".tmpl",
),
"mail/",
),
).Parse(string(content))
}
customDir := path.Join(setting.CustomPath, "templates", "mail")
if com.IsDir(customDir) {
files, err := com.StatDir(customDir)
if err != nil {
log.Warn("Failed to read %s templates dir. %v", customDir, err)
} else {
for _, filePath := range files {
if !strings.HasSuffix(filePath, ".tmpl") {
continue
}
content, err := ioutil.ReadFile(path.Join(customDir, filePath))
if err != nil {
log.Warn("Failed to read custom %s template. %v", filePath, err)
continue
}
templates.New(
strings.TrimSuffix(
filePath,
".tmpl",
),
).Parse(string(content))
}
}
}
return templates
}

View File

@@ -0,0 +1,10 @@
// 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 templates
//go:generate go-bindata -tags "bindata" -ignore "\\.go" -pkg "templates" -o "bindata.go" ../../templates/...
//go:generate go fmt bindata.go
//go:generate sed -i.bak s/..\/..\/templates\/// bindata.go
//go:generate rm -f bindata.go.bak

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