Compare commits

...

124 Commits

Author SHA1 Message Date
Lunny Xiao
53efbeadc1 bug fix for dump when data directoryis not exist (#1025) (#1100) 2017-03-16 09:23:12 +08:00
Lunny Xiao
3d1ff149a2 add back the default setting values and fix #739 (#1093) (#1098) 2017-03-02 08:26:21 +08:00
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
Kim "BKC" Carlbäcker
cd0ce9f3d8 Awlays build, even when it thinks it's up to date (#351) 2016-12-05 22:58:04 +08:00
Thomas Boerger
70134323d1 Merge pull request #348 from tboerger/release-fixes
Fix drone release publishing and test steps
2016-12-05 14:49:00 +01:00
Thomas Boerger
8a28130540 Fixed build tags and deps for all build/test steps 2016-12-05 14:34:55 +01:00
Thomas Boerger
e52b24ad5d Properly move releases within drone builds 2016-12-05 14:31:49 +01:00
Antonio Facciolo
947d2ee21b Fixes #316
Export Pusher name as GITEA_PUSHER_NAME env variable
Export also GITEA_UUID, but keep the uuid env variable for backward compatibility

export pusher name ENV variable #316

change env variable prefix to GITEA_

Signed-off-by: Antonio Facciolo <afdev82@gmail.com>

Export also GITEA_UUID #316

Keep uuid env variable for backward compatibility
2016-12-05 12:25:45 +01:00
Kim "BKC" Carlbäcker
d07c955e2a Fix regression in PR-API #248 (#349)
* Fix #344 (regression in PR-API #248)
2016-12-05 12:17:39 +01:00
Thomas Boerger
edae0f134c Merge pull request #347 from thehowl/fix-contributing-typos
Fix typos in CONTRIBUTING
2016-12-05 08:22:16 +01:00
Morgan Bazalgette
db29855d2d Apply suggested changes 2016-12-04 22:50:36 +01:00
Morgan Bazalgette
e6cb9a7397 Fix typos in CONTRIBUTING
Signed-off-by: Morgan Bazalgette <the@howl.moe>
2016-12-04 20:56:21 +01:00
Andrey Nering
dc14d0c046 Merge pull request #345 from Bwko/fix_for_320
Fix for #320
2016-12-03 20:06:05 -02:00
Bwko
0118b275b6 Fix for #320
Suppress the error when we're removing a file that may not exist
2016-12-03 22:31:54 +01:00
Denis Denisov
c8f300b2cd Safe compare password (timing attack) (#338) 2016-12-03 13:49:17 +08:00
Thomas Boerger
db6a4e9fbf Merge pull request #334 from avelino/scripts_project_name_update
Fixed project name on scripts
2016-12-02 20:13:20 +01:00
Avelino
b21bf80dd4 update SERVICENAME on init scripts 2016-12-02 15:52:28 -02:00
Kim "BKC" Carlbäcker
0f05470cb8 [API] Pull Requests (#248) 2016-12-02 12:10:39 +01:00
Kim "BKC" Carlbäcker
d7ed78a919 Merge pull request #227 from go-gitea/api/github-compliance
GitHub API Compliance Fixes
2016-12-02 10:04:15 +01:00
Kim "BKC" Carlbäcker
e8e0539b45 Linting 2016-12-02 09:31:44 +01:00
Kim "BKC" Carlbäcker
e6cfccdd40 GitHub API Compliance (& linting) 2016-12-02 09:18:15 +01:00
Kim "BKC" Carlbäcker
71bb6df75a Add undocumented endpoint for /repositories/:id 2016-12-02 09:18:15 +01:00
Avelino
bea9d55da6 Fixed project name on setting module key APP_NAME 2016-12-02 07:52:27 +01:00
Avelino
d93429af8b Fixed project name on base template head 2016-12-02 07:48:11 +01:00
Avelino
7e09f80ee3 Fixed project name on repo template mail 2016-12-02 07:46:31 +01:00
Avelino
baf60bf603 Fixed project on repo template hook settings 2016-12-02 07:46:02 +01:00
Bwko
4ff0db0246 Catch os... errors 2016-12-02 07:41:19 +01:00
Avelino
79bd7648b0 fixed typo on rename project name scripts for windows (bat) 2016-12-02 03:51:34 -02:00
Avelino
b78d3f5865 Fixed project name on scripts 2016-12-02 03:18:58 -02:00
Bwko
5ab85372da Added rel="noopener" to target="_blank" hrefs (#327)
* Added rel="noopener" to target="_blank" hrefs

* Replaced gogs.io/docs with docs.gitea.io
2016-12-02 09:12:16 +08:00
Lunny Xiao
1ae6ccb5f1 Bug fixed for .dockerignore (#329)
* bug fixed for .dockerignore

* clean up
2016-12-01 23:05:28 +08:00
Andrey Nering
0a6d9295df Merge pull request #326 from tboerger/maintainers
Added real name of Bwko to maintainers file
2016-12-01 13:03:32 -02:00
Thomas Boerger
6598745f07 Copy gitea binary to docker from correct path (#325)
Signed-off-by: Thomas Boerger <tboerger@suse.de>
2016-12-01 18:53:26 +08:00
Lunny Xiao
590a79ff8a Resolved #296 (#324)
* resolved #296

* Indentation fixed
2016-12-01 18:52:57 +08:00
Lunny Xiao
2343feadd4 resolved #310: hide fork to self (#323) 2016-12-01 18:51:50 +08:00
Thomas Boerger
bb3ed784bc Added real name of Bwko to maintainers file
Signed-off-by: Thomas Boerger <tboerger@suse.de>
2016-12-01 10:26:34 +01:00
Kim "BKC" Carlbäcker
31950cb262 Merge pull request #322 from lunny/lunny/pull_typo
typo in model/pull.go
2016-12-01 09:20:48 +01:00
Thomas Boerger
2932042a6d Get rid of bin folder within makefile, enabled TiDB (#319)
* Get rid of the bin folder within the build process

Signed-off-by: Thomas Boerger <thomas@webhippie.de>

* Dropped latest make task, it is unused

Signed-off-by: Thomas Boerger <thomas@webhippie.de>

* Added tidb tag to drone config

Signed-off-by: Thomas Boerger <thomas@webhippie.de>

* Dropped the cert build tag

Signed-off-by: Thomas Boerger <thomas@webhippie.de>

* Dropped useless minwinsvc build tag

Signed-off-by: Thomas Boerger <thomas@webhippie.de>

* Dropped the useless build tags from drone config

Signed-off-by: Thomas Boerger <thomas@webhippie.de>
2016-12-01 15:28:43 +08:00
Lunny Xiao
646e02b521 typo 2016-12-01 09:05:32 +08:00
Andrey Nering
bf0edcbdea Merge pull request #318 from stroucki/20161128locale
Suggested de locale fix
2016-11-30 19:40:29 -02:00
Michael Stroucken
4bd5730e02 Based on @tboerger's screenshot, these "times" are counts and not
clock times. Change translation to reflect that.
2016-11-30 13:25:05 -05:00
Sandro Santilli
a3fb627350 Have "make" create the executable in root dir (#247)
Same as "go build".
Makes it functional by default as it'd then find template/ and public/
by default w/out setting GITEA_WORK_DIR
2016-11-30 23:59:17 +08:00
Matthias Loibl
6dc6926abe Merge pull request #306 from Bwko/Security
Fixes xss, clickjacking & password autocompletion
2016-11-30 08:22:45 +01:00
Bwko
1e9730a779 Fixes xss, clickjacking & password autocompletion 2016-11-29 22:49:06 +01:00
395 changed files with 4682 additions and 6746 deletions

View File

@@ -1,5 +1,5 @@
*
!gitea
!docker
!bin
!public
!templates

View File

@@ -3,15 +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: cert sqlite pam miniwinsvc
TAGS: sqlite bindata
GOPATH: /srv/app
commands:
- apk -U add linux-pam-dev openssh-client
- apk -U add openssh-client
- make clean
- make generate
- make vet
- make lint
- make test
@@ -22,41 +28,61 @@ pipeline:
test-mysql:
image: webhippie/golang:edge
pull: true
environment:
CGO_ENABLED: 1
TAGS: sqlite bindata
GOPATH: /srv/app
commands:
- make test-mysql
- make test-mysql
when:
event: [ push ]
test-pgsql:
image: webhippie/golang:edge
pull: true
environment:
CGO_ENABLED: 1
TAGS: sqlite bindata
GOPATH: /srv/app
commands:
- make test-pgsql
- make test-pgsql
when:
event: [ push ]
updater:
image: karalabe/xgo-latest:latest
pull: true
environment:
CGO_ENABLED: 1
TAGS: sqlite bindata
GOPATH: /srv/app
commands:
- make release
when:
event: [ push, tag ]
branch: [ master, release/*, refs/tags/* ]
coverage:
image: plugins/coverage
server: https://coverage.gitea.io
when:
event: [ push, tag, pull_request ]
updater:
image: karalabe/xgo-latest:latest
pull: true
commands:
- make publish
docker:
image: plugins/docker
repo: gitea/gitea
tags: [ '${DRONE_TAG##v}' ]
when:
event: [ push, tag ]
branch: [ master, refs/tags/* ]
event: [ tag ]
branch: [ refs/tags/* ]
docker:
image: plugins/docker
repo: gitea/gitea
tags: [ '${TAG}' ]
tags: [ '${DRONE_BRANCH##release/v}' ]
when:
event: [ tag ]
branch: [ refs/tags/* ]
event: [ push ]
branch: [ release/* ]
docker:
image: plugins/docker
@@ -71,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.d29ya3NwYWNlOgogIGJhc2U6IC9zcnYvYXBwCiAgcGF0aDogc3JjL2NvZGUuZ2l0ZWEuaW8vZ2l0ZWEKCnBpcGVsaW5lOgogIHRlc3Q6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgQ0dPX0VOQUJMRUQ6IDEKICAgICAgVEFHUzogY2VydCBzcWxpdGUgcGFtIG1pbml3aW5zdmMKICAgIGNvbW1hbmRzOgogICAgICAtIGFwayAtVSBhZGQgbGludXgtcGFtLWRldiBvcGVuc3NoLWNsaWVudAogICAgICAtIG1ha2UgY2xlYW4KICAgICAgLSBtYWtlIHZldAogICAgICAtIG1ha2UgbGludAogICAgICAtIG1ha2UgdGVzdAogICAgICAtIG1ha2UgYnVpbGQKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2gsIHRhZywgcHVsbF9yZXF1ZXN0IF0KCiAgdGVzdC1teXNxbDoKICAgIGltYWdlOiB3ZWJoaXBwaWUvZ29sYW5nOmVkZ2UKICAgIHB1bGw6IHRydWUKICAgIGNvbW1hbmRzOgogICAgIC0gbWFrZSB0ZXN0LW15c3FsCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KCiAgdGVzdC1wZ3NxbDoKICAgIGltYWdlOiB3ZWJoaXBwaWUvZ29sYW5nOmVkZ2UKICAgIHB1bGw6IHRydWUKICAgIGNvbW1hbmRzOgogICAgIC0gbWFrZSB0ZXN0LXBnc3FsCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KCiAgY292ZXJhZ2U6CiAgICBpbWFnZTogcGx1Z2lucy9jb3ZlcmFnZQogICAgc2VydmVyOiBodHRwczovL2NvdmVyYWdlLmdpdGVhLmlvCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIHVwZGF0ZXI6CiAgICBpbWFnZToga2FyYWxhYmUveGdvLWxhdGVzdDpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGNvbW1hbmRzOgogICAgICAtIG1ha2UgcHVibGlzaAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnIF0KICAgICAgYnJhbmNoOiBbIG1hc3RlciwgcmVmcy90YWdzLyogXQoKICBkb2NrZXI6CiAgICBpbWFnZTogcGx1Z2lucy9kb2NrZXIKICAgIHJlcG86IGdpdGVhL2dpdGVhCiAgICB0YWdzOiBbICcke1RBR30nIF0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHRhZyBdCiAgICAgIGJyYW5jaDogWyByZWZzL3RhZ3MvKiBdCgogIGRvY2tlcjoKICAgIGltYWdlOiBwbHVnaW5zL2RvY2tlcgogICAgcmVwbzogZ2l0ZWEvZ2l0ZWEKICAgIHRhZ3M6IFsgJ2xhdGVzdCcgXQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCiAgICAgIGJyYW5jaDogWyBtYXN0ZXIgXQoKICByZWxlYXNlOgogICAgaW1hZ2U6IHBsdWdpbnMvczMKICAgIHBhdGhfc3R5bGU6IHRydWUKICAgIHN0cmlwX3ByZWZpeDogZGlzdC9yZWxlYXNlLwogICAgc291cmNlOiBkaXN0L3JlbGVhc2UvKgogICAgdGFyZ2V0OiAvZ2l0ZWEvbWFzdGVyCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIG1hc3RlciBdCgogIHJlbGVhc2U6CiAgICBpbWFnZTogcGx1Z2lucy9zMwogICAgcGF0aF9zdHlsZTogdHJ1ZQogICAgc3RyaXBfcHJlZml4OiBkaXN0L3JlbGVhc2UvCiAgICBzb3VyY2U6IGRpc3QvcmVsZWFzZS8qCiAgICB0YXJnZXQ6IC9naXRlYS8kJFRBRwogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgdGFnIF0KICAgICAgYnJhbmNoOiBbIHJlZnMvdGFncy8qIF0KCiAgZ2l0aHViOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0aHViLXJlbGVhc2UKICAgIGZpbGVzOgogICAgICAtIGRpc3QvcmVsZWFzZS8qCiAgICB3aGVuOgogICAgICBldmVudDogWyB0YWcgXQogICAgICBicmFuY2g6IFsgcmVmcy90YWdzLyogXQoKICBnaXR0ZXI6CiAgICBpbWFnZTogcGx1Z2lucy9naXR0ZXIKCnNlcnZpY2VzOgogIG15c3FsOgogICAgaW1hZ2U6IG15c3FsOjUuNwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gTVlTUUxfREFUQUJBU0U9dGVzdAogICAgICAtIE1ZU1FMX0FMTE9XX0VNUFRZX1BBU1NXT1JEPXllcwogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCgogIHBnc3FsOgogICAgaW1hZ2U6IHBvc3RncmVzOjkuNQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfREI9dGVzdAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCg.fIX2wjyGG2j4vH7ZY2owmyND3XRjCTMgy3Vr3Q71eTE
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

@@ -24,17 +24,17 @@ This process gives everyone a chance to validate the design, helps prevent dupli
## Testing redux
Before sending code out for review, run all the tests for the whole tree to make sure the changes don't break other usage and keep the compatibility on upgrade. To make sure you are running the test suite exactly like we do you should install the CLI for [Drone CI](https://github.com/drone/drone) as we are using the server for continous testing, follow [these instructions](http://readme.drone.io/0.5/install/cli/). After that you can simply call `drone exec` within you working directory and it will try to run the test suite locally.
Before sending code out for review, run all the tests for the whole tree to make sure the changes don't break other usage and keep the compatibility on upgrade. To make sure you are running the test suite exactly like we do you should install the CLI for [Drone CI](https://github.com/drone/drone), as we are using the server for continous testing, following [these instructions](http://readme.drone.io/0.5/install/cli/). After that you can simply call `drone exec` within your working directory and it will try to run the test suite locally.
## Code review
Changes to Gitea must be reviewed before they are accepted, no matter who makes the change even if an owner or a maintainer. We use GitHub's pull request workflow to do that and we also use [LGTM](http://lgtm.co) to ensure every PR is reviewed by at least 2 maintainers.
Changes to Gitea must be reviewed before they are accepted, no matter who makes the change even if it is an owner or a maintainer. We use GitHub's pull request workflow to do that and we also use [LGTM](http://lgtm.co) to ensure every PR is reviewed by at least 2 maintainers.
Please try to make your pull request easy to review for us. Please read the "[How to get faster PR reviews](https://github.com/kubernetes/kubernetes/blob/master/docs/devel/faster_reviews.md)" guide, it got useful tips for any project you may want to contribute. See some of the points:
Please try to make your pull request easy to review for us. Please read the "[How to get faster PR reviews](https://github.com/kubernetes/kubernetes/blob/master/docs/devel/faster_reviews.md)" guide, it has lots of useful tips for any project you may want to contribute. Some of the key points:
* Make small pull requests. The smaller, the faster to review and the more likely it will be merged soon.
* Don't make changes unrelated to your PR. Maybe there are typos on some comments, maybe refactoring would welcome on a function... but if that is not related to you PR, please make *another* PR for that.
* Split big pull requests in multiple. An incremental change will be faster to review than a huge PR.
* Don't make changes unrelated to your PR. Maybe there are typos on some comments, maybe refactoring would be welcome on a function... but if that is not related to your PR, please make *another* PR for that.
* Split big pull requests in multiple small ones. An incremental change will be faster to review than a huge PR.
## Sign your work
@@ -48,19 +48,19 @@ Please use your real name, we really dislike pseudonyms or anonymous contributio
## Maintainers
To make sure every PR have been checked, we got team maintainers. Any PR MUST be reviewed and by at least two maintainers before it can get merged. Maintainers should be a contributor of Gitea (or Gogs) and contributed at least 4 accepted PRs. A contributor should apply as a maintainer in [Gitter development channel](https://gitter.im/go-gitea/develop). The owners or the team maintainers could invite the contributor. A maintainer should spend some time on code reviews. If some maintainer have no time to do that, he should apply to leave the maintainers team and we will give him an honor to be as a member of advisor team. Of course, if an advisor have time to code view, welcome it back to maintainers team. If someone have no time to code review and forget to leave the maintainers team, the owners have the power to move him from maintainers team to advisors team.
To make sure every PR is checked, we got team maintainers. Every PR **MUST** be reviewed by at least two maintainers (or owners) before it can get merged. A maintainer should be a contributor of Gitea (or Gogs) and contributed at least 4 accepted PRs. A contributor should apply as a maintainer in the [Gitter develop channel](https://gitter.im/go-gitea/develop). The owners or the team maintainers may invite the contributor. A maintainer should spend some time on code reviews. If a maintainer has no time to do that, they should apply to leave the maintainers team and we will give them the honor of being a member of the advisors team. Of course, if an advisor has time to code review, we will gladly welcome them back to maintainers team. If someone has no time to code review and forgets to leave the maintainers team, the owners have the power to move him from maintainers team to advisors team.
## Owners
Since Gitea is a pure community organization without any company support, to keep the development healthly we will elect the owners every year. Every time we will elect three owners. All the contributers could vote for three owners, one is the main owner, the other two are assistant owners. When the new owners have been elected, the old owners MUST move the power to the new owners. If some owner don't obey these rules, the other owners are allowed to revoke his owner status.
Since Gitea is a pure community organization without any company support, to keep the development healthy we will elect the owners every year. Every time we will elect three owners. All the contributors may vote up to three people, one of which is the main owner, and the others are assistant owners. When the new owners have been elected, the old owners MUST move the power to the new ones. If an owner don't obey these rules, the others are allowed to revoke his owner status.
After the election, the new owners should say he agrees with these rules on the [CONTRIBUTING](CONTRIBUTING.md) on the [Gitter main channel](https://gitter.im/go-gitea/gitea). Below are the words to speak:
After the election, the new owners should say they agree with these rules on the [CONTRIBUTING](CONTRIBUTING.md) on the [Gitter main channel](https://gitter.im/go-gitea/gitea). Below are the words to speak:
```
I'm glad to be an owner of Gitea, I agree with [CONTRIBUTING](CONTRIBUTING.md). I will spend part of my time on Gitea and lead the development of Gitea.
```
For a honor to the owners, this document will add the history owners below:
To honor the past owners, here's the history of the owners and the time they served:
* 2016-11-04 ~ 2017-12-31
* [Lunny Xiao](https://github.com/lunny) <xiaolunwen@gmail.com>
@@ -69,9 +69,9 @@ For a honor to the owners, this document will add the history owners below:
## Versions
Gitea has one master as a tip branch and have version branches such as `v0.9`. `v0.9` is a release branch and we will tag `v0.9.0` for binary download. If `v0.9.0` got some bug, we will accept pull requests on the `v0.9` branch and publish a `v0.9.1` tag, afterwards we will port the bug fix also to the master branch.
Gitea has the `master` branch as a tip branch and has version branches such as `v0.9`. `v0.9` is a release branch and we will tag `v0.9.0` for binary download. If `v0.9.0` has bugs, we will accept pull requests on the `v0.9` branch and publish a `v0.9.1` tag, after bringing the bug fix also to the master branch.
The `master` branch is a tip version, so if you wish a production usage, please download the latest release tag version. All the branches will be protected via github, all the PRs to all the branches should be review by two maintainers and pass the automatic tests.
Since the `master` branch is a tip version, if you wish to use Gitea in production, please download the latest release tag version. All the branches will be protected via GitHub, all the PRs to every branch must be reviewed by two maintainers and must pass the automatic tests.
## Copyright
@@ -83,4 +83,4 @@ Code that you contribute should use the standard copyright header:
// license that can be found in the LICENSE file.
```
Files in the repository are copyright the year they are added and the year they are last changed. If the copyright author is changed, just copy the head below the old one.
Files in the repository contain copyright from the year they are added to the year they are last changed. If the copyright author is changed, just paste the header below the old one.

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 bin/gitea /app/gitea/gitea
COPY gitea /app/gitea/gitea

View File

@@ -41,4 +41,4 @@ COPY docker /
COPY public /app/gitea/public
COPY templates /app/gitea/templates
COPY bin/gitea /app/gitea/gitea
COPY gitea /app/gitea/gitea

View File

@@ -1,6 +1,6 @@
Alexey Makhov <amakhov@avito.ru> (@makhov)
Andrey Nering <andrey.nering@gmail.com> (@andreynering)
Bwko <bouwko@gmail.com> (@Bwko)
Kees de Vries <bouwko@gmail.com> (@Bwko)
Kim Carlbäcker <kim.carlbacker@gmail.com> (@bkcsoft)
LefsFlare <nobody@nobody.tld> (@LefsFlarey)
Lunny Xiao <xiaolunwen@gmail.com> (@lunny)

View File

@@ -1,29 +1,24 @@
DIST := dist
BIN := bin
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
@@ -35,7 +30,7 @@ all: build
.PHONY: clean
clean:
go clean -i ./...
rm -rf $(BIN) $(DIST)
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA)
.PHONY: fmt
fmt:
@@ -86,58 +81,41 @@ install: $(wildcard *.go)
go install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)'
.PHONY: build
build: $(BIN)/$(EXECUTABLE)
build: $(EXECUTABLE)
$(BIN)/$(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-build release-copy release-check
release: release-dirs release-build release-copy release-check
.PHONY: release-dirs
release-dirs:
mkdir -p $(DIST)/binaries $(DIST)/release
.PHONY: release-build
release-build:
@which xgo > /dev/null; if [ $$? -ne 0 ]; then \
go get -u github.com/karalabe/xgo; \
fi
xgo -dest $(BIN) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -targets '$(TARGETS)' -out $(EXECUTABLE)-$(VERSION) $(IMPORT)
xgo -dest $(DIST)/binaries -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -targets '$(TARGETS)' -out $(EXECUTABLE)-$(VERSION) $(IMPORT)
ifeq ($(CI),drone)
mv /build/* $(DIST)/binaries
endif
.PHONY: release-copy
release-copy:
mkdir -p $(DIST)/release
$(foreach file,$(wildcard $(BIN)/$(EXECUTABLE)-*),cp $(file) $(DIST)/release/$(notdir $(file));)
$(foreach file,$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*),cp $(file) $(DIST)/release/$(notdir $(file));)
.PHONY: release-check
release-check:
cd $(DIST)/release; $(foreach file,$(wildcard $(DIST)/release/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
.PHONY: latest
latest: release-build latest-copy latest-check
.PHONY: latest-copy
latest-copy:
mkdir -p $(DIST)/latest
$(foreach file,$(wildcard $(BIN)/$(EXECUTABLE)-*),cp $(file) $(DIST)/latest/$(subst $(EXECUTABLE)-$(VERSION),$(EXECUTABLE)-latest,$(notdir $(file)));)
.PHONY: latest-check
latest-check:
cd $(DIST)/latest; $(foreach file,$(wildcard $(DIST)/latest/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
.PHONY: publish
publish: release latest
.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
@@ -153,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

@@ -1,7 +1,6 @@
// +build cert
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
@@ -138,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,30 +0,0 @@
// +build !cert
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"fmt"
"os"
"github.com/urfave/cli"
)
// CmdCert represents the available cert sub-command.
var CmdCert = cli.Command{
Name: "cert",
Usage: "Generate self-signed certificate",
Description: `Please use build tags "cert" to rebuild Gogs in order to have this ability`,
Action: runCert,
}
func runCert(*cli.Context) error {
fmt.Println("Command cert not available, please use build tags 'cert' to rebuild.")
os.Exit(1)
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.
@@ -10,20 +11,22 @@ import (
"log"
"os"
"path"
"path/filepath"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/cae/zip"
"github.com/Unknwon/com"
"github.com/urfave/cli"
)
// 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 +51,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 +59,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,19 +79,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 {
os.Remove(fileName)
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() {
@@ -97,12 +100,28 @@ func runDump(ctx *cli.Context) error {
} else {
log.Printf("Custom dir %s doesn't exist, skipped", setting.CustomPath)
}
if com.IsExist(setting.AppDataPath) {
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("Failed to include data directory: %v", err)
}
}
if err := z.AddDir("log", setting.LogRootPath); err != nil {
log.Fatalf("Fail to include log: %v", err)
}
// FIXME: SSH key file.
if err = z.Close(); err != nil {
os.Remove(fileName)
_ = os.Remove(fileName)
log.Fatalf("Fail to save %s: %v", fileName, err)
}
@@ -111,8 +130,48 @@ func runDump(ctx *cli.Context) error {
}
log.Printf("Removing tmp work dir: %s", TmpWorkDir)
os.RemoveAll(TmpWorkDir)
if err := os.RemoveAll(TmpWorkDir); err != nil {
log.Fatalf("Fail to remove %s: %v", TmpWorkDir, err)
}
log.Printf("Finish dumping in file %s", fileName)
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.
@@ -51,7 +52,9 @@ func setup(logPath string) {
if setting.UseSQLite3 || setting.UseTiDB {
workDir, _ := setting.WorkDir()
os.Chdir(workDir)
if err := os.Chdir(workDir); err != nil {
log.GitLogger.Fatal(4, "Fail to change directory %s: %v", workDir, err)
}
}
models.SetEngine()
@@ -74,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 {
@@ -118,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{
@@ -142,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
}
@@ -152,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
}
@@ -253,10 +256,14 @@ 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)
}
}
uuid := gouuid.NewV4().String()
os.Setenv("GITEA_UUID", uuid)
// Keep the old env variable name for backward compability
os.Setenv("uuid", uuid)
// Special handle for Windows.

View File

@@ -49,7 +49,7 @@ func runUpdate(c *cli.Context) error {
}
task := models.UpdateTask{
UUID: os.Getenv("uuid"),
UUID: os.Getenv("GITEA_UUID"),
RefName: args[0],
OldCommitID: args[1],
NewCommitID: args[2],

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()
@@ -654,8 +609,9 @@ func runWeb(ctx *cli.Context) error {
case setting.FCGI:
err = fcgi.Serve(nil, m)
case setting.UnixSocket:
os.Remove(listenAddr)
if err := os.Remove(listenAddr); err != nil {
log.Fatal(4, "Fail to remove unix socket directory %s: %v", listenAddr, err)
}
var listener *net.UnixListener
listener, err = net.ListenUnix("unix", &net.UnixAddr{Name: listenAddr, Net: "unix"})
if err != nil {

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

12
main.go
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.
@@ -10,13 +10,15 @@ import (
"os"
"runtime"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/cmd"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli"
)
// Version holds the current Gitea version
const Version = "0.9.99.0915"
var Version = "1.0.2+dev"
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
@@ -37,5 +39,9 @@ func main() {
cmd.CmdAdmin,
}
app.Flags = append(app.Flags, []cli.Flag{}...)
app.Run(os.Args)
err := app.Run(os.Args)
if err != nil {
log.Fatal(4, "Fail to run app with %s: %v", os.Args, err)
}
}

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

@@ -584,6 +584,28 @@ func (err ErrPullRequestNotExist) Error() string {
err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBarcnh, err.BaseBranch)
}
// ErrPullRequestAlreadyExists represents a "PullRequestAlreadyExists"-error
type ErrPullRequestAlreadyExists struct {
ID int64
IssueID int64
HeadRepoID int64
BaseRepoID int64
HeadBranch string
BaseBranch string
}
// IsErrPullRequestAlreadyExists checks if an error is a ErrPullRequestAlreadyExists.
func IsErrPullRequestAlreadyExists(err error) bool {
_, ok := err.(ErrPullRequestAlreadyExists)
return ok
}
// Error does pretty-printing :D
func (err ErrPullRequestAlreadyExists) Error() string {
return fmt.Sprintf("pull request already exists for these targets [id: %d, issue_id: %d, head_repo_id: %d, base_repo_id: %d, head_branch: %s, base_branch: %s]",
err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch)
}
// _________ __
// \_ ___ \ ____ _____ _____ ____ _____/ |_
// / \ \/ / _ \ / \ / \_/ __ \ / \ __\

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)
@@ -170,6 +177,22 @@ func (issue *Issue) HTMLURL() string {
return fmt.Sprintf("%s/%s/%d", issue.Repo.HTMLURL(), path, issue.Index)
}
// DiffURL returns the absolute URL to this diff
func (issue *Issue) DiffURL() string {
if issue.IsPull {
return fmt.Sprintf("%s/pulls/%d.diff", issue.Repo.HTMLURL(), issue.Index)
}
return ""
}
// PatchURL returns the absolute URL to this patch
func (issue *Issue) PatchURL() string {
if issue.IsPull {
return fmt.Sprintf("%s/pulls/%d.patch", issue.Repo.HTMLURL(), issue.Index)
}
return ""
}
// State returns string representation of issue status.
func (issue *Issue) State() api.StateType {
if issue.IsClosed {
@@ -249,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(),
})
}
@@ -306,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
}
@@ -337,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
}
@@ -355,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(),
})
}
@@ -477,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 {
@@ -515,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(),
})
}
@@ -547,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(),
})
}
@@ -580,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 {
@@ -872,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").
@@ -1039,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
}
@@ -1049,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)
}
@@ -1073,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)
}
@@ -1128,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)
}
}
@@ -1232,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)
@@ -1314,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

@@ -67,7 +67,7 @@ func (label *Label) APIFormat() *api.Label {
return &api.Label{
ID: label.ID,
Name: label.Name,
Color: label.Color,
Color: strings.TrimLeft(label.Color, "#"),
}
}
@@ -102,6 +102,27 @@ func NewLabels(labels ...*Label) error {
return err
}
// getLabelInRepoByName returns a label by Name in given repository.
// If pass repoID as 0, then ORM will ignore limitation of repository
// and can return arbitrary label with any valid ID.
func getLabelInRepoByName(e Engine, repoID int64, labelName string) (*Label, error) {
if len(labelName) <= 0 {
return nil, ErrLabelNotExist{0, repoID}
}
l := &Label{
Name: labelName,
RepoID: repoID,
}
has, err := x.Get(l)
if err != nil {
return nil, err
} else if !has {
return nil, ErrLabelNotExist{0, l.RepoID}
}
return l, nil
}
// getLabelInRepoByID returns a label by ID in given repository.
// If pass repoID as 0, then ORM will ignore limitation of repository
// and can return arbitrary label with any valid ID.
@@ -128,6 +149,11 @@ func GetLabelByID(id int64) (*Label, error) {
return getLabelInRepoByID(x, 0, id)
}
// GetLabelInRepoByName returns a label by name in given repository.
func GetLabelInRepoByName(repoID int64, labelName string) (*Label, error) {
return getLabelInRepoByName(x, repoID, labelName)
}
// GetLabelInRepoByID returns a label by ID in given repository.
func GetLabelInRepoByID(repoID, labelID int64) (*Label, error) {
return getLabelInRepoByID(x, repoID, labelID)

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

@@ -192,7 +192,10 @@ func SetEngine() (err error) {
// WARNING: for serv command, MUST remove the output to os.stdout,
// so use log file to instead print to stdout.
logPath := path.Join(setting.LogRootPath, "xorm.log")
os.MkdirAll(path.Dir(logPath), os.ModePerm)
if err := os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil {
return fmt.Errorf("Fail to create dir %s: %v", logPath, err)
}
f, err := os.Create(logPath)
if err != nil {

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

@@ -121,7 +121,54 @@ func (pr *PullRequest) LoadIssue() (err error) {
// Required - Issue
// Optional - Merger
func (pr *PullRequest) APIFormat() *api.PullRequest {
var (
baseBranch *Branch
headBranch *Branch
baseCommit *git.Commit
headCommit *git.Commit
err error
)
apiIssue := pr.Issue.APIFormat()
if pr.BaseRepo == nil {
pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID)
if err != nil {
log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err)
return nil
}
}
if pr.HeadRepo == nil {
pr.HeadRepo, err = GetRepositoryByID(pr.HeadRepoID)
if err != nil {
log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err)
return nil
}
}
if baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch); err != nil {
return nil
}
if baseCommit, err = baseBranch.GetCommit(); err != nil {
return nil
}
if headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch); err != nil {
return nil
}
if headCommit, err = headBranch.GetCommit(); err != nil {
return nil
}
apiBaseBranchInfo := &api.PRBranchInfo{
Name: pr.BaseBranch,
Ref: pr.BaseBranch,
Sha: baseCommit.ID.String(),
RepoID: pr.BaseRepoID,
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(AccessModeNone),
}
apiPullRequest := &api.PullRequest{
ID: pr.ID,
Index: pr.Index,
@@ -134,7 +181,12 @@ func (pr *PullRequest) APIFormat() *api.PullRequest {
State: apiIssue.State,
Comments: apiIssue.Comments,
HTMLURL: pr.Issue.HTMLURL(),
DiffURL: pr.Issue.DiffURL(),
PatchURL: pr.Issue.PatchURL(),
HasMerged: pr.HasMerged,
Base: apiBaseBranchInfo,
Head: apiHeadBranchInfo,
MergeBase: pr.MergeBase,
}
if pr.Status != PullRequestStatusChecking {
@@ -218,7 +270,11 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
// Clone base repo.
tmpBasePath := path.Join(setting.AppDataPath, "tmp/repos", com.ToStr(time.Now().Nanosecond())+".git")
os.MkdirAll(path.Dir(tmpBasePath), os.ModePerm)
if err := os.MkdirAll(path.Dir(tmpBasePath), os.ModePerm); err != nil {
return fmt.Errorf("Fail to create dir %s: %v", tmpBasePath, err)
}
defer os.RemoveAll(path.Dir(tmpBasePath))
var stderr string
@@ -299,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)
@@ -324,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(),
}
@@ -339,7 +395,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
return nil
}
// patchConflicts is a list of conflit description from Git.
// patchConflicts is a list of conflict description from Git.
var patchConflicts = []string{
"patch does not apply",
"already exists in working directory",
@@ -347,8 +403,7 @@ var patchConflicts = []string{
"error:",
}
// testPatch checks if patch can be merged to base repository without conflit.
// FIXME: make a mechanism to clean up stable local copies.
// testPatch checks if patch can be merged to base repository without conflict.
func (pr *PullRequest) testPatch() (err error) {
if pr.BaseRepo == nil {
pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID)
@@ -373,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)
}
@@ -384,7 +442,7 @@ func (pr *PullRequest) testPatch() (err error) {
if err != nil {
for i := range patchConflicts {
if strings.Contains(stderr, patchConflicts[i]) {
log.Trace("PullRequest[%d].testPatch (apply): has conflit", pr.ID)
log.Trace("PullRequest[%d].testPatch (apply): has conflict", pr.ID)
fmt.Println(stderr)
pr.Status = PullRequestStatusConflict
return nil
@@ -458,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)
@@ -468,6 +526,46 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
return nil
}
// PullRequestsOptions holds the options for PRs
type PullRequestsOptions struct {
Page int
State string
SortType string
Labels []string
MilestoneID int64
}
func listPullRequestStatement(baseRepoID int64, opts *PullRequestsOptions) *xorm.Session {
sess := x.Where("pull_request.base_repo_id=?", baseRepoID)
sess.Join("INNER", "issue", "pull_request.issue_id = issue.id")
switch opts.State {
case "closed", "open":
sess.And("issue.is_closed=?", opts.State == "closed")
}
return sess
}
// PullRequests returns all pull requests for a base Repo by the given conditions
func PullRequests(baseRepoID int64, opts *PullRequestsOptions) ([]*PullRequest, int64, error) {
if opts.Page <= 0 {
opts.Page = 1
}
countSession := listPullRequestStatement(baseRepoID, opts)
maxResults, err := countSession.Count(new(PullRequest))
if err != nil {
log.Error(4, "Count PRs", err)
return nil, maxResults, err
}
prs := make([]*PullRequest, 0, ItemsPerPage)
findSession := listPullRequestStatement(baseRepoID, opts)
findSession.Limit(ItemsPerPage, (opts.Page-1)*ItemsPerPage)
return prs, maxResults, findSession.Find(&prs)
}
// GetUnmergedPullRequest returnss a pull request that is open and has not been merged
// by given head/base and repo/branch.
func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch string) (*PullRequest, error) {
@@ -508,6 +606,30 @@ func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequ
Find(&prs)
}
// GetPullRequestByIndex returns a pull request by the given index
func GetPullRequestByIndex(repoID int64, index int64) (*PullRequest, error) {
pr := &PullRequest{
BaseRepoID: repoID,
Index: index,
}
has, err := x.Get(pr)
if err != nil {
return nil, err
} else if !has {
return nil, ErrPullRequestNotExist{0, repoID, index, 0, "", ""}
}
if err = pr.LoadAttributes(); err != nil {
return nil, err
}
if err = pr.LoadIssue(); err != nil {
return nil, err
}
return pr, nil
}
func getPullRequestByID(e Engine, id int64) (*PullRequest, error) {
pr := new(PullRequest)
has, err := e.Id(id).Get(pr)
@@ -622,7 +744,9 @@ func (pr *PullRequest) PushToBaseRepo() (err error) {
headFile := fmt.Sprintf("refs/pull/%d/head", pr.Index)
// Remove head in case there is a conflict.
os.Remove(path.Join(pr.BaseRepo.RepoPath(), headFile))
file := path.Join(pr.BaseRepo.RepoPath(), headFile)
_ = os.Remove(file)
if err = git.Push(headRepoPath, tmpRemoteName, fmt.Sprintf("%s:%s", pr.HeadBranch, headFile)); err != nil {
return fmt.Errorf("Push: %v", err)
@@ -718,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)
@@ -805,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(),
@@ -499,14 +503,14 @@ var (
// DescriptionHTML does special handles to description and return HTML string.
func (repo *Repository) DescriptionHTML() template.HTML {
sanitize := func(s string) string {
return fmt.Sprintf(`<a href="%[1]s" target="_blank">%[1]s</a>`, s)
return fmt.Sprintf(`<a href="%[1]s" target="_blank" rel="noopener">%[1]s</a>`, s)
}
return template.HTML(descPattern.ReplaceAllStringFunc(markdown.Sanitizer.Sanitize(repo.Description), sanitize))
}
// 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.
@@ -558,8 +562,12 @@ func (repo *Repository) SavePatch(index int64, patch []byte) error {
if err != nil {
return fmt.Errorf("PatchPath: %v", err)
}
dir := filepath.Dir(patchPath)
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return fmt.Errorf("Fail to create dir %s: %v", dir, err)
}
os.MkdirAll(filepath.Dir(patchPath), os.ModePerm)
if err = ioutil.WriteFile(patchPath, patch, 0644); err != nil {
return fmt.Errorf("WriteFile: %v", err)
}
@@ -669,7 +677,10 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
migrateTimeout := time.Duration(setting.Git.Timeout.Migrate) * time.Second
os.RemoveAll(repoPath)
if err := os.RemoveAll(repoPath); err != nil {
return repo, fmt.Errorf("Fail to remove %s: %v", repoPath, err)
}
if err = git.Clone(opts.RemoteAddr, repoPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
@@ -680,13 +691,20 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
wikiRemotePath := wikiRemoteURL(opts.RemoteAddr)
if len(wikiRemotePath) > 0 {
os.RemoveAll(wikiPath)
if err := os.RemoveAll(wikiPath); err != nil {
return repo, fmt.Errorf("Fail to remove %s: %v", wikiPath, err)
}
if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{
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)
}
}
}
@@ -812,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 {
@@ -902,7 +933,11 @@ func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts C
// Initialize repository according to user's choice.
if opts.AutoInit {
os.MkdirAll(tmpDir, os.ModePerm)
if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil {
return fmt.Errorf("Fail to create dir %s: %v", tmpDir, err)
}
defer os.RemoveAll(tmpDir)
if err = prepareRepoCommit(repo, tmpDir, repoPath, opts); err != nil {
@@ -1198,7 +1233,12 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
}
// Rename remote repository to new path and delete local copy.
os.MkdirAll(UserPath(newOwner.Name), os.ModePerm)
dir := UserPath(newOwner.Name)
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return fmt.Errorf("Fail to create dir %s: %v", dir, err)
}
if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil {
return fmt.Errorf("rename repository directory: %v", err)
}

View File

@@ -104,7 +104,11 @@ func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (
localPath := repo.LocalCopyPath()
oldFilePath := path.Join(localPath, opts.OldTreeName)
filePath := path.Join(localPath, opts.NewTreeName)
os.MkdirAll(path.Dir(filePath), os.ModePerm)
dir := path.Dir(filePath)
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return fmt.Errorf("Fail to create dir %s: %v", dir, err)
}
// If it's meant to be a new file, make sure it doesn't exist.
if opts.IsNewFile {
@@ -154,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,
@@ -185,7 +189,12 @@ func (repo *Repository) GetDiffPreview(branch, treePath, content string) (diff *
localPath := repo.LocalCopyPath()
filePath := path.Join(localPath, treePath)
os.MkdirAll(filepath.Dir(filePath), os.ModePerm)
dir := filepath.Dir(filePath)
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return nil, fmt.Errorf("Fail to create dir %s: %v", dir, err)
}
if err = ioutil.WriteFile(filePath, []byte(content), 0666); err != nil {
return nil, fmt.Errorf("WriteFile: %v", err)
}
@@ -288,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,
@@ -475,7 +484,10 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
localPath := repo.LocalCopyPath()
dirPath := path.Join(localPath, opts.TreePath)
os.MkdirAll(dirPath, os.ModePerm)
if err := os.MkdirAll(dirPath, os.ModePerm); err != nil {
return fmt.Errorf("Fail to create dir %s: %v", dirPath, err)
}
// Copy uploaded files into repository.
for _, upload := range uploads {
@@ -521,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

@@ -373,7 +373,12 @@ func addKey(e Engine, key *PublicKey) (err error) {
// Calculate fingerprint.
tmpPath := strings.Replace(path.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()),
"id_rsa.pub"), "\\", "/", -1)
os.MkdirAll(path.Dir(tmpPath), os.ModePerm)
dir := path.Dir(tmpPath)
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return fmt.Errorf("Fail to create dir %s: %v", dir, err)
}
if err = ioutil.WriteFile(tmpPath, []byte(key.Content), 0644); err != nil {
return err
}

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

@@ -8,6 +8,7 @@ import (
"bytes"
"container/list"
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
"errors"
"fmt"
@@ -24,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"
@@ -360,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)
}
@@ -368,7 +370,7 @@ func (u *User) EncodePasswd() {
func (u *User) ValidatePassword(passwd string) bool {
newUser := &User{Passwd: passwd, Salt: u.Salt}
newUser.EncodePasswd()
return u.Passwd == newUser.Passwd
return subtle.ConstantTimeCompare([]byte(u.Passwd), []byte(newUser.Passwd)) == 1
}
// UploadAvatar saves custom avatar for user.
@@ -392,7 +394,10 @@ func (u *User) UploadAvatar(data []byte) error {
return fmt.Errorf("updateUser: %v", err)
}
os.MkdirAll(setting.AvatarUploadPath, os.ModePerm)
if err := os.MkdirAll(setting.AvatarUploadPath, os.ModePerm); err != nil {
return fmt.Errorf("Fail to create dir %s: %v", setting.AvatarUploadPath, err)
}
fw, err := os.Create(u.CustomAvatarPath())
if err != nil {
return fmt.Errorf("Create: %v", err)
@@ -409,7 +414,10 @@ func (u *User) UploadAvatar(data []byte) error {
// DeleteAvatar deletes the user's custom avatar.
func (u *User) DeleteAvatar() error {
log.Trace("DeleteAvatar[%d]: %s", u.ID, u.CustomAvatarPath())
os.Remove(u.CustomAvatarPath())
if err := os.Remove(u.CustomAvatarPath()); err != nil {
return fmt.Errorf("Fail to remove %s: %v", u.CustomAvatarPath(), err)
}
u.UseCustomAvatar = false
if err := UpdateUser(u); err != nil {
@@ -524,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)
}
@@ -596,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
@@ -866,9 +878,18 @@ func deleteUser(e *xorm.Session, u *User) error {
// FIXME: system notice
// Note: There are something just cannot be roll back,
// so just keep error logs of those operations.
path := UserPath(u.Name)
os.RemoveAll(UserPath(u.Name))
os.Remove(u.CustomAvatarPath())
if err := os.RemoveAll(path); err != nil {
return fmt.Errorf("Fail to RemoveAll %s: %v", path, err)
}
avatarPath := u.CustomAvatarPath()
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,11 @@ func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, mes
return ErrWikiAlreadyExist{filename}
}
} else {
os.Remove(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)
}
}
// SECURITY: if new file is a symlink to non-exist critical file,
@@ -120,7 +125,8 @@ func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, mes
// as a new page operation.
// So we want to make sure the symlink is removed before write anything.
// The new file we created will be in normal text format.
os.Remove(filename)
_ = os.Remove(filename)
if err = ioutil.WriteFile(filename, []byte(content), 0666); err != nil {
return fmt.Errorf("WriteFile: %v", err)
@@ -143,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))
@@ -166,10 +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")
os.Remove(filename)
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

@@ -35,6 +35,9 @@ func SignedInID(ctx *macaron.Context, sess session.Store) int64 {
// Check access token.
if IsAPIPath(ctx.Req.URL.Path) {
tokenSHA := ctx.Query("token")
if len(tokenSHA) <= 0 {
tokenSHA = ctx.Query("access_token")
}
if len(tokenSHA) == 0 {
// Well, check with header again.
auHead := ctx.Req.Header.Get("Authorization")

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

@@ -8,6 +8,7 @@ import (
"fmt"
"strings"
"code.gitea.io/git"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
@@ -103,3 +104,24 @@ func ExtractOwnerAndRepo() macaron.Handler {
ctx.Data["Repository"] = repo
}
}
// ReferencesGitRepo injects the GitRepo into the Context
func ReferencesGitRepo() macaron.Handler {
return func(ctx *APIContext) {
// Empty repository does not have reference information.
if ctx.Repo.Repository.IsBare {
return
}
// For API calls.
if ctx.Repo.GitRepo == nil {
repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
ctx.Error(500, "RepoRef Invalid repo "+repoPath, err)
return
}
ctx.Repo.GitRepo = gitRepo
}
}
}

View File

@@ -6,6 +6,7 @@ package context
import (
"fmt"
"html"
"html/template"
"io"
"net/http"
@@ -186,8 +187,10 @@ func Contexter() macaron.Handler {
}
}
ctx.Data["CsrfToken"] = x.GetToken()
ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + x.GetToken() + `">`)
ctx.Resp.Header().Set(`X-Frame-Options`, `SAMEORIGIN`)
ctx.Data["CsrfToken"] = html.EscapeString(x.GetToken())
ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + ctx.Data["CsrfToken"].(string) + `">`)
log.Debug("Session ID: %s", sess.ID())
log.Debug("CSRF Token: %v", ctx.Data["CsrfToken"])

View File

@@ -219,7 +219,10 @@ func (w *FileLogWriter) deleteOldLog() {
if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.Maxdays) {
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.Filename)) {
os.Remove(path)
if err := os.Remove(path); err != nil {
returnErr = fmt.Errorf("Fail to remove %s: %v", path, err)
}
}
}
return returnErr

View File

@@ -39,10 +39,26 @@ 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) {
os.MkdirAll(path.Dir(logPath), os.ModePerm)
path := path.Dir(logPath)
if err := os.MkdirAll(path, os.ModePerm); err != nil {
Fatal(4, "Fail to create dir %s: %v", path, err)
}
GitLogger = newLogger(0)
GitLogger.SetLogger("file", fmt.Sprintf(`{"level":0,"filename":"%s","rotate":false}`, logPath))
}

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

@@ -1,15 +0,0 @@
// +build miniwinsvc
// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package setting
import (
_ "github.com/kardianos/minwinsvc"
)
func init() {
SupportMiniWinService = true
}

View File

@@ -17,17 +17,16 @@ 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"
"github.com/go-macaron/session"
_ "github.com/go-macaron/session/redis" // redis plugin for store session
_ "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
@@ -52,10 +51,6 @@ const (
// settings
var (
// BuildTime information should only be set by -ldflags.
BuildTime string
BuildGitHash string
// AppVer settings
AppVer string
AppName string
@@ -85,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"`
@@ -108,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
@@ -140,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
@@ -161,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
@@ -202,7 +260,7 @@ var (
CSRFCookieName = "_csrf"
// Cron tasks
Cron struct {
Cron = struct {
UpdateMirror struct {
Enabled bool
RunAtStart bool
@@ -220,10 +278,42 @@ var (
RunAtStart bool
Schedule string
} `ini:"cron.check_repo_stats"`
}{
UpdateMirror: struct {
Enabled bool
RunAtStart bool
Schedule string
}{
Enabled: true,
RunAtStart: false,
Schedule: "@every 10m",
},
RepoHealthCheck: struct {
Enabled bool
RunAtStart bool
Schedule string
Timeout time.Duration
Args []string `delim:" "`
}{
Enabled: true,
RunAtStart: false,
Schedule: "@every 24h",
Timeout: 60 * time.Second,
Args: []string{},
},
CheckRepoStats: struct {
Enabled bool
RunAtStart bool
Schedule string
}{
Enabled: true,
RunAtStart: true,
Schedule: "@every 24h",
},
}
// Git settings
Git struct {
Git = struct {
DisableDiffHighlight bool
MaxGitDiffLines int
MaxGitDiffLineCharacters int
@@ -236,16 +326,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
@@ -259,7 +372,6 @@ var (
ShowFooterBranding bool
ShowFooterVersion bool
ShowFooterTemplateLoadTime bool
SupportMiniWinService bool
// Global setting objects
Cfg *ini.File
@@ -352,9 +464,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")
@@ -393,7 +506,7 @@ please consider changing to GITEA_CUSTOM`)
forcePathSeparator(LogRootPath)
sec := Cfg.Section("server")
AppName = Cfg.Section("").Key("APP_NAME").MustString("Gogs: Go Git Service")
AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea")
AppURL = sec.Key("ROOT_URL").MustString("http://localhost:3000/")
if AppURL[len(AppURL)-1] != '/' {
AppURL += "/"
@@ -447,6 +560,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 +587,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 +622,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 +665,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 +713,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 +765,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 +824,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 +861,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))))
@@ -162,7 +162,12 @@ func Listen(port int) {
keyPath := filepath.Join(setting.AppDataPath, "ssh/gogs.rsa")
if !com.IsExist(keyPath) {
os.MkdirAll(filepath.Dir(keyPath), os.ModePerm)
filePath := filepath.Dir(keyPath)
if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
log.Error(4, "Fail to create dir %s: %v", filePath, err)
}
_, stderr, err := com.ExecCmd("ssh-keygen", "-f", keyPath, "-t", "rsa", "-N", "")
if err != nil {
panic(fmt.Sprintf("Fail to generate private key: %v - %s", err, stderr))
@@ -180,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