Compare commits

..

489 Commits

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

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

* Added comment to new function (lint failure)

* update based on PR comments (code style)

* code style fix (thanks bkcsoft)

* check if logger exists based on the l.outputs (like in l.DelLogger) instead of adapter, otherwise panic when reinstalling gitea (since the output adapter still exist, without outputs)
2017-02-18 22:25:28 +08:00
Lunny Xiao
61cdc32496 fixed bugs on Wiki and resolved #667 (#674) (#958) 2017-02-16 19:32:39 +08:00
Lunny Xiao
5fcf218ed9 Add data directory excluding sessions to dump (#587) (#959) 2017-02-16 17:30:28 +08:00
Lunny Xiao
91836614cd Security: prevent XSS attach on wiki page (#955)
Reported by Miguel Ángel Jimeno.
2017-02-16 17:02:15 +08:00
Lunny Xiao
ab4eb0daf9 bug fixed for issue count (#882) 2017-02-09 18:36:01 +08:00
Thomas Boerger
155fb93b9b Added 1.0.1 to changelog (#595)
(cherry picked from commit 0ac40cc694)
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
Thomas Boerger
6519718706 Merge pull request #298 from stroucki/20161128locale
suggested locale fixes
2016-11-29 22:49:10 +01:00
Bwko
1e9730a779 Fixes xss, clickjacking & password autocompletion 2016-11-29 22:49:06 +01:00
Michael Stroucken
e929ca2c41 Time values displayed are apparently single values, so use singular. 2016-11-29 14:54:10 -05:00
Thomas Boerger
ccad2cce32 Merge pull request #275 from strk/readmelink
Turn banner into a link to the github page
2016-11-29 20:38:23 +01:00
Sandro Santilli
349ecc6919 Turn banner into a link to the github gitea repository
Also use relative link to banner
2016-11-29 18:45:02 +01:00
Thomas Boerger
b6a95a8cb3 Integrate public as bindata optionally (#293)
* Dropped unused codekit config

* Integrated dynamic and static bindata for public

* Ignore public bindata

* Add a general generate make task

* Integrated flexible public assets into web command

* Updated vendoring, added all missiong govendor deps

* Made the linter happy with the bindata and dynamic code

* Moved public bindata definition to modules directory

* Ignoring the new bindata path now

* Updated to the new public modules import path

* Updated public bindata command and drop the new prefix
2016-11-30 00:26:36 +08:00
Thomas Boerger
4680c349dd Merge pull request #303 from tboerger/linting
Fixed remaining linting errors
2016-11-29 15:18:27 +01:00
Thomas Boerger
684d55e130 Reenabled lint check within drone 2016-11-29 14:15:36 +01:00
Thomas Boerger
60e3e5b4e1 Updated bindata to latest version 2016-11-29 14:14:40 +01:00
Thomas Boerger
e93d394620 Replace invaliud bindata variable names within make task 2016-11-29 14:14:22 +01:00
Thomas Boerger
6dd2c3b2db Fixed linting errors for variable definitions 2016-11-29 14:05:26 +01:00
Kim "BKC" Carlbäcker
42ec5ce740 Fix breakage from vendor-update 2016-11-29 11:50:22 +01:00
Kim "BKC" Carlbäcker
dad806d3ea CreateBranch-hook has shasum. Use the full ref for fetching shasum 2016-11-29 11:50:22 +01:00
Kim "BKC" Carlbäcker
57dc9efaae Update gitea/sdk vendor 2016-11-29 11:50:22 +01:00
Kim "BKC" Carlbäcker
f364522468 Tag-webhooks are useless without shasums 2016-11-29 11:50:22 +01:00
Lunny Xiao
abf6c3a8e3 bug fixed caused by #295 (#299) 2016-11-29 14:57:36 +08:00
Thomas Boerger
16cdbe1956 Merge pull request #288 from tboerger/docker
Docker integration
2016-11-29 07:21:47 +01:00
Michael Stroucken
36a4663393 Rebase branch onto go-gitea/gitea 2016-11-28 20:03:45 -05:00
Andrey Nering
fd53028139 Merge pull request #294 from Bwko/Lint/user.go
Lint models/user.go
2016-11-28 20:30:02 -02:00
Andrey Nering
b9b22b4a0b Merge pull request #295 from Bwko/Lint/repo_
Lint models/repo
2016-11-28 20:29:15 -02:00
Matthias Loibl
8704f48e66 Merge pull request #290 from tboerger/maintain-contribute
Project unification, updates for contributors guide and github files
2016-11-28 20:49:39 +01:00
Bwko
bad1bc6518 Lint models/repo.go 2016-11-28 18:27:55 +01:00
Bwko
a5aae1c145 Lint models/repo_* 2016-11-28 17:58:59 +01:00
Bwko
9963d61233 Lint models/user.go 2016-11-28 17:47:46 +01:00
Thomas Boerger
d7dea676fd Added -S flag to addgroup command within Dockerfiles 2016-11-28 17:37:31 +01:00
Thomas Boerger
4b0abdae9e Replaced edge with 3.4 for the alpine base image 2016-11-28 17:23:22 +01:00
Thomas Boerger
972ce6b791 Replaced shadow with addgroup and adduser 2016-11-28 17:22:22 +01:00
Thomas Boerger
65d0426b91 Use su-exec instead of gosu, much smaller 2016-11-28 17:16:13 +01:00
Thomas Boerger
8def53ffcc Add a pragraph to the k8s PR guide to contributors guide 2016-11-28 16:57:42 +01:00
Lunny Xiao
27d66855eb golint fixed for models/migrations (#291) 2016-11-28 23:44:17 +08:00
Lunny Xiao
1d0f811399 golint fixed for models/pull.go (#292) 2016-11-28 23:31:06 +08:00
Thomas Boerger
fd3f16695e Merge pull request #289 from lunny/lunny/golint_models_issue_comment
Golint fixed for models/issue_comment.go
2016-11-28 14:46:00 +01:00
Thomas Boerger
b3abc2775f Dropped more or less useless files 2016-11-28 14:36:35 +01:00
Thomas Boerger
91d6c715ea Dropped new lines from contributing, some rewording and reformatting 2016-11-28 14:35:55 +01:00
Thomas Boerger
caac5fb99d Updated maintainers file to latest status 2016-11-28 14:35:04 +01:00
Thomas Boerger
c2044e5b39 Dropped always outdated contributors file, link to it the graph on readme 2016-11-28 14:34:06 +01:00
Lunny Xiao
9fc609ce17 golint fixed for models/issue_comment.go 2016-11-28 21:33:09 +08:00
Matthias Loibl
7b6cc9244d Update link on user’s profile avatar to avatar settings (#287) 2016-11-28 21:29:39 +08:00
Thomas Boerger
9628d4fb44 Unified GitHub templates accross all projects 2016-11-28 14:28:40 +01:00
Thomas Boerger
3d2138812c Unified editorconfig accross all projects 2016-11-28 14:27:59 +01:00
Thomas Boerger
575dc69e3b Updated drone docker definitions
In order to automatically build docker images I have re-enabled the
docker building parts within our drone runs on every push to master and
on every tag.

Signed-off-by: Thomas Boerger <tboerger@suse.de>
2016-11-28 14:15:14 +01:00
Thomas Boerger
86aa8e413a Restructured docker building
I have restructured the docker build process entirely, the binary gets
built outside of the docker build command, now we are managing all
dependencies with real Alpine packages and I have dropped features like
socat or the cron daemon.

Signed-off-by: Thomas Boerger <tboerger@suse.de>
2016-11-28 14:13:18 +01:00
Thomas Boerger
9948f0daaa Merge pull request #285 from lunny/lunny/golint_models_org_team
Golint for models/org_team.go
2016-11-28 09:42:53 +01:00
Lunny Xiao
f215d78157 rename all uID -> userID on models/org_team.go 2016-11-28 16:33:08 +08:00
Lunny Xiao
bf8d90c5cc golint fixed for models/models.go (#284) 2016-11-28 15:25:16 +08:00
Lunny Xiao
21846d16e5 golint for models/org_team.go 2016-11-28 09:30:08 +08:00
Thomas Boerger
25b5722155 Merge pull request #274 from lunny/lunny/golint_modules_auth
Golint fixed for modules/auth
2016-11-27 16:21:49 +01:00
Lunny Xiao
d0bef011ad Merge branch 'lunny/golint_modules_auth' of github.com:lunny/gitea into lunny/golint_modules_auth 2016-11-27 21:41:56 +08:00
Lunny Xiao
ec87a75c00 golint fixed for modules/auth 2016-11-27 21:39:06 +08:00
Thomas Boerger
e6da2cf2cb Merge pull request #281 from Bwko/Lint/typos
Fixes typos
2016-11-27 14:01:50 +01:00
Bwko
a4ece1f223 Fixes typos 2016-11-27 12:59:12 +01:00
Thomas Boerger
5efdccd1d8 Merge pull request #264 from Bwko/lint/org.go
Lint models/org.go
2016-11-27 12:18:20 +01:00
Thomas Boerger
7a92519bd7 Merge pull request #269 from lunny/lunny/golint_modules_log
Golint fixed for modules/log
2016-11-27 12:16:35 +01:00
Thomas Boerger
9a984c0d49 Merge pull request #266 from Bwko/lint/repo_mirror
Lint models/repo_mirror.go
2016-11-27 12:15:01 +01:00
Thomas Boerger
fe3908d099 Merge pull request #268 from Bwko/lint/repo_branch
Lint models/repo_branch.go
2016-11-27 12:14:25 +01:00
Thomas Boerger
e23a9d22e5 Merge pull request #267 from Bwko/lint/ssh_key
Lint models/ssh_key.go
2016-11-27 12:13:43 +01:00
Thomas Boerger
93d527a0a4 Merge pull request #265 from Bwko/lint/access.go
Lint models/access.go
2016-11-27 12:12:56 +01:00
Thomas Boerger
8347a55cc2 Merge pull request #263 from Bwko/lint/user_email
Lint models/user_email.go
2016-11-27 12:12:02 +01:00
Thomas Boerger
bc59b8abc9 Merge pull request #273 from typeless/master
modules/process: add ExecDirEnv (next to ExecDir)
2016-11-27 12:11:04 +01:00
Mura Li
9aaf2a6d9a modules/process: add ExecDirEnv (next to ExecDir)
Add a sibling to ExecDir which is capable of specifying environment variables,
so that we can invoke `git` with GIT_INDEX_FILE, GIT_DIR, etc..

For #258
2016-11-27 18:53:57 +08:00
Andrey Nering
3ac72255fa Merge pull request #272 from andreynering/gitea/location-cherrypick-a3ea4b8
Update locales and add Swedish
2016-11-27 08:49:26 -02:00
Andrey Nering
c664ffd1db Merge pull request #270 from andreynering/gitea/http-headers-download
Fix HTTP headers for issue attachment download
2016-11-27 08:48:26 -02:00
Lunny Xiao
94da472717 Golint fixed for modules/setting (#262)
* golint fixed for modules/setting

* typo fixed and renamed UNIXSOCKET to UnixSocket
2016-11-27 18:14:25 +08:00
Lunny Xiao
5b998a6680 golint fixed for modules/auth 2016-11-27 14:03:59 +08:00
Unknwon
4cb21115dc Update locales and add Swedish
Signed-off-by: Andrey Nering <andrey.nering@gmail.com>
2016-11-26 14:22:55 -02:00
Andrey Nering
d647d02c2f Fix Chrome not liking commas 2016-11-26 11:26:03 -02:00
Andrey Nering
638dd24cec Fix HTTP headers for issue attachment download
- Download filename was wrong for files other than images. Example: It was `download` instead of `file.pdf`
- PDF was downloading instead of showing on browser
2016-11-26 10:13:25 -02:00
Lunny Xiao
3228544c31 golint fixed for modules/log 2016-11-26 19:53:29 +08:00
Bwko
0b9cf10340 Lint models/org.go & models.go 2016-11-26 11:37:50 +01:00
Bwko
7bf7042013 Lint models/repo_mirror.go 2016-11-26 11:23:55 +01:00
Bwko
ce8c9ef580 Lint models/repo_branch.go 2016-11-26 11:20:37 +01:00
Bwko
6cde041080 Lint models/ssh_key.go 2016-11-26 01:36:03 +01:00
Bwko
2bb1601d7c Lint models/access.go 2016-11-26 01:07:57 +01:00
Bwko
066f515a47 Lint models/user_email.go 2016-11-26 01:03:06 +01:00
Thomas Boerger
0a76d260fa Merge pull request #260 from tboerger/drone-latest
Dropped latest publishing from drone
2016-11-25 17:13:55 +01:00
Thomas Boerger
65549863bc Dropped latest publishing from drone 2016-11-25 13:07:19 +01:00
Thomas Boerger
574e49c854 Merge pull request #241 from Bwko/lint/admin.go
Lint models/admin.go
2016-11-25 12:55:24 +01:00
Thomas Boerger
21b7d30174 Merge pull request #245 from Bwko/lint/update&slack
Lint models/update.go, release.go & webhook_slack.go
2016-11-25 12:55:14 +01:00
Thomas Boerger
e9c6053b86 Merge pull request #246 from Bwko/fix/typo
Fix typos
2016-11-25 12:54:57 +01:00
Thomas Boerger
177a4c7385 Merge pull request #259 from tboerger/drone-fixes
Fixed s3 publishing within drone
2016-11-25 11:48:17 +01:00
Thomas Boerger
0accc935a3 Fixed s3 publishing within drone 2016-11-25 10:53:48 +01:00
Thomas Boerger
5d4333eb0d Merge pull request #240 from go-gitea/drone-additions
Additions to the Drone CI integration
2016-11-25 10:25:01 +01:00
Thomas Boerger
32f8a38f6c Merge pull request #254 from lunny/lunny/golint_modules_context
Golint fixed for modules/context
2016-11-25 10:11:52 +01:00
Thomas Boerger
3ae7955d15 Disable broken docker build for now 2016-11-25 10:11:49 +01:00
Thomas Boerger
755ed84740 Be more explicit and dropped matrix builds from drone 2016-11-25 10:11:49 +01:00
Thomas Boerger
5b17661c5d Updated badges for drone and similar to lgtm 2016-11-25 10:11:49 +01:00
Thomas Boerger
3e6f363471 Merge pull request #256 from lunny/lunny/golint_modules_avatar
Golint fixed for modules/avatar
2016-11-25 10:11:44 +01:00
Thomas Boerger
2255a9af6a Merge pull request #255 from lunny/lunny/golint_modules_cron
Golint fixed for modules/cron
2016-11-25 10:11:36 +01:00
Thomas Boerger
26ae2ff86d Merge pull request #252 from lunny/lunny/golint_fixed_modules_httplib
Golint fixed for modules/httplib
2016-11-25 10:08:49 +01:00
Thomas Boerger
d39266228c Merge pull request #251 from lunny/lunny/golint_modules_template
Golint fixed for modules/template
2016-11-25 10:08:37 +01:00
Thomas Boerger
7c5de1e393 Merge pull request #250 from lunny/lunny/golint_modules_markdown
Golint fixed for modules/markdown
2016-11-25 10:08:23 +01:00
Thomas Boerger
a321ffbcce Merge pull request #249 from lunny/lunny/golint_modules_mailer
Golint fixed for modules/mailer
2016-11-25 10:07:52 +01:00
Lunny Xiao
3c87c57d96 golint fixed for modules/avatar 2016-11-25 16:37:04 +08:00
Lunny Xiao
b47051e59b golint fixed for modules/cron 2016-11-25 16:19:24 +08:00
Thomas Boerger
900a21008c Added errcheck make task (#242) 2016-11-25 16:12:06 +08:00
Bwko
c0ca6644ad Lint/issue &mail (#243)
* Lint models/release.go

* Lint models/ issue_label, issue_mail & mail.go
2016-11-25 16:11:12 +08:00
Bwko
081c2a9395 Lint models/token.go (#244) 2016-11-25 16:03:52 +08:00
Lunny Xiao
76604d8f90 fixed test build error 2016-11-25 16:02:10 +08:00
Bwko
33a2ac3830 Lint models/update.go & webhook_slack.go 2016-11-25 07:55:08 +01:00
Lunny Xiao
faabc76fd6 Golint fixed for modules/context 2016-11-25 14:53:59 +08:00
Lunny Xiao
bd5ea3e222 Golint fixed for modules/httplib 2016-11-25 14:32:09 +08:00
Lunny Xiao
229ec927b9 Golint fixed for modules/template 2016-11-25 14:23:48 +08:00
Lunny Xiao
304bbd3f25 golint fixed for modules/markdown 2016-11-25 09:58:05 +08:00
Lunny Xiao
2e565bc1c4 Golint fixed for modules/mailer 2016-11-25 09:44:04 +08:00
Andrey Nering
6a28909f40 CONTRIBUTING.md: link to "Faster reviews" document (#229)
* CONTRIBUTING.md: link to "Faster reviews" document

* CONTRIBUTING.md: small fixes
2016-11-25 09:25:34 +08:00
Bwko
d8e11a8eaa Lint models/admin.go 2016-11-24 23:42:07 +01:00
Bwko
ece19f4a5e Lint models/release.go 2016-11-24 22:02:54 +01:00
Thomas Boerger
21e8deed89 Merge pull request #96 from metalmatze/feature/drone-config
Create a first draft for .drone.yml
2016-11-24 21:36:47 +01:00
Lunny Xiao
450969c158 test database is connect OK after db config initialized (#239) 2016-11-24 22:30:36 +08:00
Thomas Boerger
ba2e75a0ab Merge pull request #238 from go-gitea/make-install
Really use go install on make install
2016-11-24 15:29:17 +01:00
Thomas Boerger
fd090dc29b Added matrix drone builds 2016-11-24 14:48:40 +01:00
Matthias Loibl
4c03974326 Create a first draft for .drone.yml 2016-11-24 14:47:36 +01:00
Thomas Boerger
cb0b91cdc9 Dropped travis config 2016-11-24 14:41:59 +01:00
Thomas Boerger
fd13b71fb2 Added drone instead of travis detection to makefile 2016-11-24 14:41:30 +01:00
Thomas Boerger
cd7e661870 Added dummy tasks for mysql and pgsql tests 2016-11-24 14:40:56 +01:00
Thomas Boerger
cc8c57458f Really use go install on make install 2016-11-24 14:38:37 +01:00
Thomas Boerger
b6b616b336 Merge pull request #228 from Bwko/feature/short-hash-download
Added short-hash support to downloads
2016-11-24 13:38:14 +01:00
Thomas Boerger
289f819f78 Merge pull request #237 from strk/login_source-lint
Lint models/login_source.go
2016-11-24 13:37:01 +01:00
Sandro Santilli
1c3044b873 Lint models/login_source.go 2016-11-24 12:34:38 +01:00
Bwko
ff0d1bd602 Added short-hash support to downloads 2016-11-24 11:45:16 +01:00
Thomas Boerger
2ccdcda072 Merge pull request #235 from lunny/lunny/golint_modules_user
golint fixed for modules/user
2016-11-24 11:33:47 +01:00
Thomas Boerger
0a66c2a2d9 Merge pull request #234 from strk/issue-lint
Lint issue.go
2016-11-24 11:30:39 +01:00
Thomas Boerger
e512411863 Merge pull request #233 from strk/git_diff-lint
Lint git_diff.go
2016-11-24 11:29:51 +01:00
Thomas Boerger
03b6880089 Merge pull request #232 from strk/error-lint
Lint error.go
2016-11-24 11:29:15 +01:00
Thomas Boerger
8ba0ac976f Merge pull request #231 from lunny/lunny/golint_modules_base
golint fixed for modules/base
2016-11-24 11:28:31 +01:00
Thomas Boerger
1cfbfb3812 Merge pull request #212 from strk/action-lint
Lint action.go
2016-11-24 11:17:04 +01:00
Thomas Boerger
f0cfb1cb03 Merge pull request #192 from strk/make-default-target
Have the default 'all' rule just build
2016-11-24 11:13:35 +01:00
Thomas Boerger
0581210a76 Merge pull request #176 from strk/manager-lint
Lint and document manager api
2016-11-24 11:10:34 +01:00
Lunny Xiao
46ecb0a14d golint fixed for modules/user 2016-11-24 17:37:11 +08:00
Sandro Santilli
8aa960f129 Actually document the missing bits 2016-11-24 09:41:11 +01:00
Sandro Santilli
3fba29c571 Expand documentations 2016-11-24 09:30:08 +01:00
Sandro Santilli
0a61d54a9c Expand documentation a bit more 2016-11-24 09:20:28 +01:00
Sandro Santilli
dd9d0f3732 Lint action.go 2016-11-24 09:03:29 +01:00
Sandro Santilli
170f2e98cc Lint error.go
This was done semi-programmatically, not really documenting anything
2016-11-24 09:03:17 +01:00
Sandro Santilli
6e644726d0 Lint git_diff.go
Semi-automatic linting (don't really document things)
2016-11-24 09:02:58 +01:00
Sandro Santilli
4dd1eb57bd Lint issue.go 2016-11-24 09:02:44 +01:00
Sandro Santilli
5301a5db3a Have the deault 'all' rule just build
Clean and test are saner being seperate targets
2016-11-24 09:02:32 +01:00
Sandro Santilli
ad3d6b7fff Lint and document manager api 2016-11-24 09:02:10 +01:00
Lunny Xiao
6ed7f269f1 Move init functions from routers/install to routers/init (#230)
* move init functions from routers/install to routers/init

* copyright typo
2016-11-24 15:40:16 +08:00
Lunny Xiao
fb3bb69ec6 golint fixed for modules/base 2016-11-24 15:17:44 +08:00
Lunny Xiao
3917ed45de golint fixed for routers (#208) 2016-11-24 15:04:31 +08:00
stroucki
3a3782bb7f Handle ssh key import better (#224)
* Handle user ssh key input better

ssh_key: when user submitted keys had a newline at the end, strings.Split
would have created a slice with an empty last element, and the key type
check would be incorrect. Perhaps a better way is to look for 'ssh-rsa' or
'ssh-dsa' at the beginning of the string, but this is simple.

* ssh_key: correct indentation
2016-11-24 08:52:55 +08:00
Lunny Xiao
cb1602840c golint fixed for routers/repo/branch.go (#206) 2016-11-22 16:32:00 +08:00
Sandro Santilli
c25063d834 Lint webhook.go, unexports simpleMarshalJSON (#198) 2016-11-22 14:42:52 +08:00
Bwko
2a449bd4b1 Fix typos 2016-11-21 20:08:21 +01:00
Lunny Xiao
b2cce12980 golint fixed for routers/repo/wiki.go (#203) 2016-11-21 18:03:42 +08:00
Lunny Xiao
f0df8e8dfa golint fixed for routers/repo/middlewares.go (#204) 2016-11-21 18:03:37 +08:00
Lunny Xiao
18dc4f1023 golint fixed for routers/repo/view.go (#205) 2016-11-21 18:03:29 +08:00
Thomas Boerger
1d9576d5ea Merge pull request #202 from lunny/lunny/golint_fixed_routers_admin
go lint fixed for routers/admin
2016-11-21 10:37:14 +01:00
Lunny Xiao
659bc2814c go lint fixed for routers/admin 2016-11-21 11:29:25 +08:00
Andrey Nering
bd13c81684 Merge pull request #196 from Bwko/fix/commit-view-panic
Fix panic when no user is signed in
2016-11-19 14:30:37 -02:00
Bwko
7b75d93f3d Fix for anonymous users to switch views 2016-11-19 16:53:34 +01:00
Bwko
fc3ed8a1de Fix panic when no user is signed in
See #188
2016-11-19 12:43:10 +01:00
Lunny Xiao
cf045b029c golint fixed for parts of routers root, dev, user and org dirs (#167)
* golint fixed for parts of routers root, dev and org dirs

* add user/auth.go golint fixed

* rename unnecessary exported to unexported and user dir golint fixed
2016-11-18 11:03:03 +08:00
Andrey Nering
91953ae9b4 Merge pull request #187 from strk/vendor
Add vendoring section
2016-11-17 17:35:48 -02:00
Sandro Santilli
39b3fcad1d Wrap vendor/ in backtics 2016-11-17 17:06:13 +01:00
Sandro Santilli
4faf9c213e Add vendoring section
Closes #178
2016-11-17 16:49:12 +01:00
Andrey Nering
d884312223 Merge pull request #100 from ethantkoenig/develop
API endpoints for stars
2016-11-17 07:15:15 -02:00
Ethan Koenig
0834e492c0 API endpoints for stars 2016-11-16 22:51:54 -05:00
Thibault Meyer
871c964ef7 Upgrade vendor "git" (#175) 2016-11-15 23:24:08 +08:00
Matthias Loibl
7596e41027 Merge pull request #171 from andreynering/gitea/editorconfig-crlf
.editorconfig: do not specify line ending
2016-11-15 12:06:41 +01:00
Thomas Boerger
56a8cf523b fix variable assigned and not used. (#173)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2016-11-15 07:53:16 +01:00
Bo-Yi Wu
d9ffe99972 fix variable assigned and not used.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2016-11-15 14:16:27 +08:00
Kim "BKC" Carlbäcker
07a0753420 Merge pull request #169 from strk/allow-update-draft-releases
Allow updating draft releases while keeping them as draft
2016-11-14 21:48:21 +01:00
Andrey Nering
6cf66117e7 Merge pull request #170 from strk/wiki-lint
Fix lint errors in models/wiki (just add methods docs)
2016-11-14 17:34:16 -02:00
Andrey Nering
a285c07d5e .editorconfig: do not specify line ending
That is annoying on Windows, since the editor will change the file if
you just open it. Git will checking as LF anyway.
2016-11-14 15:48:44 -02:00
Sandro Santilli
cd339263d9 Allow updating draft releases while keeping them as draft
Closes #162
2016-11-14 18:02:21 +01:00
Sandro Santilli
592a4ec4d3 Fix lint errors in models/wiki (just add methods docs)
See #70
2016-11-14 18:01:46 +01:00
Andrey Nering
81f227eace Merge pull request #168 from appleboy/gofmt
fix gofmt error.
2016-11-14 15:00:02 -02:00
Bo-Yi Wu
5054020c1f fix gofmt error.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2016-11-15 00:03:37 +08:00
Bo-Yi Wu
904deb7d6a Fix broken link for Contributors Guide (#166)
* Fix broken link for Contributors Guide

* remove ./
2016-11-14 08:17:15 +01:00
Andrey Nering
739f07c98e Remember diff view style (#163) 2016-11-13 10:54:04 +08:00
Lunny Xiao
bd76e156bb fixed bug #151 finally (#164) 2016-11-12 22:52:19 +08:00
LefsFlare
3ef022b071 Fixes possible vulnerabilities with keyword hijacking (#20)
- Added public entries to reserved keywords list
- Rename variables
- Derped comment
2016-11-12 13:26:45 +01:00
Lunny Xiao
3dedc027ac Bug fixed for issues (#156) 2016-11-12 13:06:33 +01:00
Thibault Meyer
54e6ed3431 Upgrade vendor "git" (#161) 2016-11-12 12:09:25 +01:00
Lunny Xiao
b339858500 replace footer gogs to gitea (#157) 2016-11-12 09:32:43 +01:00
Lunny Xiao
0baaa7728a bug fixed caused by #153 (#154) 2016-11-12 09:30:46 +01:00
Lunny Xiao
30a37311f8 use in instead string join (#155) 2016-11-12 09:29:18 +01:00
Lunny Xiao
555d8b16cb fixed bug #151 caused Find should be Get (#153) 2016-11-12 00:01:09 +01:00
Matthias Loibl
900f233b3c Merge pull request #152 from lunny/lunny/optimization_in
optimization on database IN
2016-11-11 22:09:54 +01:00
Lunny Xiao
ade6d4a20f optimization on database IN 2016-11-12 01:31:37 +08:00
Lunny Xiao
9bf28a2799 bug fixed for 500 caused by get org users (#149) 2016-11-12 00:55:06 +08:00
Lunny Xiao
a8c6698de8 Fix error 500 on organization dashboard page (#150) 2016-11-12 00:40:21 +08:00
Lunny Xiao
e2aa991e10 ask for go get from code.gitea.io/gitea and change gogs to gitea on main file (#146) 2016-11-11 14:56:35 +01:00
Thomas Boerger
5fc370e332 Merge pull request #142 from 0xbaadf00d/feature/gofmt
Normalize files with gofmt
2016-11-11 14:44:30 +01:00
Thomas Boerger
f07362b90f Merge pull request #144 from strk/install-via-go
Add instructions to install via go
2016-11-11 14:43:07 +01:00
Sandro Santilli
786cc5bbc8 Add info about installing via go 2016-11-11 13:35:58 +01:00
Thibault Meyer
ddee4c8b58 Normalize files with gofmt 2016-11-11 13:11:45 +01:00
Sandro Santilli
a1c5f02444 Fix import path of go-sdk (#141)
From code.gitea.io/go-sdk/gitea
  To code.gitea.io/sdk/gitea
2016-11-11 17:39:44 +08:00
Andrey Nering
96c9fef35f Update home page to Gitea (#138) 2016-11-11 08:50:31 +08:00
Andrey Nering
52cc3fd36a Merge pull request #136 from 0xbaadf00d/feature/rewrite-xorm-queries
Rewrite raw queries
2016-11-10 21:18:34 -02:00
Thibault Meyer
b12f2a5916 Remove unused import 2016-11-10 21:10:25 +01:00
Thibault Meyer
b0ddced2b5 Merge remote-tracking branch 'upstream/master' into feature/rewrite-xorm-queries
# Conflicts:
#	models/git_diff.go
#	models/issue.go
#	models/org.go
#	models/pull.go
#	models/repo.go
2016-11-10 21:05:52 +01:00
Thibault Meyer
a4454f5d0f Rewrite XORM queries 2016-11-10 20:59:51 +01:00
Sandro Santilli
4247304f5a Update import paths from github.com/go-gitea to code.gitea.io (#135)
- Update import paths from github.com/go-gitea to code.gitea.io
- Fix import path for travis

See https://docs.travis-ci.com/user/languages/go#Go-Import-Path
2016-11-10 17:24:48 +01:00
Andrey Nering
1c0a4e166f Merge pull request #134 from metalmatze/fix/admin-templates
Fix bug that tries to load mistyped templates
2016-11-10 13:06:54 -02:00
Matthias Loibl
63ca42d17f Fix bug that tries to load mistyped templates 2016-11-10 11:54:20 +01:00
Rachid Zarouali
c040f2fbb1 first batch of Readme updates (#65) 2016-11-10 11:52:39 +01:00
Matthias Loibl
94b2747375 Remove go version from build tags (#133) 2016-11-10 08:43:49 -02:00
Matthias Loibl
31da225309 Check unhandled errors (#128) 2016-11-10 08:02:01 -02:00
Matthias Loibl
24d7bae2b2 Merge pull request #131 from 0xbaadf00d/feature/gitignore
Add IDEA IntelliJ to .gitignore
2016-11-10 10:53:43 +01:00
Lunny Xiao
1b238fe4d5 Merge pull request #121 from joubertredrat/feature-last-login
Last Login for admin manage your users
2016-11-10 17:20:55 +08:00
Lunny Xiao
c6c840faf7 Merge pull request #129 from lunny/lunny/SQL_instead_Sql
use x.SQL instead of x.Sql
2016-11-10 17:12:14 +08:00
Thibault Meyer
7ea943d501 Add IDEA IntelliJ to .gitignore 2016-11-10 10:01:44 +01:00
Lunny Xiao
b5bfab9855 Merge pull request #130 from 0xbaadf00d/feature/ordering-org-user
Ordering organizations and users by name
2016-11-10 16:56:36 +08:00
Thibault Meyer
3a10a0c1ca Ordering organizations and users by name 2016-11-10 09:18:54 +01:00
Lunny Xiao
7dcc3bc3d7 use x.SQL instead of x.Sql 2016-11-10 15:20:48 +08:00
Lunny Xiao
145648a233 Merge pull request #127 from metalmatze/enhancement/cli
Use cli Flags directly and not some helper funcs
2016-11-10 11:31:26 +08:00
Matthias Loibl
90fb64b217 Improve formatting of admin command
Signed-off-by: Matthias Loibl <mail@matthiasloibl.com>
2016-11-09 23:32:24 +01:00
Matthias Loibl
5cd093aa46 Use cli Flags directly and not some helper funcs
Signed-off-by: Matthias Loibl <mail@matthiasloibl.com>
2016-11-09 23:18:22 +01:00
Joubert RedRat
f91cbf0fed Support to last login feature 2016-11-09 08:53:45 -02:00
Lunny Xiao
475ddd8d89 Merge pull request #116 from lunny/lunny/lang-miss
fixed lack of translation for zh-CN
2016-11-09 15:16:27 +08:00
Lunny Xiao
c511f1c6c3 Merge pull request #18 from LefsFlarey/issue/3675
Fix 500 error caused by deleted users on issues (#3675)
2016-11-09 15:14:18 +08:00
Flare
a6c487f6ca Fix err not being nil 2016-11-09 13:07:01 +08:00
Matthias Loibl
45c4539c61 Merge pull request #17 from LefsFlarey/issue/3666
Fixed 404 caused by unexpected question mark
2016-11-08 18:27:59 +01:00
Flare
01c5233b53 Fixed 404 caused by unexpected question mark
This fixes 404 caused when creating new files or wiki pages with question marks. Amended to force CI rebuild
2016-11-08 22:09:48 +08:00
Lunny Xiao
f6d53ecbc1 Merge pull request #119 from metalmatze/fix/editorconfig
Go uses ident size 8 with tabs. Nothing else.
2016-11-08 19:13:29 +08:00
Matthias Loibl
1ceb56fc7f Go uses ident size 8 with tabs. Nothing else.
We are using gofmt to format our code. This will emit tabs.
The standard is tabs which is 8 spaces.
2016-11-08 11:41:02 +01:00
Kim "BKC" Carlbäcker
85b8b7f4e1 Merge pull request #90 from metalmatze/feature/tool-tests
Start to add tests for modules/base/tool
2016-11-08 10:30:52 +01:00
Lunny Xiao
8b0576b377 lack of translation for zh-CN 2016-11-08 16:20:45 +08:00
Lunny Xiao
8857d701fb Merge pull request #115 from strk/license
Re-add "Gogs authors" copyright (togheter with "Gitea authors")
2016-11-08 15:57:46 +08:00
Lunny Xiao
e06e0f9bb9 Merge pull request #113 from avelino/update_locale
replace Gogs to Gitea on locale files
2016-11-08 15:56:00 +08:00
Sandro Santilli
4e4c0c2cd3 Fix typo 2016-11-08 08:42:05 +01:00
Sandro Santilli
dad9dbacf7 Re-add "Gogs authors" copyright (togheter with "Gitea authors") 2016-11-08 08:36:19 +01:00
Thiago Avelino
5ea257be87 update copyright gitea license (#112) 2016-11-08 07:57:25 +01:00
Avelino
b4671c9aab replace Gogs to Gitea on locale files 2016-11-08 01:21:31 -02:00
Lunny Xiao
5667d4daae Merge pull request #73 from bkcsoft/gt/2164-release-pagination
Add Pagination to Releases-page (and de-duplicate pagination templates)
2016-11-08 10:39:03 +08:00
Matthias Loibl
e74868a850 Add test for IsTextFile() 2016-11-07 23:31:40 +01:00
Matthias Loibl
95d4cd9292 Make long godoc comment 2 lines 2016-11-07 23:31:40 +01:00
Matthias Loibl
2bb188ae79 Add test for IsLetter() 2016-11-07 23:31:40 +01:00
Matthias Loibl
4235fff9ee Add test for Int64sToMap() 2016-11-07 23:31:40 +01:00
Matthias Loibl
d417aedcfa Add tests for StringsToInt64s() & Int64sToStrings() 2016-11-07 23:31:40 +01:00
Matthias Loibl
b00d82d679 Add tests for TruncateString() 2016-11-07 23:31:40 +01:00
Matthias Loibl
86c32f2706 Use TruncateString(sha1,10) in ShortSha and deprecate it. 2016-11-07 23:31:39 +01:00
Matthias Loibl
030ba2894f Add tests for EllipsisString() and fix bug if param length < 3 2016-11-07 23:31:39 +01:00
Matthias Loibl
f81711f40d Test AvatarLink and refactor with tests passing 2016-11-07 23:31:39 +01:00
Matthias Loibl
a5d0b4de5b Vendor github.com/stretchr/testify for the assert package 2016-11-07 23:31:39 +01:00
Matthias Loibl
70fb1cf9d1 Use testify/assert for all tests in tool_test.go 2016-11-07 23:29:42 +01:00
Matthias Loibl
d874a9bf6b Add unit test for base.FileSize() 2016-11-07 23:29:42 +01:00
Matthias Loibl
11c9160cd3 Start to add tests for modules/base/tool 2016-11-07 23:29:41 +01:00
Sandro Santilli
864d1b1f9f Fix type in unused constant name (#111)
* Write LDAP, SMTP, PAM, DLDAP back to all uppercase

* Fix type in unused constant name

* Other MixCased fixes

* Complete MixerCasing of template constants

* Re uppercase LTS and LDAPS suffixes

* Uppercase JSON suffix in constant names

* Proper case LoginNoType

* Prefix unexported template path constants with "tpl"
2016-11-07 18:58:22 -02:00
Matthias Loibl
c8c748aea6 Merge pull request #109 from go-gitea/lgtm
Added ignore_maintainers_file option to .lgtm
2016-11-07 20:07:47 +01:00
Sandro Santilli
01a7674b5c Merge pull request #110 from strk/MixedCaseConst
Use MixedCase constant names
2016-11-07 19:22:21 +01:00
Sandro Santilli
b7bf9dfd28 more 2016-11-07 17:55:31 +01:00
Sandro Santilli
aadd7dcdc3 And others 2016-11-07 17:53:22 +01:00
Sandro Santilli
b3828e38a5 more 2016-11-07 17:41:28 +01:00
Sandro Santilli
05fd9d3f09 Security protocols 2016-11-07 17:38:43 +01:00
Sandro Santilli
7612b5ec40 More mixage 2016-11-07 17:37:28 +01:00
Sandro Santilli
64196d4036 More overlooks 2016-11-07 17:35:34 +01:00
Sandro Santilli
f14232d2e9 This one I overlooked before 2016-11-07 17:33:03 +01:00
Sandro Santilli
60c82a8780 More... 2016-11-07 17:30:04 +01:00
Sandro Santilli
f6a11e0de1 More MixedCase consts 2016-11-07 17:24:59 +01:00
Sandro Santilli
f388661bda ACCESS_MODE_* -> AccessMode* 2016-11-07 17:20:37 +01:00
Sandro Santilli
0b62aeb495 More MixedCase consts 2016-11-07 17:08:21 +01:00
Sandro Santilli
80eea77953 Use MixedCase constant names
See https://github.com/golang/go/wiki/CodeReviewComments#mixed-caps
2016-11-07 17:05:08 +01:00
Thomas Boerger
d944bdec47 Added ignore_maintainers_file option to .lgtm 2016-11-07 16:36:37 +01:00
Thomas Boerger
5d430c9e68 Merge pull request #108 from go-gitea/go-sdk
Replaced gogits go-gogs-client with go-sdk
2016-11-07 16:31:17 +01:00
Sandro Santilli
ee963f67c1 Merge pull request #103 from strk/GOGS_drop
Replace GOGS with GITEA in variable names
2016-11-07 16:30:48 +01:00
Joubert RedRat
9c434ccc50 Change binary name from main to gitea 2016-11-07 13:26:19 -02:00
Joubert RedRat
28bee28102 Replace Gogs to Gitea in installation options 2016-11-07 13:26:19 -02:00
Sandro Santilli
f430d26f7e Hush dangerous GNU comment, mark "check" rule as phony 2016-11-07 13:25:50 -02:00
Sandro Santilli
3f18111cbe Add "check" alias for testing
Follows GNU Coding Standards, see
https://www.gnu.org/prep/standards/html_node/Standard-Targets.html#Standard-Targets
2016-11-07 13:25:50 -02:00
Thomas Boerger
4c6c16f358 Replaced go-gogs-client with go-sdk imports 2016-11-07 16:10:32 +01:00
Thomas Boerger
77f9c7e571 Fixed links to sdk docs 2016-11-07 16:10:32 +01:00
Thomas Boerger
e378648c79 Added updated go-sdk 2016-11-07 16:10:32 +01:00
Thomas Boerger
d1b14fef56 Stop ignoring gitea in general 2016-11-07 16:10:32 +01:00
Sandro Santilli
30be1f4826 Fix typo in unused constant name 2016-11-07 16:06:21 +01:00
Sandro Santilli
145ab5c89a Rename and update init files to use "gitea" instead of "gogs"
Closes #102
2016-11-07 16:06:21 +01:00
Sandro Santilli
b7263f31a5 Replace GOGS with GITEA in variable names
Still use GOGS_WORK_DIR and GOGS_CUSTOM env variables
as a fallback if the equivalent GITEA_* are not set,
warning user about the need for change.

Does not change "gogs" to "gitea" in webhook type name
Because "gogs" hook type is part of the API (routes) and used
in templates...

Closes #87
2016-11-07 16:05:18 +01:00
Thomas Boerger
6f3097f9e6 Dropped github.com/gogits/go-gogs-client vendored dep 2016-11-07 15:51:49 +01:00
Thomas Boerger
3e13e16b3f Dropped client from version check 2016-11-07 14:49:25 +01:00
Thomas Boerger
a6d683f498 Link to godoc instead of Gogs wiki 2016-11-07 14:49:25 +01:00
Thomas Boerger
ceb920802a Dropped link to Gogs docs from template 2016-11-07 14:49:25 +01:00
Thomas Boerger
6bf9910975 Set correct doc url for go-sdk 2016-11-07 14:49:25 +01:00
Lunny Xiao
1b962bac0b Merge pull request #97 from andreynering/gitea/diff-colors
CSS: Stronger colors for diffs
2016-11-07 20:39:20 +08:00
Kim "BKC" Carlbäcker
562f9b6eae Merge all pagination-templates into 'base/paginate'
to reduce code-duplicity
2016-11-07 12:44:29 +01:00
Kim "BKC" Carlbäcker
86fb1a0cb1 Add Pagination to Releases-page 2016-11-07 11:41:09 +01:00
Rachid Zarouali
be5607e510 Merge pull request #50 from 0xbaadf00d/feature/2583-disablehttpcloning
Disable HTTP cloning
2016-11-07 11:23:30 +01:00
Odin Ugedal
5a6f7edde9 Use the rev-parsed sha1 commit id (#98)
Use the rev-parsed sha1 commit id in urls to repo files,
instead of the abbreviated version.
2016-11-06 19:15:44 -02:00
Andrey Nering
ef5fc3c959 CSS: Stronger colors for diffs 2016-11-06 17:57:45 -02:00
Matthias Loibl
92c48dabe3 Merge pull request #95 from odinuge/readmeTxt
Fix rendering of non-markdown readme files
2016-11-06 19:54:46 +01:00
Odin Ugedal
530f6c1da4 Fix rendering of non-markdown readme files 2016-11-06 16:02:42 +01:00
Sandro Santilli
6e4252dad4 Replace gogits/git-module dependency with go-gitea/git (#94)
* Replace gogits/git-module dependency with go-gitea/git

Fixes #92

* Remove git alias for git module import (not needed)
2016-11-06 11:18:34 -02:00
LefsFlare
55a4d46f5d Adds checking of reserved keywords against team names (#22) 2016-11-06 10:07:03 +01:00
Thibault Meyer
fe8bfa54de Ordering team by name ascending except for 'Owners' (#48) 2016-11-06 09:59:21 +01:00
Matthias Loibl
d318f612a9 Add tests for CurrentUsername() (#88) 2016-11-06 09:47:25 +01:00
Lunny Xiao
1cb5b0e2f6 Merge pull request #83 from strk/dot.github
Review issue and pull templates, drop unused contributing file
2016-11-06 12:30:31 +08:00
Sandro Santilli
27f99a16a6 Review issue and pull templates, drop unused contributing file
The CONTRIBUTING.md from root dir will be used by github
2016-11-05 23:24:21 +01:00
Sandro Santilli
9f437eb1ab Wrap text to 80 columns (#81)
Use a list for owners (nitpick response)
2016-11-05 23:23:14 +01:00
Matthias Loibl
92f39da802 Merge pull request #85 from metalmatze/feature/goimports
Fix imports found by goimports.
2016-11-05 23:08:29 +01:00
Sandro Santilli
f36544f98d Merge branch 'master' into feature/goimports 2016-11-05 22:54:20 +01:00
Matthias Loibl
a0e54c0512 Merge pull request #84 from andreynering/gitea/fix-500-on-invalid-editorconfig
Refactor editorconfig middleware
2016-11-05 19:01:20 +01:00
Andrey Nering
bd898a10f8 Refactor editorconfig middleware 2016-11-05 15:44:14 -02:00
Matthias Loibl
953c099428 Add missing version & gogs package 2016-11-05 18:04:47 +01:00
Matthias Loibl
1f44b01e2a Fix imports found by goimports. 2016-11-05 17:56:35 +01:00
Matthias Loibl
91b589f2f0 Add myself to the MAINTAINERS (#82)
😊
2016-11-05 14:32:11 -02:00
Sandro Santilli
789dacdfbe Merge pull request #59 from andreynering/gitea/fix-500-on-invalid-editorconfig
Fix 500 when repo has invalid .editorconfig
2016-11-05 16:53:36 +01:00
Andrey Nering
984fa8d83b Fix 500 when repo has invalid .editorconfig
Creating a notice instead
2016-11-05 13:33:41 -02:00
Thomas Boerger
ab12596143 Merge pull request #79 from strk/Makefile-tabs
Use tabs in Makefiles
2016-11-05 16:13:33 +01:00
Sandro Santilli
6111e09a97 Drop indent-size from Makefile section 2016-11-05 13:26:11 +01:00
Sandro Santilli
c808e8c138 Use tabs in Makefiles 2016-11-05 12:55:27 +01:00
Thomas Boerger
b58b634e0e Merge pull request #69 from go-gitea/makefile
Refactoring of the makefile
2016-11-05 00:06:41 +01:00
Thomas Boerger
c524078d2b Extended gitignore 2016-11-04 23:46:11 +01:00
Thomas Boerger
b32776d533 Dropped outdated build scripts 2016-11-04 23:46:11 +01:00
Thomas Boerger
3dd14ee522 Fixed "net.UnixAddr composite literal uses unkeyed fields" 2016-11-04 23:45:47 +01:00
Thomas Boerger
ec054ba582 Totally refactored the makefile and adjusted travis config 2016-11-04 23:45:47 +01:00
Thomas Boerger
7a870080d6 Added a common golang gitignore 2016-11-04 23:45:06 +01:00
Thomas Boerger
eb25d1f252 Regenerated bindata 2016-11-04 23:45:06 +01:00
Thomas Boerger
5b5af7daee Made linter happy in cmd folder 2016-11-04 23:45:06 +01:00
Thomas Boerger
212a04a45e Linter doesn't like uppercase variables 2016-11-04 23:45:06 +01:00
Thomas Boerger
648c6fdd60 Vet complains about "should have signature MarshalJSON() ([]byte, error)", replaced with custom name 2016-11-04 23:45:06 +01:00
Thomas Boerger
f960b776f0 Simply made go vet happy, fixed tags 2016-11-04 23:45:06 +01:00
Thomas Boerger
e05a5ca36c Executed go fmt for all files 2016-11-04 23:45:06 +01:00
Thomas Boerger
ba4d255635 Merge pull request #33 from metalmatze/feature/main.go
Rename gogs.go to main.go with all references
2016-11-04 23:44:42 +01:00
Thomas Boerger
cda6baf02c Merge branch 'master' into feature/main.go 2016-11-04 23:24:55 +01:00
Thomas Boerger
a46efe240d Merge pull request #54 from joubertredrat/changes-less-css
Set default less and css to new default name
2016-11-04 23:24:45 +01:00
Flare
fd6be0d17e Still print error if user does not exist 2016-11-05 02:47:54 +08:00
Thomas Boerger
747f86aa23 Merge branch 'master' into changes-less-css 2016-11-04 19:23:32 +01:00
Thomas Boerger
03902bb53d Minor cleanups, look at the specific commits (#67)
* Dropped codebeat, we got go reportcard

* Dropped gopm file, we are using govendor

* Dropped chinese readme, this should be part of the docs

* Dropped bra config, not really used

* Dropped packager, we will provide our own packages
2016-11-04 14:27:33 -02:00
Thomas Boerger
6a20711afd Merge pull request #72 from go-gitea/maintainers
One more try to validate maintainers and contributors
2016-11-04 16:39:17 +01:00
Thomas Boerger
ccdbd8bf48 One more try to validate maintainers and contributors 2016-11-04 16:37:50 +01:00
Thomas Boerger
38c209e85b Merge pull request #71 from go-gitea/lgtm-fix
Use a correct format for CONTRIBUTORS and MAINTAINERS
2016-11-04 16:33:38 +01:00
Thomas Boerger
1aaa3a303d Use a correct format for CONTRIBUTORS and MAINTAINERS 2016-11-04 16:18:25 +01:00
Thomas Boerger
75ddcddd06 Merge branch 'master' into changes-less-css 2016-11-04 14:36:24 +01:00
Thomas Boerger
8e66e09cd8 Merge branch 'master' into feature/main.go 2016-11-04 14:35:45 +01:00
Thomas Boerger
4fdca026c7 Merge pull request #62 from lunny/master
Added CONTRIBUTING
2016-11-04 14:30:35 +01:00
Thomas Boerger
13c3edde05 Merge branch 'master' into master 2016-11-04 14:08:31 +01:00
Matthias Loibl
f01d927efb Rename all occurrences of gogs.go
Signed-off-by: Matthias Loibl <mail@matthiasloibl.com>
2016-11-04 13:49:10 +01:00
Matthias Loibl
a2514904cb Rename gogs.go to main.go
Signed-off-by: Matthias Loibl <mail@matthiasloibl.com>
2016-11-04 13:44:23 +01:00
Matthias Loibl
a4fa889ced Run goimports on the whole project (#34)
Signed-off-by: Matthias Loibl <mail@matthiasloibl.com>
2016-11-04 09:57:27 -02:00
Joubert RedRat
ff54e4d929 Set default less and css to new default name 2016-11-04 08:53:18 -02:00
Lunny Xiao
587d870f1e follow the advisor: add DCO and some improvements 2016-11-04 16:43:41 +08:00
Thomas Boerger
fc55182a4c Merge pull request #41 from DblK/feature-issueTrackerLink
Allow user to set an external tracker url and forward to it
2016-11-04 09:37:13 +01:00
Rémy Boulanouar
8dc49dc114 Implementation of the feature to redirect to an external issue tracker 2016-11-04 09:06:54 +01:00
Lunny Xiao
4a5faecd8f Merge pull request #58 from go-gitea/vendoring
Integrated dependency manager
2016-11-04 16:04:20 +08:00
Thomas Boerger
f8b4699a14 Dropped go get from travis config 2016-11-04 08:43:11 +01:00
Thomas Boerger
1ebb35b988 Added all required dependencies 2016-11-04 08:43:11 +01:00
Thomas Boerger
78f86abba4 Added vendoring config for govendor 2016-11-04 08:43:11 +01:00
Thomas Boerger
90402a6328 Dropped glide configs 2016-11-04 08:43:11 +01:00
Thomas Boerger
998e7452b8 Dropped vendoring from gitignore 2016-11-04 08:43:11 +01:00
Thibault Meyer
17f9ab4ff8 Use user fullname if resolved 2016-11-04 08:13:14 +01:00
Lunny Xiao
33df11e823 typo and contributing improved 2016-11-04 15:05:45 +08:00
Kim "BKC" Carlbäcker
5a8cb2dac1 Merge pull request #60 from andreynering/gitea/issue-pr-number-on-title
Show issue/PR number on title
2016-11-04 03:14:31 +01:00
Lunny Xiao
0d41394d6e diff the CONTRIBUTORS and MAINTAINERS 2016-11-04 09:54:57 +08:00
Lunny Xiao
55e804e078 Merge branch 'master' of https://github.com/go-gitea/gitea 2016-11-04 09:40:38 +08:00
Lunny Xiao
a90b25226a added CONTRIBUTING 2016-11-04 09:39:04 +08:00
Andrey Nering
87b593f93e Show issue/PR number on title 2016-11-03 20:28:05 -02:00
Sandro Santilli
137dcbf93d Merge pull request #47 from 0xbaadf00d/fix/3743-route-regexp-branchname
Fix SHA and compare regex on route file [Critical]
2016-11-03 17:51:33 +01:00
Lunny Xiao
1adde07a3f Merge branch 'master' into fix/3743-route-regexp-branchname 2016-11-04 00:11:08 +08:00
Thomas Boerger
42a744d9e6 Badges and travis testing (#40)
* Added badges to the README

* Restructured the travis config
2016-11-03 12:50:44 -02:00
Rémy Boulanouar
2d68bd1ef9 Change import reference to match gitea instead of gogs (#37) 2016-11-03 10:29:56 -02:00
Thibault Meyer
8ea63f8c50 Restore whitespace 2016-11-03 09:37:24 +01:00
Thibault Meyer
a79eb48de3 Fix SHA regexp and commit comparisons 2016-11-03 09:32:55 +01:00
Thomas Boerger
507ce134fa Merge pull request #5 from joubertredrat/title-ui-fix
Small UI fixes on full width form titles
2016-11-03 09:09:51 +01:00
Thomas Boerger
bc7e92a2b5 Merge branch 'develop' into title-ui-fix 2016-11-03 09:09:00 +01:00
Thomas Boerger
e4fe69365f Merge pull request #23 from lunny/develop
config lgtm to disable maintainer to LGTM himself's PR
2016-11-03 09:08:09 +01:00
Thomas Boerger
980282a06f Merge branch 'develop' into develop 2016-11-03 09:07:55 +01:00
Lunny Xiao
d8de2beb5b Merge pull request #2 from strk/proper-from-on-issue-mail
Fix sender of issue notifications
2016-11-03 16:06:27 +08:00
Lunny Xiao
060d10a4cb config lgtm to disable maintainer to LGTM himself's PR 2016-11-03 14:41:13 +08:00
Sandro Santilli
af03d00780 Fix sender of issue notifications
It is the FROM field in mailer configuration that needs be used,
not the USER field, which is for authentication.

Closes https://github.com/gogits/gogs/issues/3615
2016-11-02 21:00:54 +01:00
Thomas Boerger
5c54243014 Merge pull request #3 from strk/libravatar-proper-url
Use proper url for libravatar dep
2016-11-02 19:22:31 +01:00
Sandro Santilli
d59a48a255 Use proper url for libravatar dep 2016-11-02 18:18:04 +01:00
Joubert RedRat
f3321d920d Small UI fixes on full width form titles 2016-10-19 11:21:10 -02:00
Thibault Meyer
e54dec7ce5 missing space 2016-10-04 18:59:07 +02:00
Thibault Meyer
93f1eabe30 rename variable + fix wiki link 2016-10-04 18:58:14 +02:00
Flare
1b59e6f910 Fix 500 error caused by deleted users on issues (#3675) 2016-09-20 18:13:57 +08:00
Thibault Meyer
9d66497abc Can disable GIT interactions by HTTP protocol 2016-09-18 10:54:33 +02:00
1888 changed files with 824802 additions and 12437 deletions

View File

@@ -1,19 +0,0 @@
[run]
init_cmds = [
["make", "build-dev"],
["./gogs", "web"]
]
watch_all = true
watch_dirs = [
"$WORKDIR/cmd",
"$WORKDIR/models",
"$WORKDIR/modules",
"$WORKDIR/routers"
]
watch_exts = [".go"]
ignore_files = [".+_test.go"]
build_delay = 1500
cmds = [
["make", "build-dev"], # TAGS=sqlite cert pam tidb
["./gogs", "web"]
]

View File

@@ -1,7 +0,0 @@
conf/**
docker/**
modules/bindata/**
packager/**
public/**
scripts/**
templates/**

View File

@@ -1,7 +0,0 @@
{
"GOLANG": {
"TOTAL_LOC": [500, 999, 1999, 9999],
"TOO_MANY_FUNCTIONS": [50, 99, 199, 999],
"TOO_MANY_IVARS": [20, 50, 70, 99]
}
}

View File

@@ -1,19 +1,5 @@
.git
.git/**
packager
packager/**
scripts
scripts/**
.github/
.github/**
config.codekit
.dockerignore
*.yml
*.md
.bra.toml
.editorconfig
.gitignore
Dockerfile*
vendor
vendor/**
gogs
*
!gitea
!docker
!public
!templates

150
.drone.yml Normal file
View File

@@ -0,0 +1,150 @@
workspace:
base: /srv/app
path: src/code.gitea.io/gitea
pipeline:
clone:
image: plugins/git
tags: true
test:
image: webhippie/golang:edge
pull: true
environment:
CGO_ENABLED: 1
TAGS: sqlite bindata
GOPATH: /srv/app
commands:
- apk -U add openssh-client
- make clean
- make generate
- make vet
- make lint
- make test
- make build
when:
event: [ push, tag, pull_request ]
test-mysql:
image: webhippie/golang:edge
pull: true
environment:
CGO_ENABLED: 1
TAGS: sqlite bindata
GOPATH: /srv/app
commands:
- 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
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 ]
docker:
image: plugins/docker
repo: gitea/gitea
tags: [ '${DRONE_TAG##v}' ]
when:
event: [ tag ]
branch: [ refs/tags/* ]
docker:
image: plugins/docker
repo: gitea/gitea
tags: [ '${DRONE_BRANCH##release/v}' ]
when:
event: [ push ]
branch: [ release/* ]
docker:
image: plugins/docker
repo: gitea/gitea
tags: [ 'latest' ]
when:
event: [ push ]
branch: [ master ]
release:
image: plugins/s3
path_style: true
strip_prefix: dist/release/
source: dist/release/*
target: /gitea/${DRONE_TAG##v}
when:
event: [ tag ]
branch: [ refs/tags/* ]
release:
image: plugins/s3
path_style: true
strip_prefix: dist/release/
source: dist/release/*
target: /gitea/${DRONE_BRANCH##release/v}
when:
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
files:
- dist/release/*
when:
event: [ tag ]
branch: [ refs/tags/* ]
gitter:
image: plugins/gitter
services:
mysql:
image: mysql:5.7
environment:
- MYSQL_DATABASE=test
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
when:
event: [ push ]
pgsql:
image: postgres:9.5
environment:
- POSTGRES_DB=test
when:
event: [ push ]

1
.drone.yml.sig Normal file
View File

@@ -0,0 +1 @@
eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9zcnYvYXBwCiAgcGF0aDogc3JjL2NvZGUuZ2l0ZWEuaW8vZ2l0ZWEKCnBpcGVsaW5lOgogIGNsb25lOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0CiAgICB0YWdzOiB0cnVlCgogIHRlc3Q6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgQ0dPX0VOQUJMRUQ6IDEKICAgICAgVEFHUzogc3FsaXRlIGJpbmRhdGEKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gYXBrIC1VIGFkZCBvcGVuc3NoLWNsaWVudAogICAgICAtIG1ha2UgY2xlYW4KICAgICAgLSBtYWtlIGdlbmVyYXRlCiAgICAgIC0gbWFrZSB2ZXQKICAgICAgLSBtYWtlIGxpbnQKICAgICAgLSBtYWtlIHRlc3QKICAgICAgLSBtYWtlIGJ1aWxkCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIHRlc3QtbXlzcWw6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgQ0dPX0VOQUJMRUQ6IDEKICAgICAgVEFHUzogc3FsaXRlIGJpbmRhdGEKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gbWFrZSB0ZXN0LW15c3FsCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KCiAgdGVzdC1wZ3NxbDoKICAgIGltYWdlOiB3ZWJoaXBwaWUvZ29sYW5nOmVkZ2UKICAgIHB1bGw6IHRydWUKICAgIGVudmlyb25tZW50OgogICAgICBDR09fRU5BQkxFRDogMQogICAgICBUQUdTOiBzcWxpdGUgYmluZGF0YQogICAgICBHT1BBVEg6IC9zcnYvYXBwCiAgICBjb21tYW5kczoKICAgICAgLSBtYWtlIHRlc3QtcGdzcWwKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQoKICB1cGRhdGVyOgogICAgaW1hZ2U6IGthcmFsYWJlL3hnby1sYXRlc3Q6bGF0ZXN0CiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgQ0dPX0VOQUJMRUQ6IDEKICAgICAgVEFHUzogc3FsaXRlIGJpbmRhdGEKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gbWFrZSByZWxlYXNlCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcgXQogICAgICBicmFuY2g6IFsgbWFzdGVyLCByZWxlYXNlLyosIHJlZnMvdGFncy8qIF0KCiAgY292ZXJhZ2U6CiAgICBpbWFnZTogcGx1Z2lucy9jb3ZlcmFnZQogICAgc2VydmVyOiBodHRwczovL2NvdmVyYWdlLmdpdGVhLmlvCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIGRvY2tlcjoKICAgIGltYWdlOiBwbHVnaW5zL2RvY2tlcgogICAgcmVwbzogZ2l0ZWEvZ2l0ZWEKICAgIHRhZ3M6IFsgJyR7RFJPTkVfVEFHIyN2fScgXQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgdGFnIF0KICAgICAgYnJhbmNoOiBbIHJlZnMvdGFncy8qIF0KCiAgZG9ja2VyOgogICAgaW1hZ2U6IHBsdWdpbnMvZG9ja2VyCiAgICByZXBvOiBnaXRlYS9naXRlYQogICAgdGFnczogWyAnJHtEUk9ORV9CUkFOQ0gjI3JlbGVhc2Uvdn0nIF0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQogICAgICBicmFuY2g6IFsgcmVsZWFzZS8qIF0KCiAgZG9ja2VyOgogICAgaW1hZ2U6IHBsdWdpbnMvZG9ja2VyCiAgICByZXBvOiBnaXRlYS9naXRlYQogICAgdGFnczogWyAnbGF0ZXN0JyBdCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIG1hc3RlciBdCgogIHJlbGVhc2U6CiAgICBpbWFnZTogcGx1Z2lucy9zMwogICAgcGF0aF9zdHlsZTogdHJ1ZQogICAgc3RyaXBfcHJlZml4OiBkaXN0L3JlbGVhc2UvCiAgICBzb3VyY2U6IGRpc3QvcmVsZWFzZS8qCiAgICB0YXJnZXQ6IC9naXRlYS8ke0RST05FX1RBRyMjdn0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHRhZyBdCiAgICAgIGJyYW5jaDogWyByZWZzL3RhZ3MvKiBdCgogIHJlbGVhc2U6CiAgICBpbWFnZTogcGx1Z2lucy9zMwogICAgcGF0aF9zdHlsZTogdHJ1ZQogICAgc3RyaXBfcHJlZml4OiBkaXN0L3JlbGVhc2UvCiAgICBzb3VyY2U6IGRpc3QvcmVsZWFzZS8qCiAgICB0YXJnZXQ6IC9naXRlYS8ke0RST05FX0JSQU5DSCMjcmVsZWFzZS92fQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCiAgICAgIGJyYW5jaDogWyByZWxlYXNlLyogXQoKICByZWxlYXNlOgogICAgaW1hZ2U6IHBsdWdpbnMvczMKICAgIHBhdGhfc3R5bGU6IHRydWUKICAgIHN0cmlwX3ByZWZpeDogZGlzdC9yZWxlYXNlLwogICAgc291cmNlOiBkaXN0L3JlbGVhc2UvKgogICAgdGFyZ2V0OiAvZ2l0ZWEvbWFzdGVyCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIG1hc3RlciBdCgogIGdpdGh1YjoKICAgIGltYWdlOiBwbHVnaW5zL2dpdGh1Yi1yZWxlYXNlCiAgICBmaWxlczoKICAgICAgLSBkaXN0L3JlbGVhc2UvKgogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgdGFnIF0KICAgICAgYnJhbmNoOiBbIHJlZnMvdGFncy8qIF0KCiAgZ2l0dGVyOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0dGVyCgpzZXJ2aWNlczoKICBteXNxbDoKICAgIGltYWdlOiBteXNxbDo1LjcKICAgIGVudmlyb25tZW50OgogICAgICAtIE1ZU1FMX0RBVEFCQVNFPXRlc3QKICAgICAgLSBNWVNRTF9BTExPV19FTVBUWV9QQVNTV09SRD15ZXMKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQoKICBwZ3NxbDoKICAgIGltYWdlOiBwb3N0Z3Jlczo5LjUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX0RCPXRlc3QKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQo.NGE3UiNBappXiPimJXv1DzgjT3k2hofGPsCPhw7KsSM

View File

@@ -4,22 +4,27 @@ root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.go]
indent_style = tab
indent_size = 4
indent_size = 8
[*.tmpl]
[*.{tmpl,html}]
indent_style = tab
indent_size = 2
indent_size = 4
[*.{less,yml}]
indent_style = space
indent_size = 2
indent_size = 4
[*.js]
indent_style = space
indent_size = 4
[Makefile]
indent_style = tab
[*.md]
trim_trailing_whitespace = false

11
.gitattributes vendored
View File

@@ -1,11 +0,0 @@
public/conf/gitignore/* linguist-vendored
public/conf/license/* linguist-vendored
public/assets/* linguist-vendored
public/plugins/* linguist-vendored
public/plugins/* linguist-vendored
public/css/themes/* linguist-vendored
public/css/github.min.css linguist-vendored
public/css/semantic-2.2.1.min.css linguist-vendored
public/js/libs/* linguist-vendored
public/js/jquery-1.11.3.min.js linguist-vendored
public/js/semantic-2.2.1.min.js linguist-vendored

View File

@@ -1,63 +0,0 @@
# Contributing to Gogs
> This guidelines sheet is forked from [CONTRIBUTING.md](https://github.com/drone/drone/blob/8d9c7cee56d6c2eac81dc156ce27be6716d97e68/CONTRIBUTING.md).
Gogs is not perfect, and it has bugs or incomplete features in rare cases. You're welcome to tell us, or to contribute some code. This document describes details about how can you contribute to Gogs project.
## Contribution guidelines
Depends on the situation, you will:
- Find a bug and create an issue
- Need more functionality and make a feature request
- Want to contribute code and open a pull request
- Run into issue and need help
### Bug Report
If you find something you consider a bug, please create a issue on [GitHub](https://github.com/gogits/gogs/issues). To avoid wasting time and reduce back-and-forth communication with team members, please include at least the following information in a form comfortable for you:
- Bug Description
- Gogs Version
- Git Version
- System Type
- Error Log
- Other information
Please take a moment to check that an issue on [GitHub](https://github.com/gogits/gogs/issues) doesn't already exist documenting your bug report or improvement proposal. If it does, it never hurts to add a quick "+1" or "I have this problem too". This will help prioritize the most common problems and requests.
#### Bug Report Example
Gogs crashed when creating a repository with a license, using v0.5.13.0207, SQLite3, Git 1.9.0, Ubuntu 12.04.
Error log:
```
2014/09/01 07:21:49 [E] nil pointer
```
### Feature Request
There is no standard form of making a feature request. Just try to describe the feature as clearly as possible, because team members may not have experience with the functionality you're talking about.
### Pull Request
Please read detailed information on [Wiki](https://github.com/gogits/gogs/wiki/Contributing-Code).
### Ask For Help
Before opening an issue, please make sure your problem isn't already addressed on the [Troubleshooting](https://gogs.io/docs/intro/troubleshooting.html) and [FAQs](https://gogs.io/docs/intro/faqs.html) pages.
## Code of conduct
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
Instances of abusive, harassing, or otherwise unacceptable behavior can be reported by emailing u@gogs.io
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)

View File

@@ -1,25 +0,0 @@
The issue will be closed without any reasons if it does not satisfy any of following requirements:
1. Please speak English, we have forum in [Chinese](https://discuss.gogs.io/c/getting-help/getting-help-chinese).
2. Please post questions or config/deploy problems on our forum: https://discuss.gogs.io, here are bugs and feature requests only.
3. Please take a moment to search that an issue doesn't already exist.
4. Please give all relevant information below for bug reports; incomplete details considered invalid report.
**You MUST delete above content including this line before posting; too lazy to take this action considered invalid report.**
- Gogs version (or commit ref):
- Git version:
- Operating system:
- Database (use `[x]`):
- [ ] PostgreSQL
- [ ] MySQL
- [ ] SQLite
- Can you reproduce the bug at https://try.gogs.io:
- [ ] Yes (provide example URL)
- [ ] No
- [ ] Not relevant
- Log gist:
## Description
...

View File

@@ -1,9 +0,0 @@
The pull request will be closed without any reasons if it does not satisfy any of following requirements:
1. Please make sure you are targeting the `develop` branch.
2. Please read contributing guidelines:
https://github.com/gogits/gogs/wiki/Contributing-Code
3. Please describe what your pull request does and which issue you're targeting
4. ... if it is not related to any particular issues, explain why we should not reject your pull request.
**You MUST delete above content including this line before posting; too lazy to take this action considered invalid pull request.**

23
.github/issue_template.md vendored Normal file
View File

@@ -0,0 +1,23 @@
1. Please speak English, this is the language everybody of us can speak and write.
2. Please ask questions or config/deploy problems on our Gitter channel: https://gitter.im/go-gitea/gitea
3. Please take a moment to search that an issue doesn't already exist.
4. Please give all relevant information below for bug reports, incomplete details will be handled as an invalid report.
**You MUST delete the content above including this line before posting, otherwise your pull request will be invalid.**
- Gitea version (or commit ref):
- Git version:
- Operating system:
- Database (use `[x]`):
- [ ] PostgreSQL
- [ ] MySQL
- [ ] SQLite
- Can you reproduce the bug at https://try.gitea.io:
- [ ] Yes (provide example URL)
- [ ] No
- [ ] Not relevant
- Log gist:
## Description
...

7
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,7 @@
Please check the following:
1. Make sure you are targeting the `master` branch, pull requests on release branches are only allowed for bug fixes.
2. Read contributing guidelines: https://github.com/go-gitea/gitea/blob/master/CONTRIBUTING.md
3. Describe what your pull request does and which issue you're targeting (if any)
**You MUST delete the content above including this line before posting, otherwise your pull request will be invalid.**

61
.gitignore vendored
View File

@@ -1,20 +1,45 @@
.DS_Store
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# IntelliJ
.idea
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
coverage.out
/modules/options/bindata.go
/modules/public/bindata.go
/modules/templates/bindata.go
*.db
*.log
log/
custom/
data/
.vendor/
.idea/
*.iml
public/img/avatar/
*.exe
*.exe~
/gogs
profile/
*.pem
output*
gogs.sublime-project
gogs.sublime-workspace
/release
vendor
/gitea
/bin
/dist
/custom
/data
/log
/public/img/avatar

View File

@@ -1,59 +0,0 @@
[target]
path = github.com/gogits/gogs
[deps]
github.com/bradfitz/gomemcache = commit:fb1f79c
github.com/urfave/cli = commit:1efa31f
github.com/go-macaron/binding = commit:9440f33
github.com/go-macaron/cache = commit:5617353
github.com/go-macaron/captcha = commit:8aa5919
github.com/go-macaron/csrf = commit:6a9a7df
github.com/go-macaron/gzip = commit:cad1c65
github.com/go-macaron/i18n = commit:ef57533
github.com/go-macaron/inject = commit:c5ab7bf
github.com/go-macaron/session = commit:66031fc
github.com/go-macaron/toolbox = commit:82b5115
github.com/go-sql-driver/mysql = commit:0b58b37
github.com/go-xorm/core = commit:5bf745d
github.com/go-xorm/xorm = commit:c6c7056
github.com/gogits/chardet = commit:2404f77
github.com/gogits/cron = commit:7f3990a
github.com/gogits/git-module = commit:5e0c133
github.com/gogits/go-gogs-client = commit:c52f7ee
github.com/issue9/identicon = commit:d36b545
github.com/jaytaylor/html2text = commit:52d9b78
github.com/kardianos/minwinsvc = commit:cad6b2b
github.com/klauspost/compress = commit:14eb9c4
github.com/klauspost/cpuid = commit:09cded8
github.com/klauspost/crc32 = commit:19b0b33
github.com/lib/pq = commit:80f8150
github.com/mattn/go-sqlite3 = commit:e118d44
github.com/mcuadros/go-version = commit:d52711f
github.com/microcosm-cc/bluemonday = commit:9dc1992
github.com/msteinert/pam = commit:02ccfbf
github.com/nfnt/resize = commit:891127d
github.com/russross/blackfriday = commit:93622da
github.com/satori/go.uuid = commit:0aa62d5
github.com/sergi/go-diff = commit:ec7fdbb
github.com/strk/go-libravatar = commit:5eed7bf
github.com/shurcooL/sanitized_anchor_name = commit:10ef21a
github.com/Unknwon/cae = commit:7f5e046
github.com/Unknwon/com = commit:28b053d
github.com/Unknwon/i18n = commit:39d6f27
github.com/Unknwon/paginater = commit:7748a72
golang.org/x/crypto = commit:bc89c49
golang.org/x/net = commit:57bfaa8
golang.org/x/sys = commit:a646d33
golang.org/x/text = commit:2910a50
gopkg.in/alexcesaro/quotedprintable.v3 = commit:2caba25
gopkg.in/asn1-ber.v1 = commit:4e86f43
gopkg.in/bufio.v1 = commit:567b2bf
gopkg.in/editorconfig/editorconfig-core-go.v1 = commit:a872f05
gopkg.in/gomail.v2 = commit:81ebce5
gopkg.in/ini.v1 = commit:cf53f92
gopkg.in/ldap.v2 = commit:d0a5ced
gopkg.in/macaron.v1 = commit:7564489
gopkg.in/redis.v2 = commit:e617904
[res]
include = public|scripts|templates

2
.lgtm Normal file
View File

@@ -0,0 +1,2 @@
self_approval_off = false
ignore_maintainers_file = true

View File

@@ -1,2 +0,0 @@
Unknwon <u@gogs.io> <joe2010xtmf@163.com>
Unknwon <u@gogs.io> 无闻 <u@gogs.io>

View File

@@ -1,27 +0,0 @@
targets:
debian-7: &debian
build_dependencies:
- libpam0g-dev
dependencies:
- libpam0g
- git
debian-8:
<<: *debian
ubuntu-14.04:
<<: *debian
ubuntu-12.04:
<<: *debian
centos-6: &el
build_dependencies:
- pam-devel
dependencies:
- pam
- git
centos-7:
<<: *el
before:
- mv packager/Procfile .
- mv packager/.godir .
after:
- mv bin/main gogs
after_install: ./packager/hooks/postinst

View File

@@ -1,30 +0,0 @@
language: go
go:
- 1.4
- 1.5
- 1.6
- 1.7
before_install:
- sudo apt-get update -qq
- sudo apt-get install -y libpam-dev
- go get github.com/msteinert/pam
install:
- go get -t -v ./...
script:
- go build -v -tags "pam"
- go test -v -cover -race ./...
notifications:
email:
- u@gogs.io
slack: gophercn:o5pSanyTeNhnfYc3QnG0X7Wx
webhooks:
urls:
- https://webhooks.gitter.im/e/b590f8e03882f7aedc3e
on_success: change
on_failure: always
on_start: never

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

86
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,86 @@
# Contribution Guidelines
## Introduction
This document explains how to contribute changes to the Gitea project. It assumes you have followed the [installation instructions](https://github.com/go-gitea/docs/tree/master/en-US/installation). Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io).
## Bug reports
Please search the issues on the issue tracker with a variety of keywords to ensure your bug is not already reported.
If unique, [open an issue](https://github.com/go-gitea/gitea/issues/new) and answer the questions so we can understand and reproduce the problematic behavior.
The burden is on you to convince us that it is actually a bug in Gitea. This is easiest to do when you write clear, concise instructions so we can reproduce the behavior (even if it seems obvious). The more detailed and specific you are, the faster we will be able to help you. Check out [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html).
Please be kind, remember that Gitea comes at no cost to you, and you're getting free help.
## Discuss your design
The project welcomes submissions but please let everyone know what you're working on if you want to change or add something to the Gitea repositories.
Before starting to write something new for the Gitea project, please [file an issue](https://github.com/go-gitea/gitea/issues/new). Significant changes must go through the [change proposal process](https://github.com/go-gitea/proposals) before they can be accepted.
This process gives everyone a chance to validate the design, helps prevent duplication of effort, and ensures that the idea fits inside the goals for the project and tools. It also checks that the design is sound before code is written; the code review tool is not the place for high-level discussions.
## 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, 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 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 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 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
The sign-off is a simple line at the end of the explanation for the patch. Your signature certifies that you wrote the patch or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: If you can certify [DCO](DCO), then you just add a line to every git commit message:
```
Signed-off-by: Joe Smith <joe.smith@email.com>
```
Please use your real name, we really dislike pseudonyms or anonymous contributions. We are in the opensource world without secrets. If you set your `user.name` and `user.email` git configs, you can sign your commit automatically with `git commit -s`.
## Maintainers
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 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 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.
```
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>
* [Thomas Boerger](https://github.com/tboerger) <thomas@webhippie.de>
* [Kim Carlbäcker](https://github.com/bkcsoft) <kim.carlbacker@gmail.com>
## Versions
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.
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
Code that you contribute should use the standard copyright header:
```
// 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.
```
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.

36
DCO Normal file
View File

@@ -0,0 +1,36 @@
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.

View File

@@ -1,22 +1,42 @@
FROM alpine:3.3
MAINTAINER jp@roemer.im
FROM alpine:3.4
MAINTAINER Thomas Boerger <thomas@webhippie.de>
# Install system utils & Gogs runtime dependencies
ADD https://github.com/tianon/gosu/releases/download/1.9/gosu-amd64 /usr/sbin/gosu
RUN chmod +x /usr/sbin/gosu \
&& apk --no-cache --no-progress add ca-certificates bash git linux-pam s6 curl openssh socat tzdata
ENV GOGS_CUSTOM /data/gogs
COPY . /app/gogs/
WORKDIR /app/gogs/
RUN ./docker/build.sh
# Configure LibC Name Service
COPY docker/nsswitch.conf /etc/nsswitch.conf
# Configure Docker Container
VOLUME ["/data"]
EXPOSE 22 3000
ENTRYPOINT ["docker/start.sh"]
CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]
RUN apk update && \
apk add \
su-exec \
ca-certificates \
sqlite \
bash \
git \
linux-pam \
s6 \
curl \
openssh \
tzdata && \
rm -rf \
/var/cache/apk/* && \
addgroup \
-S -g 1000 \
git && \
adduser \
-S -H -D \
-h /data/git \
-s /bin/bash \
-u 1000 \
-G git \
git && \
echo "git:$(date +%s | sha256sum | base64 | head -c 32)" | chpasswd
ENV USER git
ENV GITEA_CUSTOM /data/gitea
ENV GODEBUG=netdns=go
VOLUME ["/data"]
ENTRYPOINT ["/usr/bin/entrypoint"]
CMD ["/bin/s6-svscan", "/etc/s6"]
COPY docker /
COPY gitea /app/gitea/gitea

View File

@@ -1,25 +1,44 @@
FROM hypriot/rpi-alpine-scratch:v3.2
MAINTAINER jp@roemer.im, raxetul@gmail.com
FROM hypriot/rpi-alpine-scratch:v3.4
MAINTAINER Thomas Boerger <thomas@webhippie.de>
# Install system utils & Gogs runtime dependencies
ADD https://github.com/tianon/gosu/releases/download/1.9/gosu-armhf /usr/sbin/gosu
RUN chmod +x /usr/sbin/gosu \
&& echo "http://dl-4.alpinelinux.org/alpine/v3.3/main/" | tee /etc/apk/repositories \
&& echo "http://dl-4.alpinelinux.org/alpine/v3.3/community/" | tee -a /etc/apk/repositories \
&& apk -U --no-progress upgrade && rm -f /var/cache/apk/APKINDEX.* \
&& apk --no-cache --no-progress add ca-certificates bash git linux-pam s6 curl openssh socat tzdata
ENV GOGS_CUSTOM /data/gogs
COPY . /app/gogs/
WORKDIR /app/gogs/
RUN ./docker/build.sh
# Configure LibC Name Service
COPY docker/nsswitch.conf /etc/nsswitch.conf
# Configure Docker Container
VOLUME ["/data"]
EXPOSE 22 3000
ENTRYPOINT ["docker/start.sh"]
CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]
RUN apk update && \
apk add \
su-exec \
ca-certificates \
sqlite \
bash \
git \
linux-pam \
s6 \
curl \
openssh \
tzdata && \
rm -rf \
/var/cache/apk/* && \
addgroup \
-S -g 1000 \
git && \
adduser \
-S -H -D \
-h /data/git \
-s /bin/bash \
-u 1000 \
-G git \
git
ENV USER git
ENV GITEA_CUSTOM /data/gitea
ENV GODEBUG=netdns=go
VOLUME ["/data"]
ENTRYPOINT ["/usr/bin/entrypoint"]
CMD ["/bin/s6-svscan", "/etc/s6"]
COPY docker /
COPY public /app/gitea/public
COPY templates /app/gitea/templates
COPY gitea /app/gitea/gitea

View File

@@ -1,4 +1,5 @@
Copyright (c) The Gogs Authors
Copyright (c) 2016 The Gitea Authors
Copyright (c) 2015 The Gogs Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -16,4 +17,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
THE SOFTWARE.

12
MAINTAINERS Normal file
View File

@@ -0,0 +1,12 @@
Alexey Makhov <amakhov@avito.ru> (@makhov)
Andrey Nering <andrey.nering@gmail.com> (@andreynering)
Kees de Vries <bouwko@gmail.com> (@Bwko)
Kim Carlbäcker <kim.carlbacker@gmail.com> (@bkcsoft)
LefsFlare <nobody@nobody.tld> (@LefsFlarey)
Lunny Xiao <xiaolunwen@gmail.com> (@lunny)
Matthias Loibl <mail@matthiasloibl.com> (@metalmatze)
Rachid Zarouali <nobody@nobody.tld> (@xinity)
Rémy Boulanouar <admin@dblk.org> (@DblK)
Sandro Santilli <strk@kbt.io> (@strk)
Thibault Meyer <meyer.thibault@gmail.com> (@0xbaadf00d)
Thomas Boerger <thomas@webhippie.de> (@tboerger)

178
Makefile
View File

@@ -1,74 +1,134 @@
LDFLAGS += -X "github.com/gogits/gogs/modules/setting.BuildTime=$(shell date -u '+%Y-%m-%d %I:%M:%S %Z')"
LDFLAGS += -X "github.com/gogits/gogs/modules/setting.BuildGitHash=$(shell git rev-parse HEAD)"
DIST := dist
EXECUTABLE := gitea
IMPORT := code.gitea.io/gitea
DATA_FILES := $(shell find conf | sed 's/ /\\ /g')
LESS_FILES := $(wildcard public/less/gogs.less public/less/_*.less)
GENERATED := modules/bindata/bindata.go public/css/gogs.css
BINDATA := modules/{options,public,templates}/bindata.go
STYLESHEETS := $(wildcard public/less/index.less public/less/_*.less)
JAVASCRIPTS :=
TAGS = ""
BUILD_FLAGS = "-v"
LDFLAGS += -X "main.Version=$(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')"
RELEASE_ROOT = "release"
RELEASE_GOGS = "release/gogs"
NOW = $(shell date -u '+%Y%m%d%I%M%S')
GOVET = go tool vet -composites=false -methods=false -structtags=false
TARGETS ?= linux/*,darwin/*,windows/*
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
SOURCES ?= $(shell find . -name "*.go" -type f)
.PHONY: build pack release bindata clean
TAGS ?=
.IGNORE: public/css/gogs.css
ifneq ($(DRONE_TAG),)
VERSION ?= $(subst v,,$(DRONE_TAG))
else
ifneq ($(DRONE_BRANCH),)
VERSION ?= $(subst release/v,,$(DRONE_BRANCH))
else
VERSION ?= master
endif
endif
.PHONY: all
all: build
check: test
dist: release
govet:
$(GOVET) gogs.go
$(GOVET) models modules routers
build: $(GENERATED)
go install $(BUILD_FLAGS) -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
cp '$(GOPATH)/bin/gogs' .
build-dev: $(GENERATED) govet
go install $(BUILD_FLAGS) -tags '$(TAGS)'
cp '$(GOPATH)/bin/gogs' .
build-dev-race: $(GENERATED) govet
go install $(BUILD_FLAGS) -race -tags '$(TAGS)'
cp '$(GOPATH)/bin/gogs' .
pack:
rm -rf $(RELEASE_GOGS)
mkdir -p $(RELEASE_GOGS)
cp -r gogs LICENSE README.md README_ZH.md templates public scripts $(RELEASE_GOGS)
rm -rf $(RELEASE_GOGS)/public/config.codekit $(RELEASE_GOGS)/public/less
cd $(RELEASE_ROOT) && zip -r gogs.$(NOW).zip "gogs"
release: build pack
bindata: modules/bindata/bindata.go
modules/bindata/bindata.go: $(DATA_FILES)
go-bindata -o=$@ -ignore="\\.DS_Store|README.md|TRANSLATORS" -pkg=bindata conf/...
less: public/css/gogs.css
public/css/gogs.css: $(LESS_FILES)
lessc $< $@
.PHONY: clean
clean:
go clean -i ./...
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA)
clean-mac: clean
find . -name ".DS_Store" -print0 | xargs -0 rm
.PHONY: fmt
fmt:
go fmt $(PACKAGES)
.PHONY: vet
vet:
go vet $(PACKAGES)
.PHONY: generate
generate:
@which go-bindata > /dev/null; if [ $$? -ne 0 ]; then \
go get -u github.com/jteeuwen/go-bindata/...; \
fi
go generate $(PACKAGES)
.PHONY: errcheck
errcheck:
@which errcheck > /dev/null; if [ $$? -ne 0 ]; then \
go get -u github.com/kisielk/errcheck; \
fi
errcheck $(PACKAGES)
.PHONY: lint
lint:
@which golint > /dev/null; if [ $$? -ne 0 ]; then \
go get -u github.com/golang/lint/golint; \
fi
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
.PHONY: test
test:
go test -cover -race ./...
for PKG in $(PACKAGES); do go test -cover -coverprofile $$GOPATH/src/$$PKG/coverage.out $$PKG || exit 1; done;
fixme:
grep -rnw "FIXME" routers models modules
.PHONY: test-mysql
test-mysql:
@echo "Not integrated yet!"
todo:
grep -rnw "TODO" routers models modules
.PHONY: test-pgsql
test-pgsql:
@echo "Not integrated yet!"
.PHONY: check
check: test
.PHONY: install
install: $(wildcard *.go)
go install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)'
.PHONY: build
build: $(EXECUTABLE)
$(EXECUTABLE): $(SOURCES)
go build -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
.PHONY: docker
docker:
docker run -ti --rm -v $(CURDIR):/srv/app/src/code.gitea.io/gitea -w /srv/app/src/code.gitea.io/gitea -e TAGS="$(TAGS)" webhippie/golang:edge make clean generate build
docker build -t gitea/gitea:latest .
.PHONY: release
release: release-dirs release-build release-copy release-check
.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 $(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:
$(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: javascripts
javascripts: public/js/index.js
.IGNORE: public/js/index.js
public/js/index.js: $(JAVASCRIPTS)
cat $< >| $@
.PHONY: stylesheets
stylesheets: public/css/index.css
.IGNORE: public/css/index.css
public/css/index.css: $(STYLESHEETS)
lessc $< $@
.PHONY: assets
assets: javascripts stylesheets

148
README.md
View File

@@ -1,138 +1,46 @@
Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/gogs/localized.svg)](https://crowdin.com/project/gogs) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gogits/gogs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
=====================
[简体中文](https://github.com/go-gitea/gitea/blob/master/README_ZH.md)
![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true)
# Gitea - Git with a cup of tea
##### Current tip version: 0.9.99 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions or submit a task on [alpha stage automated binary building system](https://build.gogs.io/))
[![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)
| 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 [Contributing Code](https://github.com/gogits/gogs/wiki/Contributing-Code) BEFORE STARTING TO WORK ON A PULL REQUEST**.
2. Due to testing purpose, data of [try.gogs.io](https://try.gogs.io) was reset in **Jan 28, 2015** and will reset multiple times after. Please do **NOT** put your important data on the site.
3. The demo site [try.gogs.io](https://try.gogs.io) is running under `develop` branch.
4. If you think there are vulnerabilities in the project, please talk privately to **u@gogs.io**. Thanks!
5. If you're interested in using APIs, we have experimental support with [documentation](https://github.com/gogits/go-gogs-client/wiki).
6. If your team/company is using Gogs and would like to put your logo on [our website](https://gogs.io), contact us by any means.
[简体中文](README_ZH.md)
|![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/)!
## Overview
## Notes
- Please see the [Documentation](https://gogs.io/docs/intro) for common usages and change log.
- See the [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team.
- Want to try it before doing anything else? Do it [online](https://try.gogs.io/gogs/gogs)!
- Having trouble? Get help with [Troubleshooting](https://gogs.io/docs/intro/troubleshooting.html) or [User Forum](https://discuss.gogs.io/).
- Want to help with localization? Check out the [guide](https://gogs.io/docs/features/i18n.html)!
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).
## Features
## Docs
- 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 ([19 languages](https://crowdin.com/project/gogs))
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.
## System Requirements
## Contributing
- A cheap Raspberry Pi is powerful enough for basic functionality.
- 2 CPU cores and 1GB RAM would be the baseline for teamwork.
Fork -> Patch -> Push -> Pull Request
## Browser Support
## Authors
- 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
Make sure you install the [prerequisites](https://gogs.io/docs/installation) first.
There are 5 ways to install Gogs:
- [Install from binary](https://gogs.io/docs/installation/install_from_binary.html)
- [Install from source](https://gogs.io/docs/installation/install_from_source.html)
- [Install from packages](https://gogs.io/docs/installation/install_from_packages.html)
- [Ship with Docker](https://github.com/gogits/gogs/tree/master/docker)
- [Install with Vagrant](https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs)
### 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.
## Contributors
- Ex-team members [@lunny](https://github.com/lunny), [@fuxiaohei](https://github.com/fuxiaohei) and [@slene](https://github.com/slene).
- See [contributors page](https://github.com/gogits/gogs/graphs/contributors) for full list of contributors.
- See [TRANSLATORS](conf/locale/TRANSLATORS) for public list of translators.
* [Maintainers](https://github.com/orgs/go-gitea/people)
* [Contributors](https://github.com/go-gitea/gitea/graphs/contributors)
* [Translators](options/locale/TRANSLATORS)
## License
This project is under the MIT License. See the [LICENSE](https://github.com/gogits/gogs/blob/master/LICENSE) file for the full license text.
This project is under the MIT License. See the [LICENSE](https://github.com/go-gitea/gitea/blob/master/LICENSE) file for the full license text.

View File

@@ -1,107 +1,48 @@
Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs)
=====================
[English](https://github.com/go-gitea/gitea/blob/master/README.md)
Gogs (Go Git Service) 是一款极易搭建的自助 Git 服务。
# 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)
Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自助 Git 服务。使用 Go 语言开发使得 Gogs 能够通过独立的二进制分发,并且支持 Go 语言支持的 **所有平台**,包括 Linux、Mac OS X、Windows 以及 ARM 平台。
||||
|:-------------:|:-------:|:-------:|
|![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)|
||||
## 项目概览
## 目标
- 有关基本用法和变更日志,请通过 [使用手册](https://gogs.io/docs/intro/) 查看
- 您可以到 [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) 跟随开发团队的脚步。
- 想要先睹为快?直接去 [在线体验](https://try.gogs.io/gogs/gogs) 。
- 使用过程中遇到问题?尝试从 [故障排查](https://gogs.io/docs/intro/troubleshooting.html) 页面或 [用户论坛](https://discuss.gogs.io/) 获取帮助。
- 希望帮助多国语言界面的翻译吗?请立即访问 [详情页面](https://gogs.io/docs/features/i18n.html)
Gitea的首要目标是创建一个极易安装运行非常快速安装和使用体验良好的自建 Git 服务。我们采用Go作为后端语言这使我们只要生成一个可执行程序即可。并且他还支持跨平台支持 Linux, macOS 和 Windows 以及各种架构除了x86amd64还包括 ARM 和 PowerPC
## 功能特性
如果您想试用一下,请访问 [在线Demo](https://try.gitea.io/)
- 支持活动时间线
- 支持 SSH 以及 HTTP/HTTPS 协议
- 支持 SMTP、LDAP 和反向代理的用户认证
- 支持反向代理子路径
- 支持用户、组织和仓库管理系统
- 支持添加和删除仓库协作者
- 支持仓库和组织级别 Web 钩子(包括 Slack 集成)
- 支持仓库 Git 钩子和部署密钥
- 支持仓库工单Issue、合并请求Pull Request以及 Wiki
- 支持迁移和镜像仓库以及它的 Wiki
- 支持在线编辑仓库文件和 Wiki
- 支持自定义源的 Gravatar 和 Federated Avatar
- 支持邮件服务
- 支持后台管理面板
- 支持 MySQL、PostgreSQL、SQLite3 和 [TiDB](https://github.com/pingcap/tidb)(实验性支持) 数据库
- 支持多语言本地化([19 种语言]([more](https://crowdin.com/project/gogs))
## 提示
## 系统要求
1. **开始贡献代码之前请确保你已经看过了 [贡献者向导(英文)](CONTRIBUTING.md)**.
2. 所有的安全问题,请私下发送邮件给 **security@gitea.io**。谢谢!
3. 如果你要使用API请参见 [API 文档](https://godoc.org/code.gitea.io/sdk/gitea).
- 最低的系统硬件要求为一个廉价的树莓派
- 如果用于团队项目,建议使用 2 核 CPU 及 1GB 内存
## 文档
## 浏览器支持
关于如何安装请访问我们的 [文档站](https://docs.gitea.io/zh-cn/),如果没有找到对应的文档,你也可以通过 [Gitter - 英文](https://gitter.im/go-gitea/gitea) 和 QQ群 328432459 来和我们交流。
- 请根据 [Semantic UI](https://github.com/Semantic-Org/Semantic-UI#browser-support) 查看具体支持的浏览器版本。
- 官方支持的最小 UI 尺寸为 **1024*768**UI 不一定会在更小尺寸的设备上被破坏,但我们无法保证且不会修复。
## 贡献流程
## 安装部署
Fork -> Patch -> Push -> Pull Request
在安装 Gogs 之前,您需要先安装 [基本环境](https://gogs.io/docs/installation)。
## 作者
然后,您可以通过以下 5 种方式来安装 Gogs
- [二进制安装](https://gogs.io/docs/installation/install_from_binary.html)
- [源码安装](https://gogs.io/docs/installation/install_from_source.html)
- [包管理安装](https://gogs.io/docs/installation/install_from_packages.html)
- [采用 Docker 部署](https://github.com/gogits/gogs/tree/master/docker)
- [通过 Vagrant 安装](https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs)
### 使用教程
- [使用 Gogs 搭建自己的 Git 服务器](https://mynook.info/blog/post/host-your-own-git-server-using-gogs)
- [阿里云上 Ubuntu 14.04 64 位安装 Gogs](http://my.oschina.net/luyao/blog/375654)
### 云端部署
- [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)
## 软件及服务支持
- [Drone](https://github.com/drone/drone)CI
- [Fabric8](http://fabric8.io/)DevOps
- [Taiga](https://taiga.io/)(项目管理)
- [Puppet](https://forge.puppetlabs.com/Siteminds/gogs)IT
- [Kanboard](http://kanboard.net/plugin/gogs-webhook)(项目管理)
- [BearyChat](https://bearychat.com/)(团队交流)
- [HiWork](http://www.hiwork.cc/)(团队交流)
### 产品支持
- [Synology](https://www.synology.com)Docker
- [One Space](http://www.onespace.cc)(应用商店)
## 特别鸣谢
- 基于 [Macaron](https://github.com/go-macaron/macaron) 的路由与中间件机制。
- 基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改的系统监视状态。
- 感谢 [Rocker](http://weibo.com/rocker1989) 设计的 Logo。
- 感谢 [Crowdin](https://crowdin.com/project/gogs) 提供免费的开源项目本地化支持。
- 感谢 [DigitalOcean](https://www.digitalocean.com) 提供主站和体验站点的服务器赞助。
- 感谢 [KeyCDN](https://www.keycdn.com/) 和 [七牛云存储](http://www.qiniu.com/) 提供 CDN 服务赞助。
## 贡献成员
- 前团队成员 [@lunny](https://github.com/lunny)、[@fuxiaohei](https://github.com/fuxiaohei) 和 [@slene](https://github.com/slene)。
- 您可以通过查看 [贡献者页面](https://github.com/gogits/gogs/graphs/contributors) 获取完整的贡献者列表。
- 您可以通过查看 [TRANSLATORS](conf/locale/TRANSLATORS) 文件获取公开的翻译人员列表。
* [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/gogits/gogs/blob/master/LICENSE) 文件中。
本项目采用 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.
@@ -9,15 +10,16 @@ import (
"github.com/urfave/cli"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/setting"
)
var (
// CmdAdmin represents the available admin sub-command.
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,
@@ -29,11 +31,30 @@ to make automatic initialization process more smoothly`,
Usage: "Create a new user in database",
Action: runCreateUser,
Flags: []cli.Flag{
stringFlag("name", "", "Username"),
stringFlag("password", "", "User password"),
stringFlag("email", "", "User email address"),
boolFlag("admin", "User is an admin"),
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
cli.StringFlag{
Name: "name",
Value: "",
Usage: "Username",
},
cli.StringFlag{
Name: "password",
Value: "",
Usage: "User password",
},
cli.StringFlag{
Name: "email",
Value: "",
Usage: "User email address",
},
cli.BoolFlag{
Name: "admin",
Usage: "User is an admin",
},
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
)
@@ -53,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.
@@ -25,19 +24,43 @@ import (
"github.com/urfave/cli"
)
// CmdCert represents the available cert sub-command.
var CmdCert = cli.Command{
Name: "cert",
Usage: "Generate self-signed certificate",
Description: `Generate a self-signed X.509 certificate for a TLS server.
Description: `Generate a self-signed X.509 certificate for a TLS server.
Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
Action: runCert,
Flags: []cli.Flag{
stringFlag("host", "", "Comma-separated hostnames and IPs to generate a certificate for"),
stringFlag("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521"),
intFlag("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set"),
stringFlag("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011"),
durationFlag("duration", 365*24*time.Hour, "Duration that certificate is valid for"),
boolFlag("ca", "whether this cert should be its own Certificate Authority"),
cli.StringFlag{
Name: "host",
Value: "",
Usage: "Comma-separated hostnames and IPs to generate a certificate for",
},
cli.StringFlag{
Name: "ecdsa-curve",
Value: "",
Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521",
},
cli.IntFlag{
Name: "rsa-bits",
Value: 2048,
Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set",
},
cli.StringFlag{
Name: "start-date",
Value: "",
Usage: "Creation date formatted as Jan 1 15:04:05 2011",
},
cli.DurationFlag{
Name: "duration",
Value: 365 * 24 * time.Hour,
Usage: "Duration that certificate is valid for",
},
cli.BoolFlag{
Name: "ca",
Usage: "whether this cert should be its own Certificate Authority",
},
},
}
@@ -114,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,28 +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"
)
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(ctx *cli.Context) error {
fmt.Println("Command cert not available, please use build tags 'cert' to rebuild.")
os.Exit(1)
return nil
}

View File

@@ -1,42 +0,0 @@
// 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 cmd
import (
"time"
"github.com/urfave/cli"
)
func stringFlag(name, value, usage string) cli.StringFlag {
return cli.StringFlag{
Name: name,
Value: value,
Usage: usage,
}
}
func boolFlag(name, usage string) cli.BoolFlag {
return cli.BoolFlag{
Name: name,
Usage: usage,
}
}
func intFlag(name string, value int, usage string) cli.IntFlag {
return cli.IntFlag{
Name: name,
Value: value,
Usage: usage,
}
}
func durationFlag(name string, value time.Duration, usage string) cli.DurationFlag {
return cli.DurationFlag{
Name: name,
Value: value,
Usage: usage,
}
}

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.
@@ -6,30 +7,41 @@ package cmd
import (
"fmt"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"time"
"io/ioutil"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/cae/zip"
"github.com/urfave/cli"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/setting"
)
// 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{
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
boolFlag("verbose, v", "Show process details"),
stringFlag("tempdir, t", os.TempDir(), "Temporary dir path"),
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
cli.BoolFlag{
Name: "verbose, v",
Usage: "Show process details",
},
cli.StringFlag{
Name: "tempdir, t",
Value: os.TempDir(),
Usage: "Temporary dir path",
},
},
}
@@ -38,6 +50,7 @@ func runDump(ctx *cli.Context) error {
setting.CustomConf = ctx.String("config")
}
setting.NewContext()
setting.NewServices() // cannot access session settings otherwise
models.LoadConfigs()
models.SetEngine()
@@ -45,14 +58,14 @@ func runDump(ctx *cli.Context) error {
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
log.Fatalf("Path does not exist: %s", tmpDir)
}
TmpWorkDir, err := ioutil.TempDir(tmpDir, "gogs-dump-")
TmpWorkDir, err := ioutil.TempDir(tmpDir, "gitea-dump-")
if err != nil {
log.Fatalf("Fail to create tmp work directory: %v", err)
}
log.Printf("Creating tmp work dir: %s", TmpWorkDir)
reposDump := path.Join(TmpWorkDir, "gogs-repo.zip")
dbDump := path.Join(TmpWorkDir, "gogs-db.sql")
reposDump := path.Join(TmpWorkDir, "gitea-repo.zip")
dbDump := path.Join(TmpWorkDir, "gitea-db.sql")
log.Printf("Dumping local repositories...%s", setting.RepoRootPath)
zip.Verbose = ctx.Bool("verbose")
@@ -65,19 +78,18 @@ func runDump(ctx *cli.Context) error {
log.Fatalf("Fail to dump database: %v", err)
}
fileName := fmt.Sprintf("gogs-dump-%d.zip", time.Now().Unix())
fileName := fmt.Sprintf("gitea-dump-%d.zip", time.Now().Unix())
log.Printf("Packing dump files...")
z, err := zip.Create(fileName)
if err != nil {
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() {
@@ -87,12 +99,26 @@ func runDump(ctx *cli.Context) error {
} else {
log.Printf("Custom dir %s doesn't exist, skipped", setting.CustomPath)
}
log.Printf("Packing data directory...%s", setting.AppDataPath)
var sessionAbsPath string
if setting.SessionConfig.Provider == "file" {
if len(setting.SessionConfig.ProviderConfig) == 0 {
setting.SessionConfig.ProviderConfig = "data/sessions"
}
sessionAbsPath, _ = filepath.Abs(setting.SessionConfig.ProviderConfig)
}
if err := zipAddDirectoryExclude(z, "data", setting.AppDataPath, sessionAbsPath); err != nil {
log.Fatalf("Fail to include data directory: %v", err)
}
if err := z.AddDir("log", setting.LogRootPath); err != nil {
log.Fatalf("Fail to include log: %v", err)
}
// 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)
}
@@ -101,8 +127,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.
@@ -13,29 +14,33 @@ import (
"strings"
"time"
"code.gitea.io/git"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/com"
git "github.com/gogits/git-module"
gouuid "github.com/satori/go.uuid"
"github.com/urfave/cli"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/httplib"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
const (
_ACCESS_DENIED_MESSAGE = "Repository does not exist or you do not have access"
accessDenied = "Repository does not exist or you do not have access"
)
// CmdServ represents the available serv sub-command.
var CmdServ = cli.Command{
Name: "serv",
Usage: "This command should only be called by SSH shell",
Description: `Serv provide access auth for repositories`,
Action: runServ,
Flags: []cli.Flag{
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
@@ -47,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()
@@ -63,14 +70,14 @@ func parseCmd(cmd string) (string, string) {
var (
allowedCommands = map[string]models.AccessMode{
"git-upload-pack": models.ACCESS_MODE_READ,
"git-upload-archive": models.ACCESS_MODE_READ,
"git-receive-pack": models.ACCESS_MODE_WRITE,
"git-upload-pack": models.AccessModeRead,
"git-upload-archive": models.AccessModeRead,
"git-receive-pack": models.AccessModeWrite,
}
)
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 {
@@ -114,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{
@@ -138,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
}
@@ -148,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
}
@@ -179,7 +186,7 @@ func runServ(c *cli.Context) error {
repo, err := models.GetRepositoryByName(repoUser.ID, reponame)
if err != nil {
if models.IsErrRepoNotExist(err) {
fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", repoUser.Name, reponame)
fail(accessDenied, "Repository does not exist: %s/%s", repoUser.Name, reponame)
}
fail("Internal error", "Failed to get repository: %v", err)
}
@@ -190,7 +197,7 @@ func runServ(c *cli.Context) error {
}
// Prohibit push to mirror repositories.
if requestedMode > models.ACCESS_MODE_READ && repo.IsMirror {
if requestedMode > models.AccessModeRead && repo.IsMirror {
fail("mirror repository is read-only", "")
}
@@ -199,7 +206,7 @@ func runServ(c *cli.Context) error {
keyID int64
user *models.User
)
if requestedMode == models.ACCESS_MODE_WRITE || repo.IsPrivate {
if requestedMode == models.AccessModeWrite || repo.IsPrivate {
keys := strings.Split(c.Args()[0], "-")
if len(keys) != 2 {
fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
@@ -212,7 +219,7 @@ func runServ(c *cli.Context) error {
keyID = key.ID
// Check deploy key or user key.
if key.Type == models.KEY_TYPE_DEPLOY {
if key.Type == models.KeyTypeDeploy {
if key.Mode < requestedMode {
fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
}
@@ -241,18 +248,22 @@ func runServ(c *cli.Context) error {
if err != nil {
fail("Internal error", "Fail to check access: %v", err)
} else if mode < requestedMode {
clientMessage := _ACCESS_DENIED_MESSAGE
if mode >= models.ACCESS_MODE_READ {
clientMessage := accessDenied
if mode >= models.AccessModeRead {
clientMessage = "You do not have sufficient authorization for this action"
}
fail(clientMessage,
"User %s does not have level %v access to repository %s",
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.
@@ -275,7 +286,7 @@ func runServ(c *cli.Context) error {
fail("Internal error", "Failed to execute git command: %v", err)
}
if requestedMode == models.ACCESS_MODE_WRITE {
if requestedMode == models.AccessModeWrite {
handleUpdateTask(uuid, user, repoUser, reponame, isWiki)
}

View File

@@ -9,18 +9,23 @@ import (
"github.com/urfave/cli"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
// CmdUpdate represents the available update sub-command.
var CmdUpdate = cli.Command{
Name: "update",
Usage: "This command should only be called by Git hook",
Description: `Update get pushed info and insert into database`,
Action: runUpdate,
Flags: []cli.Flag{
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
@@ -44,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,6 +14,21 @@ import (
"path"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"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/templates"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/admin"
apiv1 "code.gitea.io/gitea/routers/api/v1"
"code.gitea.io/gitea/routers/dev"
"code.gitea.io/gitea/routers/org"
"code.gitea.io/gitea/routers/repo"
"code.gitea.io/gitea/routers/user"
"github.com/go-macaron/binding"
"github.com/go-macaron/cache"
"github.com/go-macaron/captcha"
@@ -23,89 +37,38 @@ import (
"github.com/go-macaron/i18n"
"github.com/go-macaron/session"
"github.com/go-macaron/toolbox"
"github.com/go-xorm/xorm"
"github.com/mcuadros/go-version"
"github.com/urfave/cli"
"gopkg.in/ini.v1"
"gopkg.in/macaron.v1"
"github.com/gogits/git-module"
"github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/bindata"
"github.com/gogits/gogs/modules/context"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/template"
"github.com/gogits/gogs/routers"
"github.com/gogits/gogs/routers/admin"
apiv1 "github.com/gogits/gogs/routers/api/v1"
"github.com/gogits/gogs/routers/dev"
"github.com/gogits/gogs/routers/org"
"github.com/gogits/gogs/routers/repo"
"github.com/gogits/gogs/routers/user"
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{
stringFlag("port, p", "3000", "Temporary port number to prevent conflict"),
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
cli.StringFlag{
Name: "port, p",
Value: "3000",
Usage: "Temporary port number to prevent conflict",
},
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
// VerChecker is a listing of required dependency versions.
type VerChecker struct {
ImportPath string
Version func() string
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"},
{"github.com/gogits/git-module", git.Version, "0.4.1"},
{"github.com/gogits/go-gogs-client", gogs.Version, "0.12.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()
@@ -117,11 +80,11 @@ func newMacaron() *macaron.Macaron {
m.Use(gzip.Gziper())
}
if setting.Protocol == setting.FCGI {
m.SetURLPrefix(setting.AppSubUrl)
m.SetURLPrefix(setting.AppSubURL)
}
m.Use(macaron.Static(
path.Join(setting.StaticRootPath, "public"),
macaron.StaticOptions{
m.Use(public.Static(
&public.Options{
Directory: path.Join(setting.StaticRootPath, "public"),
SkipLogging: setting.DisableRouterLog,
},
))
@@ -133,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,
@@ -166,7 +129,7 @@ func newMacaron() *macaron.Macaron {
Interval: setting.CacheInterval,
}))
m.Use(captcha.Captchaer(captcha.Options{
SubURL: setting.AppSubUrl,
SubURL: setting.AppSubURL,
}))
m.Use(session.Sessioner(setting.SessionConfig))
m.Use(csrf.Csrfer(csrf.Options{
@@ -174,11 +137,11 @@ func newMacaron() *macaron.Macaron {
Cookie: setting.CSRFCookieName,
SetCookie: true,
Header: "X-Csrf-Token",
CookiePath: setting.AppSubUrl,
CookiePath: setting.AppSubURL,
}))
m.Use(toolbox.Toolboxer(m, toolbox.Options{
HealthCheckFuncs: []*toolbox.HealthCheckFuncDesc{
&toolbox.HealthCheckFuncDesc{
{
Desc: "Database connection",
Func: models.Ping,
},
@@ -193,7 +156,6 @@ func runWeb(ctx *cli.Context) error {
setting.CustomConf = ctx.String("config")
}
routers.GlobalInit()
checkVersion()
m := newMacaron()
@@ -210,7 +172,7 @@ func runWeb(ctx *cli.Context) error {
m.Get("/", ignSignIn, routers.Home)
m.Group("/explore", func() {
m.Get("", func(ctx *context.Context) {
ctx.Redirect(setting.AppSubUrl + "/explore/repos")
ctx.Redirect(setting.AppSubURL + "/explore/repos")
})
m.Get("/repos", routers.ExploreRepos)
m.Get("/users", routers.ExploreUsers)
@@ -274,7 +236,7 @@ func runWeb(ctx *cli.Context) error {
m.Group("/users", func() {
m.Get("", admin.Users)
m.Combo("/new").Get(admin.NewUser).Post(bindIgnErr(auth.AdminCrateUserForm{}), admin.NewUserPost)
m.Combo("/new").Get(admin.NewUser).Post(bindIgnErr(auth.AdminCreateUserForm{}), admin.NewUserPost)
m.Combo("/:userid").Get(admin.EditUser).Post(bindIgnErr(auth.AdminEditUserForm{}), admin.EditUserPost)
m.Post("/:userid/delete", admin.DeleteUser)
})
@@ -330,11 +292,7 @@ func runWeb(ctx *cli.Context) error {
}
defer fr.Close()
ctx.Header().Set("Cache-Control", "public,max-age=86400")
ctx.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, attach.Name))
// Fix #312. Attachments with , in their name are not handled correctly by Google Chrome.
// We must put the name in " manually.
if err = repo.ServeData(ctx, "\""+attach.Name+"\"", fr); err != nil {
if err = repo.ServeData(ctx, attach.Name, fr); err != nil {
ctx.Handle(500, "ServeData", err)
return
}
@@ -518,7 +476,8 @@ func runWeb(ctx *cli.Context) error {
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
})
m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest).
m.Combo("/compare/*", repo.MustAllowPulls, repo.SetEditorconfigIfExists).
Get(repo.CompareAndPullRequest).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
m.Group("", func() {
@@ -577,20 +536,20 @@ func runWeb(ctx *cli.Context) error {
m.Group("/pulls/:index", func() {
m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
m.Get("/files", context.RepoRef(), repo.ViewPullFiles)
m.Get("/files", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ViewPullFiles)
m.Post("/merge", reqRepoWriter, repo.MergePullRequest)
}, repo.MustAllowPulls)
m.Group("", func() {
m.Get("/src/*", repo.Home)
m.Get("/src/*", repo.SetEditorconfigIfExists, repo.Home)
m.Get("/raw/*", repo.SingleDownload)
m.Get("/commits/*", repo.RefCommits)
m.Get("/commit/:sha([a-z0-9]{7,40})$", repo.Diff)
m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.Diff)
m.Get("/forks", repo.Forks)
}, context.RepoRef())
m.Get("/commit/:sha([a-z0-9]{7,40})\\.:ext(patch|diff)", repo.RawDiff)
m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.RawDiff)
m.Get("/compare/:before([a-z0-9]{7,40})\\.\\.\\.:after([a-z0-9]{7,40})", repo.CompareDiff)
m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.CompareDiff)
}, ignSignIn, context.RepoAssignment(), repo.MustBeNotBare)
m.Group("/:username/:reponame", func() {
m.Get("/stars", repo.Stars)
@@ -599,8 +558,8 @@ func runWeb(ctx *cli.Context) error {
m.Group("/:username", func() {
m.Group("/:reponame", func() {
m.Get("", repo.Home)
m.Get("\\.git$", repo.Home)
m.Get("", repo.SetEditorconfigIfExists, repo.Home)
m.Get("\\.git$", repo.SetEditorconfigIfExists, repo.Home)
}, ignSignIn, context.RepoAssignment(true), context.RepoRef())
m.Group("/:reponame", func() {
@@ -628,17 +587,17 @@ func runWeb(ctx *cli.Context) error {
// Flag for port number in case first time run conflict.
if ctx.IsSet("port") {
setting.AppUrl = strings.Replace(setting.AppUrl, setting.HTTPPort, ctx.String("port"), 1)
setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, ctx.String("port"), 1)
setting.HTTPPort = ctx.String("port")
}
var listenAddr string
if setting.Protocol == setting.UNIX_SOCKET {
if setting.Protocol == setting.UnixSocket {
listenAddr = fmt.Sprintf("%s", setting.HTTPAddr)
} else {
listenAddr = fmt.Sprintf("%s:%s", setting.HTTPAddr, setting.HTTPPort)
}
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubUrl)
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL)
var err error
switch setting.Protocol {
@@ -649,11 +608,12 @@ func runWeb(ctx *cli.Context) error {
err = server.ListenAndServeTLS(setting.CertFile, setting.KeyFile)
case setting.FCGI:
err = fcgi.Serve(nil, m)
case setting.UNIX_SOCKET:
os.Remove(listenAddr)
case setting.UnixSocket:
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{listenAddr, "unix"})
listener, err = net.ListenUnix("unix", &net.UnixAddr{Name: listenAddr, Net: "unix"})
if err != nil {
break // Handle error after switch
}

View File

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

View File

@@ -1,8 +1,5 @@
# NEVER EVER MODIFY THIS FILE
# PLEASE MAKE CHANGES ON CORRESPONDING CUSTOM CONFIG FILE
; App name that shows on every page title
APP_NAME = Gogs: Go Git Service
APP_NAME = Gitea: Git with a cup of tea
; Change it if you run locally
RUN_USER = git
; Either "dev", "prod" or "test", default is "dev"
@@ -24,6 +21,8 @@ PULL_REQUEST_QUEUE_LENGTH = 1000
; Preferred Licenses to place at the top of the List
; Name must match file name in conf/license or custom/conf/license
PREFERRED_LICENSES = Apache License 2.0,MIT License
; Disable ability to interact with repositories by HTTP protocol
DISABLE_HTTP_GIT = false
[repository.editor]
; List of file extensions that should have line wraps in the CodeMirror editor
@@ -36,7 +35,7 @@ PREVIEWABLE_FILE_MODES = markdown
[repository.upload]
; Whether repository file uploads are enabled. Defaults to `true`
ENABLED = true
; Path for uploads. Defaults to `data/tmp/uploads` (tmp gets deleted on gogs restart)
; Path for uploads. Defaults to `data/tmp/uploads` (tmp gets deleted on gitea restart)
TEMP_PATH = data/tmp/uploads
; One or more allowed types, e.g. image/jpeg|image/png. Nothing means any file type
ALLOWED_TYPES =
@@ -55,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
@@ -91,7 +90,7 @@ HTTP_ADDR = 0.0.0.0
HTTP_PORT = 3000
; Permission for unix socket
UNIX_SOCKET_PERMISSION = 666
; Local (DMZ) URL for Gogs workers (such as SSH update) accessing web service.
; Local (DMZ) URL for Gitea workers (such as SSH update) accessing web service.
; In most cases you do not need to change the default value.
; Alter it only if your SSH server node is not the same as HTTP node.
LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/
@@ -101,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
@@ -118,7 +119,7 @@ MINIMUM_KEY_SIZE_CHECK = false
OFFLINE_MODE = false
DISABLE_ROUTER_LOG = false
; Generate steps:
; $ ./gogs cert -ca=true -duration=8760h0m0s -host=myhost.example.com
; $ ./gitea cert -ca=true -duration=8760h0m0s -host=myhost.example.com
;
; Or from a .pfx file exported from the Windows certificate store (do
; not forget to export the private key):
@@ -127,7 +128,7 @@ DISABLE_ROUTER_LOG = false
CERT_FILE = custom/https/cert.pem
KEY_FILE = custom/https/key.pem
; Upper level of template and static file path
; default is the path where Gogs is executed
; default is the path where Gitea is executed
STATIC_ROOT_PATH =
; Default path for App data
APP_DATA_PATH = data
@@ -147,13 +148,13 @@ DSA = 1024
; Either "mysql", "postgres" or "sqlite3", it's your choice
DB_TYPE = mysql
HOST = 127.0.0.1:3306
NAME = gogs
NAME = gitea
USER = root
PASSWD =
; For "postgres" only, either "disable", "require" or "verify-full"
SSL_MODE = disable
; For "sqlite3" and "tidb", use absolute path when you start as service
PATH = data/gogs.db
PATH = data/gitea.db
[admin]
@@ -163,8 +164,8 @@ INSTALL_LOCK = false
SECRET_KEY = !#@FDEWREWR&*(
; Auto-login remember days
LOGIN_REMEMBER_DAYS = 7
COOKIE_USERNAME = gogs_awesome
COOKIE_REMEMBER_NAME = gogs_incredible
COOKIE_USERNAME = gitea_awesome
COOKIE_REMEMBER_NAME = gitea_incredible
; Reverse proxy authentication header name of user name
REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
@@ -179,7 +180,7 @@ DISABLE_REGISTRATION = false
REQUIRE_SIGNIN_VIEW = false
; Mail notification
ENABLE_NOTIFY_MAIL = false
; More detail: https://github.com/gogits/gogs/issues/165
; More detail: https://github.com/go-gitea/gitea/issues/165
ENABLE_REVERSE_PROXY_AUTHENTICATION = false
ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
; Enable captcha validation for registration
@@ -334,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
@@ -342,13 +343,13 @@ RECEIVERS =
LEVEL =
; Either "mysql" or "postgres"
DRIVER =
; Based on xorm, e.g.: root:root@localhost/gogs?charset=utf8
; Based on xorm, e.g.: root:root@localhost/gitea?charset=utf8
CONN =
[cron]
; Enable running cron tasks periodically.
ENABLED = true
; Run cron tasks when Gogs starts.
; Run cron tasks when Gitea starts.
RUN_AT_START = false
; Update mirrors
@@ -398,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
NAMES = English,简体中文,繁體中文(香港),繁體中文(台湾),Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen,Türkçe,čeština,Српски
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]
@@ -421,6 +422,9 @@ it-IT = it
fi-FI = fi
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
@@ -428,7 +432,7 @@ cs-CZ = cs-CZ
[other]
SHOW_FOOTER_BRANDING = false
; Show version information about Gogs and Go in the footer
; Show version information about Gitea and Go in the footer
SHOW_FOOTER_VERSION = true
; Show time of template execution in the footer
SHOW_FOOTER_TEMPLATE_LOAD_TIME = true

View File

@@ -1,111 +0,0 @@
# Docker for Gogs
Visit [Docker Hub](https://hub.docker.com/r/gogs/) see all available images and tags.
## Usage
To keep your data out of Docker container, we do a volume (`/var/gogs` -> `/data`) here, and you can change it based on your situation.
```
# Pull image from Docker Hub.
$ docker pull gogs/gogs
# Create local directory for volume.
$ mkdir -p /var/gogs
# Use `docker run` for the first time.
$ docker run --name=gogs -p 10022:22 -p 10080:3000 -v /var/gogs:/data gogs/gogs
# Use `docker start` if you have stopped it.
$ docker start gogs
```
Note: It is important to map the Gogs ssh service from the container to the host and set the appropriate SSH Port and URI settings when setting up Gogs for the first time. To access and clone Gogs Git repositories with the above configuration you would use: `git clone ssh://git@hostname:10022/username/myrepo.git` for example.
Files will be store in local path `/var/gogs` in my case.
Directory `/var/gogs` keeps Git repositories and Gogs data:
/var/gogs
|-- git
| |-- gogs-repositories
|-- ssh
| |-- # ssh public/private keys for Gogs
|-- gogs
|-- conf
|-- data
|-- log
### Volume with data container
If you're more comfortable with mounting data to a data container, the commands you execute at the first time will look like as follows:
```
# Create data container
docker run --name=gogs-data --entrypoint /bin/true gogs/gogs
# Use `docker run` for the first time.
docker run --name=gogs --volumes-from gogs-data -p 10022:22 -p 10080:3000 gogs/gogs
```
#### Using Docker 1.9 Volume command
```
# Create docker volume.
$ docker volume create --name gogs-data
# Use `docker run` for the first time.
$ docker run --name=gogs -p 10022:22 -p 10080:3000 -v gogs-data:/data gogs/gogs
```
## Settings
### Application
Most of settings are obvious and easy to understand, but there are some settings can be confusing by running Gogs inside Docker:
- **Repository Root Path**: keep it as default value `/home/git/gogs-repositories` because `start.sh` already made a symbolic link for you.
- **Run User**: keep it as default value `git` because `start.sh` already setup a user with name `git`.
- **Domain**: fill in with Docker container IP (e.g. `192.168.99.100`). But if you want to access your Gogs instance from a different physical machine, please fill in with the hostname or IP address of the Docker host machine.
- **SSH Port**: Use the exposed port from Docker container. For example, your SSH server listens on `22` inside Docker, but you expose it by `10022:22`, then use `10022` for this value. **Builtin SSH server is not recommended inside Docker Container**
- **HTTP Port**: Use port you want Gogs to listen on inside Docker container. For example, your Gogs listens on `3000` inside Docker, and you expose it by `10080:3000`, but you still use `3000` for this value.
- **Application URL**: Use combination of **Domain** and **exposed HTTP Port** values (e.g. `http://192.168.99.100:10080/`).
Full documentation of application settings can be found [here](https://gogs.io/docs/advanced/configuration_cheat_sheet.html).
### Container options
This container have some options available via environment variables, these options are opt-in features that can help the administration of this container:
- **SOCAT_LINK**:
- <u>Possible value:</u>
`true`, `false`, `1`, `0`
- <u>Default:</u>
`true`
- <u>Action:</u>
Bind linked docker container to localhost socket using socat.
Any exported port from a linked container will be binded to the matching port on localhost.
- <u>Disclaimer:</u>
As this option rely on the environment variable created by docker when a container is linked, this option should be deactivated in managed environment such as Rancher or Kubernetes (set to `0` or `false`)
- **RUN_CROND**:
- <u>Possible value:</u>
`true`, `false`, `1`, `0`
- <u>Default:</u>
`false`
- <u>Action:</u>
Request crond to be run inside the container. Its default configuration will periodically run all scripts from `/etc/periodic/${period}` but custom crontabs can be added to `/var/spool/cron/crontabs/`.
## Upgrade
:exclamation::exclamation::exclamation:<span style="color: red">**Make sure you have volumed data to somewhere outside Docker container**</span>:exclamation::exclamation::exclamation:
Steps to upgrade Gogs with Docker:
- `docker pull gogs/gogs`
- `docker stop gogs`
- `docker rm gogs`
- Finally, create container as the first time and don't forget to do same volume and port mapping.
## Known Issues
- The docker container can not currently be build on Raspberry 1 (armv6l) as our base image `alpine` does not have a `go` package available for this platform.

View File

@@ -1,36 +0,0 @@
#!/bin/sh
set -x
set -e
# Set temp environment vars
export GOPATH=/tmp/go
export PATH=${PATH}:${GOPATH}/bin
export GO15VENDOREXPERIMENT=1
# Install build deps
apk --no-cache --no-progress add --virtual build-deps build-base linux-pam-dev go
# Install glide
git clone -b 0.10.2 https://github.com/Masterminds/glide ${GOPATH}/src/github.com/Masterminds/glide
cd ${GOPATH}/src/github.com/Masterminds/glide
make build
go install
# Build Gogs
mkdir -p ${GOPATH}/src/github.com/gogits/
ln -s /app/gogs/ ${GOPATH}/src/github.com/gogits/gogs
cd ${GOPATH}/src/github.com/gogits/gogs
glide install
make build TAGS="sqlite cert pam"
# Cleanup GOPATH & vendoring dir
rm -r $GOPATH /app/gogs/vendor
# Remove build deps
apk --no-progress del build-deps
# Create git user for Gogs
adduser -H -D -g 'Gogs Git User' git -h /data/git -s /bin/bash && passwd -u git
echo "export GOGS_CUSTOM=${GOGS_CUSTOM}" >> /etc/profile

View File

@@ -13,4 +13,3 @@ ethers: db files
rpc: db files
netgroup: nis

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

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

View File

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

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

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

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

@@ -0,0 +1,6 @@
#!/bin/bash
[[ -f ./setup ]] && source ./setup
pushd /app/gitea > /dev/null
exec su-exec git /app/gitea/gitea web
popd

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

@@ -0,0 +1,19 @@
#!/bin/bash
if [ ! -d /data/git/.ssh ]; then
mkdir -p /data/git/.ssh
chmod 700 /data/git/.ssh
fi
if [ ! -f /data/git/.ssh/environment ]; then
echo "GITEA_CUSTOM=/data/gitea" >| /data/git/.ssh/environment
chmod 600 /data/git/.ssh/environment
fi
if [ ! -f /data/gitea/conf/app.ini ]; then
mkdir -p /data/gitea/conf
cp /etc/templates/app.ini /data/gitea/conf/app.ini
fi
chown -R git:git /data/gitea /app/gitea /data/git
chmod 0755 /data/gitea /app/gitea /data/git

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

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

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

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

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

@@ -0,0 +1,29 @@
#!/bin/bash
if [ ! -d /data/ssh ]; then
mkdir -p /data/ssh
fi
if [ ! -f /data/ssh/ssh_host_ed25519_key ]; then
echo "Generating /data/ssh/ssh_host_ed25519_key..."
ssh-keygen -t ed25519 -b 4096 -f /data/ssh/ssh_host_ed25519_key -N "" > /dev/null
fi
if [ ! -f /data/ssh/ssh_host_rsa_key ]; then
echo "Generating /data/ssh/ssh_host_rsa_key..."
ssh-keygen -t rsa -b 2048 -f /data/ssh/ssh_host_rsa_key -N "" > /dev/null
fi
if [ ! -f /data/ssh/ssh_host_dsa_key ]; then
echo "Generating /data/ssh/ssh_host_dsa_key..."
ssh-keygen -t dsa -f /data/ssh/ssh_host_dsa_key -N "" > /dev/null
fi
if [ ! -f /data/ssh/ssh_host_ecdsa_key ]; then
echo "Generating /data/ssh/ssh_host_ecdsa_key..."
ssh-keygen -t ecdsa -b 256 -f /data/ssh/ssh_host_ecdsa_key -N "" > /dev/null
fi
chown root:root /data/ssh/*
chmod 0700 /data/ssh
chmod 0600 /data/ssh/*

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

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

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

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

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

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

View File

@@ -1,16 +1,32 @@
Port 22
Protocol 2
AddressFamily any
ListenAddress 0.0.0.0
ListenAddress ::
Protocol 2
LogLevel INFO
HostKey /data/ssh/ssh_host_ed25519_key
HostKey /data/ssh/ssh_host_rsa_key
HostKey /data/ssh/ssh_host_dsa_key
HostKey /data/ssh/ssh_host_ecdsa_key
HostKey /data/ssh/ssh_host_ed25519_key
PermitRootLogin no
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication no
UsePrivilegeSeparation no
AuthorizedKeysFile .ssh/authorized_keys
UseDNS no
AllowAgentForwarding no
AllowTcpForwarding no
PrintMotd no
PermitUserEnvironment yes
PermitRootLogin no
ChallengeResponseAuthentication no
PasswordAuthentication no
PermitEmptyPasswords no
AllowUsers git
Banner none
Subsystem sftp /usr/lib/ssh/sftp-server
UsePrivilegeSeparation no

View File

@@ -0,0 +1,24 @@
[repository]
ROOT = /data/git/repositories
[repository.upload]
TEMP_PATH = /data/gitea/uploads
[server]
APP_DATA_PATH = /data/gitea
[database]
HOST = mysql:3306
PATH = /data/gitea/gitea.db
[session]
PROVIDER_CONFIG = /data/gitea/sessions
[picture]
AVATAR_UPLOAD_PATH = /data/gitea/avatars
[attachment]
PATH = /data/gitea/attachments
[log]
ROOT_PATH = /data/gitea/log

View File

@@ -1,5 +0,0 @@
#!/bin/sh
# Cleanup SOCAT services and s6 event folder
rm -rf $(find /app/gogs/docker/s6/ -name 'event')
rm -rf /app/gogs/docker/s6/SOCAT_*

View File

View File

@@ -1,9 +0,0 @@
#!/bin/sh
# Crontabs are located by default in /var/spool/cron/crontabs/
# The default configuration is also calling all the scripts in /etc/periodic/${period}
if test -f ./setup; then
source ./setup
fi
exec gosu root /usr/sbin/crond -fS

View File

@@ -1,8 +0,0 @@
#!/bin/sh
if test -f ./setup; then
source ./setup
fi
export USER=git
exec gosu $USER /app/gogs/gogs web

View File

@@ -1,23 +0,0 @@
#!/bin/sh
if ! test -d ~git/.ssh; then
mkdir -p ~git/.ssh
chmod 700 ~git/.ssh
fi
if ! test -f ~git/.ssh/environment; then
echo "GOGS_CUSTOM=${GOGS_CUSTOM}" > ~git/.ssh/environment
chmod 600 ~git/.ssh/environment
fi
cd /app/gogs
# Link volumed data with app data
ln -sf /data/gogs/log ./log
ln -sf /data/gogs/data ./data
# Backward Compatibility with Gogs Container v0.6.15
ln -sf /data/git /home/git
chown -R git:git /data /app/gogs ~git/
chmod 0755 /data /data/gogs ~git/

View File

@@ -1,7 +0,0 @@
#!/bin/sh
if test -f ./setup; then
source ./setup
fi
exec gosu root /usr/sbin/sshd -D -f /app/gogs/docker/sshd_config

View File

@@ -1,23 +0,0 @@
#!/bin/sh
# Check if host keys are present, else create them
if ! test -f /data/ssh/ssh_host_rsa_key; then
ssh-keygen -q -f /data/ssh/ssh_host_rsa_key -N '' -t rsa
fi
if ! test -f /data/ssh/ssh_host_dsa_key; then
ssh-keygen -q -f /data/ssh/ssh_host_dsa_key -N '' -t dsa
fi
if ! test -f /data/ssh/ssh_host_ecdsa_key; then
ssh-keygen -q -f /data/ssh/ssh_host_ecdsa_key -N '' -t ecdsa
fi
if ! test -f /data/ssh/ssh_host_ed25519_key; then
ssh-keygen -q -f /data/ssh/ssh_host_ed25519_key -N '' -t ed25519
fi
# Set correct right to ssh keys
chown -R root:root /data/ssh/*
chmod 0700 /data/ssh
chmod 0600 /data/ssh/*

View File

@@ -1,7 +0,0 @@
#!/bin/sh
if test -f ./setup; then
source ./setup
fi
exec gosu root /sbin/syslogd -nS -O-

View File

@@ -1,65 +0,0 @@
#!/bin/sh
create_socat_links() {
# Bind linked docker container to localhost socket using socat
USED_PORT="3000:22"
while read NAME ADDR PORT; do
if test -z "$NAME$ADDR$PORT"; then
continue
elif echo $USED_PORT | grep -E "(^|:)$PORT($|:)" > /dev/null; then
echo "init:socat | Can't bind linked container ${NAME} to localhost, port ${PORT} already in use" 1>&2
else
SERV_FOLDER=/app/gogs/docker/s6/SOCAT_${NAME}_${PORT}
mkdir -p ${SERV_FOLDER}
CMD="socat -ls TCP4-LISTEN:${PORT},fork,reuseaddr TCP4:${ADDR}:${PORT}"
echo -e "#!/bin/sh\nexec $CMD" > ${SERV_FOLDER}/run
chmod +x ${SERV_FOLDER}/run
USED_PORT="${USED_PORT}:${PORT}"
echo "init:socat | Linked container ${NAME} will be binded to localhost on port ${PORT}" 1>&2
fi
done << EOT
$(env | sed -En 's|(.*)_PORT_([0-9]+)_TCP=tcp://(.*):([0-9]+)|\1 \3 \4|p')
EOT
}
cleanup() {
# Cleanup SOCAT services and s6 event folder
# On start and on shutdown in case container has been killed
rm -rf $(find /app/gogs/docker/s6/ -name 'event')
rm -rf /app/gogs/docker/s6/SOCAT_*
}
create_volume_subfolder() {
# Create VOLUME subfolder
for f in /data/gogs/data /data/gogs/conf /data/gogs/log /data/git /data/ssh; do
if ! test -d $f; then
mkdir -p $f
fi
done
}
cleanup
create_volume_subfolder
LINK=$(echo "$SOCAT_LINK" | tr '[:upper:]' '[:lower:]')
if [ "$LINK" = "false" -o "$LINK" = "0" ]; then
echo "init:socat | Will not try to create socat links as requested" 1>&2
else
create_socat_links
fi
CROND=$(echo "$RUN_CROND" | tr '[:upper:]' '[:lower:]')
if [ "$CROND" = "true" -o "$CROND" = "1" ]; then
echo "init:crond | Cron Daemon (crond) will be run as requested by s6" 1>&2
rm -f /app/gogs/docker/s6/crond/down
else
# Tell s6 not to run the crond service
touch /app/gogs/docker/s6/crond/down
fi
# Exec CMD or S6 by default if nothing present
if [ $# -gt 0 ];then
exec "$@"
else
exec /bin/s6-svscan /app/gogs/docker/s6/
fi

11
docker/usr/bin/entrypoint Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
for FOLDER in /data/gitea/conf /data/gitea/log /data/git /data/ssh; do
mkdir -p ${FOLDER}
done
if [ $# -gt 0 ]; then
exec "$@"
else
exec /bin/s6-svscan /etc/s6
fi

152
glide.lock generated
View File

@@ -1,152 +0,0 @@
hash: 1d5fcf2a90f7621ecbc0b1abed548e11d13bda3fea49b4326c829a523268e5cf
updated: 2016-06-12T17:35:14.27036884+08:00
imports:
- name: github.com/bradfitz/gomemcache
version: fb1f79c6b65acda83063cbc69f6bba1522558bfc
subpackages:
- memcache
- name: github.com/urfave/cli
version: 1efa31f08b9333f1bd4882d61f9d668a70cd902e
- name: github.com/go-macaron/binding
version: 9440f336b443056c90d7d448a0a55ad8c7599880
- name: github.com/go-macaron/cache
version: 56173531277692bc2925924d51fda1cd0a6b8178
subpackages:
- memcache
- redis
- name: github.com/go-macaron/captcha
version: 8aa5919789ab301e865595eb4b1114d6b9847deb
- name: github.com/go-macaron/csrf
version: 6a9a7df172cc1fcd81e4585f44b09200b6087cc0
- name: github.com/go-macaron/gzip
version: cad1c6580a07c56f5f6bc52d66002a05985c5854
- name: github.com/go-macaron/i18n
version: ef57533c3b0fc2d8581deda14937e52f11a203ab
- name: github.com/go-macaron/inject
version: c5ab7bf3a307593cd44cb272d1a5beea473dd072
- name: github.com/go-macaron/session
version: 66031fcb37a0fff002a1f028eb0b3a815c78306b
subpackages:
- redis
- name: github.com/go-macaron/toolbox
version: 82b511550b0aefc36b3a28062ad3a52e812bee38
- name: github.com/go-sql-driver/mysql
version: 0b58b37b664c21f3010e836f1b931e1d0b0b0685
- name: github.com/go-xorm/core
version: 5bf745d7d163f4380e6c2bba8c4afa60534dd087
- name: github.com/go-xorm/xorm
version: c6c705684057842d9854e8299dd51abb06ae29f5
- name: github.com/gogits/chardet
version: 2404f777256163ea3eadb273dada5dcb037993c0
- name: github.com/gogits/cron
version: 7f3990acf1833faa5ebd0e86f0a4c72a4b5eba3c
- name: github.com/gogits/git-module
version: 5e0c1330d7853d1affbc193885d517db0f8d1ca5
- name: github.com/gogits/go-gogs-client
version: c52f7ee0cc58d3cd6e379025552873a8df6de322
- name: github.com/issue9/identicon
version: d36b54562f4cf70c83653e13dc95c220c79ef521
- name: github.com/jaytaylor/html2text
version: 52d9b785554a1918cb09909b89a1509a98b853fd
- name: github.com/kardianos/minwinsvc
version: cad6b2b879b0970e4245a20ebf1a81a756e2bb70
- name: github.com/klauspost/compress
version: 14eb9c4951195779ecfbec34431a976de7335b0a
subpackages:
- gzip
- flate
- name: github.com/klauspost/cpuid
version: 09cded8978dc9e80714c4d85b0322337b0a1e5e0
- name: github.com/klauspost/crc32
version: 19b0b332c9e4516a6370a0456e6182c3b5036720
- name: github.com/lib/pq
version: 80f8150043c80fb52dee6bc863a709cdac7ec8f8
subpackages:
- oid
- name: github.com/mattn/go-sqlite3
version: e118d4451349065b8e7ce0f0af32e033995363f8
- name: github.com/mcuadros/go-version
version: d52711f8d6bea8dc01efafdb68ad95a4e2606630
- name: github.com/microcosm-cc/bluemonday
version: 9dc199233bf72cc1aad9b61f73daf2f0075b9ee4
- name: github.com/msteinert/pam
version: 02ccfbfaf0cc627aa3aec8ef7ed5cfeec5b43f63
- name: github.com/nfnt/resize
version: 891127d8d1b52734debe1b3c3d7e747502b6c366
- name: github.com/russross/blackfriday
version: 93622da34e54fb6529bfb7c57e710f37a8d9cbd8
- name: github.com/satori/go.uuid
version: 0aa62d5ddceb50dbcb909d790b5345affd3669b6
- name: github.com/sergi/go-diff
version: ec7fdbb58eb3e300c8595ad5ac74a5aa50019cc7
subpackages:
- diffmatchpatch
- name: github.com/strk/go-libravatar
version: 5eed7bff870ae19ef51c5773dbc8f3e9fcbd0982
- name: github.com/shurcooL/sanitized_anchor_name
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
- name: github.com/Unknwon/cae
version: 7f5e046bc8a6c3cde743c233b96ee4fd84ee6ecd
subpackages:
- zip
- name: github.com/Unknwon/com
version: 28b053d5a2923b87ce8c5a08f3af779894a72758
- name: github.com/Unknwon/i18n
version: 39d6f2727e0698b1021ceb6a77c1801aa92e7d5d
- name: github.com/Unknwon/paginater
version: 7748a72e01415173a27d79866b984328e7b0c12b
- name: golang.org/x/crypto
version: bc89c496413265e715159bdc8478ee9a92fdc265
subpackages:
- ssh
- curve25519
- ed25519
- ed25519/internal/edwards25519
- name: golang.org/x/net
version: 57bfaa875b96fb91b4766077f34470528d4b03e9
subpackages:
- html
- html/charset
- html/atom
- name: golang.org/x/sys
version: a646d33e2ee3172a661fc09bca23bb4889a41bc8
subpackages:
- windows/svc
- windows
- name: golang.org/x/text
version: 2910a502d2bf9e43193af9d68ca516529614eed3
subpackages:
- transform
- language
- encoding
- encoding/charmap
- encoding/htmlindex
- internal/tag
- encoding/internal/identifier
- encoding/internal
- encoding/japanese
- encoding/korean
- encoding/simplifiedchinese
- encoding/traditionalchinese
- encoding/unicode
- internal/utf8internal
- runes
- name: gopkg.in/alexcesaro/quotedprintable.v3
version: 2caba252f4dc53eaf6b553000885530023f54623
- name: gopkg.in/asn1-ber.v1
version: 4e86f4367175e39f69d9358a5f17b4dda270378d
- name: gopkg.in/bufio.v1
version: 567b2bfa514e796916c4747494d6ff5132a1dfce
- name: gopkg.in/editorconfig/editorconfig-core-go.v1
version: a872f05c2e34b37b567401384d202aff11ba06d4
- name: gopkg.in/gomail.v2
version: 81ebce5c23dfd25c6c67194b37d3dd3f338c98b1
- name: gopkg.in/ini.v1
version: cf53f9204df4fbdd7ec4164b57fa6184ba168292
- name: gopkg.in/ldap.v2
version: d0a5ced67b4dc310b9158d63a2c6f9c5ec13f105
- name: gopkg.in/macaron.v1
version: 7564489a79f3f96b7ac8034652b35eeebb468eb4
- name: gopkg.in/redis.v2
version: e6179049628164864e6e84e973cfb56335748dea
devImports: []

View File

@@ -1,59 +0,0 @@
package: github.com/gogits/gogs
import:
- package: github.com/Unknwon/cae
subpackages:
- zip
- package: github.com/Unknwon/com
- package: github.com/Unknwon/i18n
- package: github.com/Unknwon/paginater
- package: github.com/urfave/cli
- package: github.com/go-macaron/binding
- package: github.com/go-macaron/cache
subpackages:
- memcache
- redis
- package: github.com/go-macaron/captcha
- package: github.com/go-macaron/csrf
- package: github.com/go-macaron/gzip
- package: github.com/go-macaron/i18n
- package: github.com/go-macaron/session
subpackages:
- redis
- package: github.com/go-macaron/toolbox
- package: github.com/go-sql-driver/mysql
- package: github.com/go-xorm/core
- package: github.com/go-xorm/xorm
- package: github.com/gogits/chardet
- package: github.com/gogits/cron
- package: github.com/gogits/git-module
- package: github.com/gogits/go-gogs-client
- package: github.com/issue9/identicon
- package: github.com/kardianos/minwinsvc
- package: github.com/lib/pq
- package: github.com/mattn/go-sqlite3
- package: github.com/mcuadros/go-version
- package: github.com/microcosm-cc/bluemonday
- package: github.com/msteinert/pam
- package: github.com/nfnt/resize
- package: github.com/russross/blackfriday
- package: github.com/satori/go.uuid
- package: github.com/sergi/go-diff
subpackages:
- diffmatchpatch
- package: github.com/strk/go-libravatar
- package: golang.org/x/crypto
subpackages:
- ssh
- package: golang.org/x/net
subpackages:
- html
- html/charset
- package: golang.org/x/text
subpackages:
- transform
- language
- package: gopkg.in/editorconfig/editorconfig-core-go.v1
- package: gopkg.in/gomail.v2
- package: gopkg.in/ini.v1
- package: gopkg.in/ldap.v2
- package: gopkg.in/macaron.v1

42
gogs.go
View File

@@ -1,42 +0,0 @@
// +build go1.4
// 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.
// Gogs (Go Git Service) is a painless self-hosted Git Service.
package main
import (
"os"
"runtime"
"github.com/urfave/cli"
"github.com/gogits/gogs/cmd"
"github.com/gogits/gogs/modules/setting"
)
const APP_VER = "0.9.99.0915"
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
setting.AppVer = APP_VER
}
func main() {
app := cli.NewApp()
app.Name = "Gogs"
app.Usage = "Go Git Service: a painless self-hosted Git service"
app.Version = APP_VER
app.Commands = []cli.Command{
cmd.CmdWeb,
cmd.CmdServ,
cmd.CmdUpdate,
cmd.CmdDump,
cmd.CmdCert,
cmd.CmdAdmin,
}
app.Flags = append(app.Flags, []cli.Flag{}...)
app.Run(os.Args)
}

47
main.go Normal file
View File

@@ -0,0 +1,47 @@
// 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.
// Gitea (git with a cup of tea) is a painless self-hosted Git Service.
package main // import "code.gitea.io/gitea"
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
var Version = "1.0.2+dev"
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
setting.AppVer = Version
}
func main() {
app := cli.NewApp()
app.Name = "Gitea"
app.Usage = "A painless self-hosted Git service"
app.Version = Version
app.Commands = []cli.Command{
cmd.CmdWeb,
cmd.CmdServ,
cmd.CmdUpdate,
cmd.CmdDump,
cmd.CmdCert,
cmd.CmdAdmin,
}
app.Flags = append(app.Flags, []cli.Flag{}...)
err := app.Run(os.Args)
if err != nil {
log.Fatal(4, "Fail to run app with %s: %v", os.Args, err)
}
}

View File

@@ -7,28 +7,34 @@ package models
import (
"fmt"
"github.com/gogits/gogs/modules/log"
"code.gitea.io/gitea/modules/log"
)
// AccessMode specifies the users access mode
type AccessMode int
const (
ACCESS_MODE_NONE AccessMode = iota // 0
ACCESS_MODE_READ // 1
ACCESS_MODE_WRITE // 2
ACCESS_MODE_ADMIN // 3
ACCESS_MODE_OWNER // 4
// AccessModeNone no access
AccessModeNone AccessMode = iota // 0
// AccessModeRead read access
AccessModeRead // 1
// AccessModeWrite write access
AccessModeWrite // 2
// AccessModeAdmin admin access
AccessModeAdmin // 3
// AccessModeOwner owner access
AccessModeOwner // 4
)
func (mode AccessMode) String() string {
switch mode {
case ACCESS_MODE_READ:
case AccessModeRead:
return "read"
case ACCESS_MODE_WRITE:
case AccessModeWrite:
return "write"
case ACCESS_MODE_ADMIN:
case AccessModeAdmin:
return "admin"
case ACCESS_MODE_OWNER:
case AccessModeOwner:
return "owner"
default:
return "none"
@@ -39,11 +45,11 @@ func (mode AccessMode) String() string {
func ParseAccessMode(permission string) AccessMode {
switch permission {
case "write":
return ACCESS_MODE_WRITE
return AccessModeWrite
case "admin":
return ACCESS_MODE_ADMIN
return AccessModeAdmin
default:
return ACCESS_MODE_READ
return AccessModeRead
}
}
@@ -57,21 +63,21 @@ type Access struct {
Mode AccessMode
}
func accessLevel(e Engine, u *User, repo *Repository) (AccessMode, error) {
mode := ACCESS_MODE_NONE
func accessLevel(e Engine, user *User, repo *Repository) (AccessMode, error) {
mode := AccessModeNone
if !repo.IsPrivate {
mode = ACCESS_MODE_READ
mode = AccessModeRead
}
if u == nil {
if user == nil {
return mode, nil
}
if u.ID == repo.OwnerID {
return ACCESS_MODE_OWNER, nil
if user.ID == repo.OwnerID {
return AccessModeOwner, nil
}
a := &Access{UserID: u.ID, RepoID: repo.ID}
a := &Access{UserID: user.ID, RepoID: repo.ID}
if has, err := e.Get(a); !has || err != nil {
return mode, err
}
@@ -80,24 +86,24 @@ func accessLevel(e Engine, u *User, repo *Repository) (AccessMode, error) {
// AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the
// user does not have access. User can be nil!
func AccessLevel(u *User, repo *Repository) (AccessMode, error) {
return accessLevel(x, u, repo)
func AccessLevel(user *User, repo *Repository) (AccessMode, error) {
return accessLevel(x, user, repo)
}
func hasAccess(e Engine, u *User, repo *Repository, testMode AccessMode) (bool, error) {
mode, err := accessLevel(e, u, repo)
func hasAccess(e Engine, user *User, repo *Repository, testMode AccessMode) (bool, error) {
mode, err := accessLevel(e, user, repo)
return testMode <= mode, err
}
// HasAccess returns true if someone has the request access level. User can be nil!
func HasAccess(u *User, repo *Repository, testMode AccessMode) (bool, error) {
return hasAccess(x, u, repo, testMode)
func HasAccess(user *User, repo *Repository, testMode AccessMode) (bool, error) {
return hasAccess(x, user, repo, testMode)
}
// GetRepositoryAccesses finds all repositories with their access mode where a user has access but does not own.
func (u *User) GetRepositoryAccesses() (map[*Repository]AccessMode, error) {
func (user *User) GetRepositoryAccesses() (map[*Repository]AccessMode, error) {
accesses := make([]*Access, 0, 10)
if err := x.Find(&accesses, &Access{UserID: u.ID}); err != nil {
if err := x.Find(&accesses, &Access{UserID: user.ID}); err != nil {
return nil, err
}
@@ -113,7 +119,7 @@ func (u *User) GetRepositoryAccesses() (map[*Repository]AccessMode, error) {
}
if err = repo.GetOwner(); err != nil {
return nil, err
} else if repo.OwnerID == u.ID {
} else if repo.OwnerID == user.ID {
continue
}
repos[repo] = access.Mode
@@ -124,18 +130,22 @@ func (u *User) GetRepositoryAccesses() (map[*Repository]AccessMode, error) {
// GetAccessibleRepositories finds repositories which the user has access but does not own.
// If limit is smaller than 1 means returns all found results.
func (user *User) GetAccessibleRepositories(limit int) (repos []*Repository, _ error) {
sess := x.Where("owner_id !=? ", user.ID).Desc("updated_unix")
sess := x.
Where("owner_id !=? ", user.ID).
Desc("updated_unix")
if limit > 0 {
sess.Limit(limit)
repos = make([]*Repository, 0, limit)
} else {
repos = make([]*Repository, 0, 10)
}
return repos, sess.Join("INNER", "access", "access.user_id = ? AND access.repo_id = repository.id", user.ID).Find(&repos)
return repos, sess.
Join("INNER", "access", "access.user_id = ? AND access.repo_id = repository.id", user.ID).
Find(&repos)
}
func maxAccessMode(modes ...AccessMode) AccessMode {
max := ACCESS_MODE_NONE
max := AccessModeNone
for _, mode := range modes {
if mode > max {
max = mode
@@ -146,9 +156,9 @@ func maxAccessMode(modes ...AccessMode) AccessMode {
// FIXME: do corss-comparison so reduce deletions and additions to the minimum?
func (repo *Repository) refreshAccesses(e Engine, accessMap map[int64]AccessMode) (err error) {
minMode := ACCESS_MODE_READ
minMode := AccessModeRead
if !repo.IsPrivate {
minMode = ACCESS_MODE_WRITE
minMode = AccessModeWrite
}
newAccesses := make([]Access, 0, len(accessMap))
@@ -212,7 +222,7 @@ func (repo *Repository) recalculateTeamAccesses(e Engine, ignTeamID int64) (err
// Owner team gets owner access, and skip for teams that do not
// have relations with repository.
if t.IsOwnerTeam() {
t.Authorize = ACCESS_MODE_OWNER
t.Authorize = AccessModeOwner
} else if !t.hasRepository(e, repo.ID) {
continue
}
@@ -241,6 +251,6 @@ func (repo *Repository) recalculateAccesses(e Engine) error {
}
// RecalculateAccesses recalculates all accesses for repository.
func (r *Repository) RecalculateAccesses() error {
return r.recalculateAccesses(x)
func (repo *Repository) RecalculateAccesses() error {
return repo.recalculateAccesses(x)
}

View File

@@ -16,41 +16,44 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client"
"code.gitea.io/git"
api "code.gitea.io/sdk/gitea"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
// ActionType represents the type of an action.
type ActionType int
// Possible action types.
const (
ACTION_CREATE_REPO ActionType = iota + 1 // 1
ACTION_RENAME_REPO // 2
ACTION_STAR_REPO // 3
ACTION_WATCH_REPO // 4
ACTION_COMMIT_REPO // 5
ACTION_CREATE_ISSUE // 6
ACTION_CREATE_PULL_REQUEST // 7
ACTION_TRANSFER_REPO // 8
ACTION_PUSH_TAG // 9
ACTION_COMMENT_ISSUE // 10
ACTION_MERGE_PULL_REQUEST // 11
ACTION_CLOSE_ISSUE // 12
ACTION_REOPEN_ISSUE // 13
ACTION_CLOSE_PULL_REQUEST // 14
ACTION_REOPEN_PULL_REQUEST // 15
ActionCreateRepo ActionType = iota + 1 // 1
ActionRenameRepo // 2
ActionStarRepo // 3
ActionWatchRepo // 4
ActionCommitRepo // 5
ActionCreateIssue // 6
ActionCreatePullRequest // 7
ActionTransferRepo // 8
ActionPushTag // 9
ActionCommentIssue // 10
ActionMergePullRequest // 11
ActionCloseIssue // 12
ActionReopenIssue // 13
ActionClosePullRequest // 14
ActionReopenPullRequest // 15
)
var (
// Same as Github. See https://help.github.com/articles/closing-issues-via-commit-messages
IssueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
IssueReopenKeywords = []string{"reopen", "reopens", "reopened"}
// Same as Github. See
// https://help.github.com/articles/closing-issues-via-commit-messages
issueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
issueReopenKeywords = []string{"reopen", "reopens", "reopened"}
IssueCloseKeywordsPat, IssueReopenKeywordsPat *regexp.Regexp
IssueReferenceKeywordsPat *regexp.Regexp
issueCloseKeywordsPat, issueReopenKeywordsPat *regexp.Regexp
issueReferenceKeywordsPat *regexp.Regexp
)
func assembleKeywordsPattern(words []string) string {
@@ -58,13 +61,14 @@ func assembleKeywordsPattern(words []string) string {
}
func init() {
IssueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(IssueCloseKeywords))
IssueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(IssueReopenKeywords))
IssueReferenceKeywordsPat = regexp.MustCompile(`(?i)(?:)(^| )\S+`)
issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords))
issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords))
issueReferenceKeywordsPat = regexp.MustCompile(`(?i)(?:)(^| )\S+`)
}
// Action represents user operation type and other information to repository.,
// it implemented interface base.Actioner so that can be used in template render.
// Action represents user operation type and other information to
// repository. It implemented interface base.Actioner so that can be
// used in template render.
type Action struct {
ID int64 `xorm:"pk autoincr"`
UserID int64 // Receiver user id.
@@ -82,10 +86,13 @@ type Action struct {
CreatedUnix int64
}
// BeforeInsert will be invoked by XORM before inserting a record
// representing this object.
func (a *Action) BeforeInsert() {
a.CreatedUnix = time.Now().Unix()
}
// AfterSet updates the webhook object upon setting a column.
func (a *Action) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
@@ -93,65 +100,87 @@ func (a *Action) AfterSet(colName string, _ xorm.Cell) {
}
}
// GetOpType gets the ActionType of this action.
// TODO: change return type to ActionType ?
func (a *Action) GetOpType() int {
return int(a.OpType)
}
// GetActUserName gets the action's user name.
func (a *Action) GetActUserName() string {
return a.ActUserName
}
// ShortActUserName gets the action's user name trimmed to max 20
// chars.
func (a *Action) ShortActUserName() string {
return base.EllipsisString(a.ActUserName, 20)
}
// GetRepoUserName returns the name of the action repository owner.
func (a *Action) GetRepoUserName() string {
return a.RepoUserName
}
// ShortRepoUserName returns the name of the action repository owner
// trimmed to max 20 chars.
func (a *Action) ShortRepoUserName() string {
return base.EllipsisString(a.RepoUserName, 20)
}
// GetRepoName returns the name of the action repository.
func (a *Action) GetRepoName() string {
return a.RepoName
}
// ShortRepoName returns the name of the action repository
// trimmed to max 33 chars.
func (a *Action) ShortRepoName() string {
return base.EllipsisString(a.RepoName, 33)
}
// GetRepoPath returns the virtual path to the action repository.
func (a *Action) GetRepoPath() string {
return path.Join(a.RepoUserName, a.RepoName)
}
// ShortRepoPath returns the virtual path to the action repository
// trimed to max 20 + 1 + 33 chars.
func (a *Action) ShortRepoPath() string {
return path.Join(a.ShortRepoUserName(), a.ShortRepoName())
}
// GetRepoLink returns relative link to action repository.
func (a *Action) GetRepoLink() string {
if len(setting.AppSubUrl) > 0 {
return path.Join(setting.AppSubUrl, a.GetRepoPath())
if len(setting.AppSubURL) > 0 {
return path.Join(setting.AppSubURL, a.GetRepoPath())
}
return "/" + a.GetRepoPath()
}
// GetBranch returns the action's repository branch.
func (a *Action) GetBranch() string {
return a.RefName
}
// GetContent returns the action's content.
func (a *Action) GetContent() string {
return a.Content
}
// GetCreate returns the action creation time.
func (a *Action) GetCreate() time.Time {
return a.Created
}
// GetIssueInfos returns a list of issues associated with
// the action.
func (a *Action) GetIssueInfos() []string {
return strings.SplitN(a.Content, "|", 2)
}
// GetIssueTitle returns the title of first issue associated
// with the action.
func (a *Action) GetIssueTitle() string {
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
issue, err := GetIssueByIndex(a.RepoID, index)
@@ -162,6 +191,8 @@ func (a *Action) GetIssueTitle() string {
return issue.Title
}
// GetIssueContent returns the content of first issue associated with
// this action.
func (a *Action) GetIssueContent() string {
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
issue, err := GetIssueByIndex(a.RepoID, index)
@@ -176,7 +207,7 @@ func newRepoAction(e Engine, u *User, repo *Repository) (err error) {
if err = notifyWatchers(e, &Action{
ActUserID: u.ID,
ActUserName: u.Name,
OpType: ACTION_CREATE_REPO,
OpType: ActionCreateRepo,
RepoID: repo.ID,
RepoUserName: repo.Owner.Name,
RepoName: repo.Name,
@@ -198,7 +229,7 @@ func renameRepoAction(e Engine, actUser *User, oldRepoName string, repo *Reposit
if err = notifyWatchers(e, &Action{
ActUserID: actUser.ID,
ActUserName: actUser.Name,
OpType: ACTION_RENAME_REPO,
OpType: ActionRenameRepo,
RepoID: repo.ID,
RepoUserName: repo.Owner.Name,
RepoName: repo.Name,
@@ -221,6 +252,7 @@ func issueIndexTrimRight(c rune) bool {
return !unicode.IsDigit(c)
}
// PushCommit represents a commit in a push operation.
type PushCommit struct {
Sha1 string
Message string
@@ -231,6 +263,7 @@ type PushCommit struct {
Timestamp time.Time
}
// PushCommits represents list of commits in a push operation.
type PushCommits struct {
Len int
Commits []*PushCommit
@@ -239,13 +272,16 @@ type PushCommits struct {
avatars map[string]string
}
// NewPushCommits creates a new PushCommits object.
func NewPushCommits() *PushCommits {
return &PushCommits{
avatars: make(map[string]string),
}
}
func (pc *PushCommits) ToApiPayloadCommits(repoLink string) []*api.PayloadCommit {
// ToAPIPayloadCommits converts a PushCommits object to
// api.PayloadCommit format.
func (pc *PushCommits) ToAPIPayloadCommits(repoLink string) []*api.PayloadCommit {
commits := make([]*api.PayloadCommit, len(pc.Commits))
for i, commit := range pc.Commits {
authorUsername := ""
@@ -281,21 +317,21 @@ func (pc *PushCommits) ToApiPayloadCommits(repoLink string) []*api.PayloadCommit
// AvatarLink tries to match user in database with e-mail
// in order to show custom avatar, and falls back to general avatar link.
func (push *PushCommits) AvatarLink(email string) string {
_, ok := push.avatars[email]
func (pc *PushCommits) AvatarLink(email string) string {
_, ok := pc.avatars[email]
if !ok {
u, err := GetUserByEmail(email)
if err != nil {
push.avatars[email] = base.AvatarLink(email)
pc.avatars[email] = base.AvatarLink(email)
if !IsErrUserNotExist(err) {
log.Error(4, "GetUserByEmail: %v", err)
}
} else {
push.avatars[email] = u.RelAvatarLink()
pc.avatars[email] = u.RelAvatarLink()
}
}
return push.avatars[email]
return pc.avatars[email]
}
// UpdateIssuesCommit checks if issues are manipulated by commit message.
@@ -305,7 +341,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
c := commits[i]
refMarked := make(map[int64]bool)
for _, ref := range IssueReferenceKeywordsPat.FindAllString(c.Message, -1) {
for _, ref := range issueReferenceKeywordsPat.FindAllString(c.Message, -1) {
ref = ref[strings.IndexByte(ref, byte(' '))+1:]
ref = strings.TrimRightFunc(ref, issueIndexTrimRight)
@@ -343,7 +379,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
refMarked = make(map[int64]bool)
// FIXME: can merge this one and next one to a common function.
for _, ref := range IssueCloseKeywordsPat.FindAllString(c.Message, -1) {
for _, ref := range issueCloseKeywordsPat.FindAllString(c.Message, -1) {
ref = ref[strings.IndexByte(ref, byte(' '))+1:]
ref = strings.TrimRightFunc(ref, issueIndexTrimRight)
@@ -383,7 +419,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
}
// It is conflict to have close and reopen at same time, so refsMarkd doesn't need to reinit here.
for _, ref := range IssueReopenKeywordsPat.FindAllString(c.Message, -1) {
for _, ref := range issueReopenKeywordsPat.FindAllString(c.Message, -1) {
ref = ref[strings.IndexByte(ref, byte(' '))+1:]
ref = strings.TrimRightFunc(ref, issueIndexTrimRight)
@@ -425,6 +461,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
return nil
}
// CommitRepoActionOptions represent options of a new commit action.
type CommitRepoActionOptions struct {
PusherName string
RepoOwnerID int64
@@ -435,7 +472,8 @@ type CommitRepoActionOptions struct {
Commits *PushCommits
}
// CommitRepoAction adds new commit actio to the repository, and prepare corresponding webhooks.
// CommitRepoAction adds new commit action to the repository, and prepare
// corresponding webhooks.
func CommitRepoAction(opts CommitRepoActionOptions) error {
pusher, err := GetUserByName(opts.PusherName)
if err != nil {
@@ -454,14 +492,14 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
}
isNewBranch := false
opType := ACTION_COMMIT_REPO
opType := ActionCommitRepo
// Check it's tag push or branch.
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
opType = ACTION_PUSH_TAG
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)
@@ -501,15 +539,17 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
}()
apiPusher := pusher.APIFormat()
apiRepo := repo.APIFormat(nil)
apiRepo := repo.APIFormat(AccessModeNone)
var shaSum string
switch opType {
case ACTION_COMMIT_REPO: // Push
if err = PrepareWebhooks(repo, HOOK_EVENT_PUSH, &api.PushPayload{
case ActionCommitRepo: // Push
if err = PrepareWebhooks(repo, HookEventPush, &api.PushPayload{
Ref: opts.RefFullName,
Before: opts.OldCommitID,
After: opts.NewCommitID,
CompareURL: setting.AppUrl + opts.Commits.CompareURL,
Commits: opts.Commits.ToApiPayloadCommits(repo.HTMLURL()),
CompareURL: setting.AppURL + opts.Commits.CompareURL,
Commits: opts.Commits.ToAPIPayloadCommits(repo.HTMLURL()),
Repo: apiRepo,
Pusher: apiPusher,
Sender: apiPusher,
@@ -518,17 +558,35 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
}
if isNewBranch {
return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
gitRepo, err := git.OpenRepository(repo.RepoPath())
if err != nil {
log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err)
}
shaSum, err = gitRepo.GetBranchCommitID(refName)
if err != nil {
log.Error(4, "GetBranchCommitID[%s]: %v", opts.RefFullName, err)
}
return PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{
Ref: refName,
Sha: shaSum,
RefType: "branch",
Repo: apiRepo,
Sender: apiPusher,
})
}
case ACTION_PUSH_TAG: // Create
return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
case ActionPushTag: // Create
gitRepo, err := git.OpenRepository(repo.RepoPath())
if err != nil {
log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err)
}
shaSum, err = gitRepo.GetTagCommitID(refName)
if err != nil {
log.Error(4, "GetTagCommitID[%s]: %v", opts.RefFullName, err)
}
return PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{
Ref: refName,
Sha: shaSum,
RefType: "tag",
Repo: apiRepo,
Sender: apiPusher,
@@ -542,7 +600,7 @@ func transferRepoAction(e Engine, doer, oldOwner *User, repo *Repository) (err e
if err = notifyWatchers(e, &Action{
ActUserID: doer.ID,
ActUserName: doer.Name,
OpType: ACTION_TRANSFER_REPO,
OpType: ActionTransferRepo,
RepoID: repo.ID,
RepoUserName: repo.Owner.Name,
RepoName: repo.Name,
@@ -572,7 +630,7 @@ func mergePullRequestAction(e Engine, doer *User, repo *Repository, issue *Issue
return notifyWatchers(e, &Action{
ActUserID: doer.ID,
ActUserName: doer.Name,
OpType: ACTION_MERGE_PULL_REQUEST,
OpType: ActionMergePullRequest,
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title),
RepoID: repo.ID,
RepoUserName: repo.Owner.Name,
@@ -591,9 +649,14 @@ func MergePullRequestAction(actUser *User, repo *Repository, pull *Issue) error
// actorID can be -1 when isProfile is true or to skip the permission check.
func GetFeeds(ctxUser *User, actorID, offset int64, isProfile bool) ([]*Action, error) {
actions := make([]*Action, 0, 20)
sess := x.Limit(20, int(offset)).Desc("id").Where("user_id = ?", ctxUser.ID)
sess := x.
Limit(20, int(offset)).
Desc("id").
Where("user_id = ?", ctxUser.ID)
if isProfile {
sess.And("is_private = ?", false).And("act_user_id = ?", ctxUser.ID)
sess.
And("is_private = ?", false).
And("act_user_id = ?", ctxUser.ID)
} else if actorID != -1 && ctxUser.IsOrganization() {
// FIXME: only need to get IDs here, not all fields of repository.
repos, _, err := ctxUser.GetUserRepositories(actorID, 1, ctxUser.NumRepos)

View File

@@ -14,15 +14,16 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
//NoticeType describes the notice type
type NoticeType int
const (
NOTICE_REPOSITORY NoticeType = iota + 1
//NoticeRepository type
NoticeRepository NoticeType = iota + 1
)
// Notice represents a system notice for admin.
@@ -34,10 +35,12 @@ type Notice struct {
CreatedUnix int64
}
// BeforeInsert is invoked from XORM before inserting an object of this type.
func (n *Notice) BeforeInsert() {
n.CreatedUnix = time.Now().Unix()
}
// AfterSet is invoked from XORM after setting the value of a field of this object.
func (n *Notice) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
@@ -65,9 +68,9 @@ func CreateNotice(tp NoticeType, desc string) error {
return err
}
// CreateRepositoryNotice creates new system notice with type NOTICE_REPOSITORY.
// CreateRepositoryNotice creates new system notice with type NoticeRepository.
func CreateRepositoryNotice(desc string) error {
return CreateNotice(NOTICE_REPOSITORY, desc)
return CreateNotice(NoticeRepository, desc)
}
// RemoveAllWithNotice removes all directories in given path and
@@ -103,7 +106,10 @@ func CountNotices() int64 {
// Notices returns number of notices in given page.
func Notices(page, pageSize int) ([]*Notice, error) {
notices := make([]*Notice, 0, pageSize)
return notices, x.Limit(pageSize, (page-1)*pageSize).Desc("id").Find(&notices)
return notices, x.
Limit(pageSize, (page-1)*pageSize).
Desc("id").
Find(&notices)
}
// DeleteNotice deletes a system notice by given ID.
@@ -127,6 +133,8 @@ func DeleteNoticesByIDs(ids []int64) error {
if len(ids) == 0 {
return nil
}
_, err := x.Where("id IN (" + strings.Join(base.Int64sToStrings(ids), ",") + ")").Delete(new(Notice))
_, err := x.
In("id", ids).
Delete(new(Notice))
return err
}

View File

@@ -8,10 +8,12 @@ import (
"fmt"
)
// ErrNameReserved represents a "reserved name" error.
type ErrNameReserved struct {
Name string
}
// IsErrNameReserved checks if an error is a ErrNameReserved.
func IsErrNameReserved(err error) bool {
_, ok := err.(ErrNameReserved)
return ok
@@ -21,10 +23,13 @@ func (err ErrNameReserved) Error() string {
return fmt.Sprintf("name is reserved [name: %s]", err.Name)
}
// ErrNamePatternNotAllowed represents a "pattern not allowed" error.
type ErrNamePatternNotAllowed struct {
Pattern string
}
// IsErrNamePatternNotAllowed checks if an error is an
// ErrNamePatternNotAllowed.
func IsErrNamePatternNotAllowed(err error) bool {
_, ok := err.(ErrNamePatternNotAllowed)
return ok
@@ -41,10 +46,12 @@ func (err ErrNamePatternNotAllowed) Error() string {
// |______//____ >\___ >__|
// \/ \/
// ErrUserAlreadyExist represents a "user already exists" error.
type ErrUserAlreadyExist struct {
Name string
}
// IsErrUserAlreadyExist checks if an error is a ErrUserAlreadyExists.
func IsErrUserAlreadyExist(err error) bool {
_, ok := err.(ErrUserAlreadyExist)
return ok
@@ -54,24 +61,29 @@ func (err ErrUserAlreadyExist) Error() string {
return fmt.Sprintf("user already exists [name: %s]", err.Name)
}
// ErrUserNotExist represents a "UserNotExist" kind of error.
type ErrUserNotExist struct {
UID int64
Name string
UID int64
Name string
KeyID int64
}
// IsErrUserNotExist checks if an error is a ErrUserNotExist.
func IsErrUserNotExist(err error) bool {
_, ok := err.(ErrUserNotExist)
return ok
}
func (err ErrUserNotExist) Error() string {
return fmt.Sprintf("user does not exist [uid: %d, name: %s]", err.UID, err.Name)
return fmt.Sprintf("user does not exist [uid: %d, name: %s, keyid: %d]", err.UID, err.Name, err.KeyID)
}
// ErrEmailAlreadyUsed represents a "EmailAlreadyUsed" kind of error.
type ErrEmailAlreadyUsed struct {
Email string
}
// IsErrEmailAlreadyUsed checks if an error is a ErrEmailAlreadyUsed.
func IsErrEmailAlreadyUsed(err error) bool {
_, ok := err.(ErrEmailAlreadyUsed)
return ok
@@ -81,10 +93,12 @@ func (err ErrEmailAlreadyUsed) Error() string {
return fmt.Sprintf("e-mail has been used [email: %s]", err.Email)
}
// ErrUserOwnRepos represents a "UserOwnRepos" kind of error.
type ErrUserOwnRepos struct {
UID int64
}
// IsErrUserOwnRepos checks if an error is a ErrUserOwnRepos.
func IsErrUserOwnRepos(err error) bool {
_, ok := err.(ErrUserOwnRepos)
return ok
@@ -94,10 +108,12 @@ func (err ErrUserOwnRepos) Error() string {
return fmt.Sprintf("user still has ownership of repositories [uid: %d]", err.UID)
}
// ErrUserHasOrgs represents a "UserHasOrgs" kind of error.
type ErrUserHasOrgs struct {
UID int64
}
// IsErrUserHasOrgs checks if an error is a ErrUserHasOrgs.
func IsErrUserHasOrgs(err error) bool {
_, ok := err.(ErrUserHasOrgs)
return ok
@@ -107,10 +123,12 @@ func (err ErrUserHasOrgs) Error() string {
return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID)
}
// ErrReachLimitOfRepo represents a "ReachLimitOfRepo" kind of error.
type ErrReachLimitOfRepo struct {
Limit int
}
// IsErrReachLimitOfRepo checks if an error is a ErrReachLimitOfRepo.
func IsErrReachLimitOfRepo(err error) bool {
_, ok := err.(ErrReachLimitOfRepo)
return ok
@@ -127,10 +145,12 @@ func (err ErrReachLimitOfRepo) Error() string {
// \__/\ / |__|__|_ \__|
// \/ \/
// ErrWikiAlreadyExist represents a "WikiAlreadyExist" kind of error.
type ErrWikiAlreadyExist struct {
Title string
}
// IsErrWikiAlreadyExist checks if an error is a ErrWikiAlreadyExist.
func IsErrWikiAlreadyExist(err error) bool {
_, ok := err.(ErrWikiAlreadyExist)
return ok
@@ -147,10 +167,12 @@ func (err ErrWikiAlreadyExist) Error() string {
// |____| |____/|___ /____/__|\___ > |____|__ \___ > ____|
// \/ \/ \/ \/\/
// ErrKeyUnableVerify represents a "KeyUnableVerify" kind of error.
type ErrKeyUnableVerify struct {
Result string
}
// IsErrKeyUnableVerify checks if an error is a ErrKeyUnableVerify.
func IsErrKeyUnableVerify(err error) bool {
_, ok := err.(ErrKeyUnableVerify)
return ok
@@ -160,10 +182,12 @@ func (err ErrKeyUnableVerify) Error() string {
return fmt.Sprintf("Unable to verify key content [result: %s]", err.Result)
}
// ErrKeyNotExist represents a "KeyNotExist" kind of error.
type ErrKeyNotExist struct {
ID int64
}
// IsErrKeyNotExist checks if an error is a ErrKeyNotExist.
func IsErrKeyNotExist(err error) bool {
_, ok := err.(ErrKeyNotExist)
return ok
@@ -173,11 +197,13 @@ func (err ErrKeyNotExist) Error() string {
return fmt.Sprintf("public key does not exist [id: %d]", err.ID)
}
// ErrKeyAlreadyExist represents a "KeyAlreadyExist" kind of error.
type ErrKeyAlreadyExist struct {
OwnerID int64
Content string
}
// IsErrKeyAlreadyExist checks if an error is a ErrKeyAlreadyExist.
func IsErrKeyAlreadyExist(err error) bool {
_, ok := err.(ErrKeyAlreadyExist)
return ok
@@ -187,11 +213,13 @@ func (err ErrKeyAlreadyExist) Error() string {
return fmt.Sprintf("public key already exists [owner_id: %d, content: %s]", err.OwnerID, err.Content)
}
// ErrKeyNameAlreadyUsed represents a "KeyNameAlreadyUsed" kind of error.
type ErrKeyNameAlreadyUsed struct {
OwnerID int64
Name string
}
// IsErrKeyNameAlreadyUsed checks if an error is a ErrKeyNameAlreadyUsed.
func IsErrKeyNameAlreadyUsed(err error) bool {
_, ok := err.(ErrKeyNameAlreadyUsed)
return ok
@@ -201,12 +229,14 @@ func (err ErrKeyNameAlreadyUsed) Error() string {
return fmt.Sprintf("public key already exists [owner_id: %d, name: %s]", err.OwnerID, err.Name)
}
// ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error.
type ErrKeyAccessDenied struct {
UserID int64
KeyID int64
Note string
}
// IsErrKeyAccessDenied checks if an error is a ErrKeyAccessDenied.
func IsErrKeyAccessDenied(err error) bool {
_, ok := err.(ErrKeyAccessDenied)
return ok
@@ -217,12 +247,14 @@ func (err ErrKeyAccessDenied) Error() string {
err.UserID, err.KeyID, err.Note)
}
// ErrDeployKeyNotExist represents a "DeployKeyNotExist" kind of error.
type ErrDeployKeyNotExist struct {
ID int64
KeyID int64
RepoID int64
}
// IsErrDeployKeyNotExist checks if an error is a ErrDeployKeyNotExist.
func IsErrDeployKeyNotExist(err error) bool {
_, ok := err.(ErrDeployKeyNotExist)
return ok
@@ -232,11 +264,13 @@ func (err ErrDeployKeyNotExist) Error() string {
return fmt.Sprintf("Deploy key does not exist [id: %d, key_id: %d, repo_id: %d]", err.ID, err.KeyID, err.RepoID)
}
// ErrDeployKeyAlreadyExist represents a "DeployKeyAlreadyExist" kind of error.
type ErrDeployKeyAlreadyExist struct {
KeyID int64
RepoID int64
}
// IsErrDeployKeyAlreadyExist checks if an error is a ErrDeployKeyAlreadyExist.
func IsErrDeployKeyAlreadyExist(err error) bool {
_, ok := err.(ErrDeployKeyAlreadyExist)
return ok
@@ -246,11 +280,13 @@ func (err ErrDeployKeyAlreadyExist) Error() string {
return fmt.Sprintf("public key already exists [key_id: %d, repo_id: %d]", err.KeyID, err.RepoID)
}
// ErrDeployKeyNameAlreadyUsed represents a "DeployKeyNameAlreadyUsed" kind of error.
type ErrDeployKeyNameAlreadyUsed struct {
RepoID int64
Name string
}
// IsErrDeployKeyNameAlreadyUsed checks if an error is a ErrDeployKeyNameAlreadyUsed.
func IsErrDeployKeyNameAlreadyUsed(err error) bool {
_, ok := err.(ErrDeployKeyNameAlreadyUsed)
return ok
@@ -267,10 +303,12 @@ func (err ErrDeployKeyNameAlreadyUsed) Error() string {
// \____|__ /\___ >___ >___ >____ >____ > |____| \____/|__|_ \\___ >___| /
// \/ \/ \/ \/ \/ \/ \/ \/ \/
// ErrAccessTokenNotExist represents a "AccessTokenNotExist" kind of error.
type ErrAccessTokenNotExist struct {
SHA string
}
// IsErrAccessTokenNotExist checks if an error is a ErrAccessTokenNotExist.
func IsErrAccessTokenNotExist(err error) bool {
_, ok := err.(ErrAccessTokenNotExist)
return ok
@@ -280,9 +318,11 @@ func (err ErrAccessTokenNotExist) Error() string {
return fmt.Sprintf("access token does not exist [sha: %s]", err.SHA)
}
// ErrAccessTokenEmpty represents a "AccessTokenEmpty" kind of error.
type ErrAccessTokenEmpty struct {
}
// IsErrAccessTokenEmpty checks if an error is a ErrAccessTokenEmpty.
func IsErrAccessTokenEmpty(err error) bool {
_, ok := err.(ErrAccessTokenEmpty)
return ok
@@ -299,10 +339,12 @@ func (err ErrAccessTokenEmpty) Error() string {
// \_______ /__| \___ (____ /___| /__/_____ \(____ /__| |__|\____/|___| /
// \/ /_____/ \/ \/ \/ \/ \/
// ErrLastOrgOwner represents a "LastOrgOwner" kind of error.
type ErrLastOrgOwner struct {
UID int64
}
// IsErrLastOrgOwner checks if an error is a ErrLastOrgOwner.
func IsErrLastOrgOwner(err error) bool {
_, ok := err.(ErrLastOrgOwner)
return ok
@@ -319,12 +361,14 @@ func (err ErrLastOrgOwner) Error() string {
// |____|_ /\___ > __/ \____/____ >__||__| \____/|__| / ____|
// \/ \/|__| \/ \/
// ErrRepoNotExist represents a "RepoNotExist" kind of error.
type ErrRepoNotExist struct {
ID int64
UID int64
Name string
}
// IsErrRepoNotExist checks if an error is a ErrRepoNotExist.
func IsErrRepoNotExist(err error) bool {
_, ok := err.(ErrRepoNotExist)
return ok
@@ -334,11 +378,13 @@ func (err ErrRepoNotExist) Error() string {
return fmt.Sprintf("repository does not exist [id: %d, uid: %d, name: %s]", err.ID, err.UID, err.Name)
}
// ErrRepoAlreadyExist represents a "RepoAlreadyExist" kind of error.
type ErrRepoAlreadyExist struct {
Uname string
Name string
}
// IsErrRepoAlreadyExist checks if an error is a ErrRepoAlreadyExist.
func IsErrRepoAlreadyExist(err error) bool {
_, ok := err.(ErrRepoAlreadyExist)
return ok
@@ -348,12 +394,14 @@ func (err ErrRepoAlreadyExist) Error() string {
return fmt.Sprintf("repository already exists [uname: %s, name: %s]", err.Uname, err.Name)
}
// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error.
type ErrInvalidCloneAddr struct {
IsURLError bool
IsInvalidPath bool
IsPermissionDenied bool
}
// IsErrInvalidCloneAddr checks if an error is a ErrInvalidCloneAddr.
func IsErrInvalidCloneAddr(err error) bool {
_, ok := err.(ErrInvalidCloneAddr)
return ok
@@ -364,10 +412,12 @@ func (err ErrInvalidCloneAddr) Error() string {
err.IsURLError, err.IsInvalidPath, err.IsPermissionDenied)
}
// ErrUpdateTaskNotExist represents a "UpdateTaskNotExist" kind of error.
type ErrUpdateTaskNotExist struct {
UUID string
}
// IsErrUpdateTaskNotExist checks if an error is a ErrUpdateTaskNotExist.
func IsErrUpdateTaskNotExist(err error) bool {
_, ok := err.(ErrUpdateTaskNotExist)
return ok
@@ -377,10 +427,12 @@ func (err ErrUpdateTaskNotExist) Error() string {
return fmt.Sprintf("update task does not exist [uuid: %s]", err.UUID)
}
// ErrReleaseAlreadyExist represents a "ReleaseAlreadyExist" kind of error.
type ErrReleaseAlreadyExist struct {
TagName string
}
// IsErrReleaseAlreadyExist checks if an error is a ErrReleaseAlreadyExist.
func IsErrReleaseAlreadyExist(err error) bool {
_, ok := err.(ErrReleaseAlreadyExist)
return ok
@@ -390,11 +442,13 @@ func (err ErrReleaseAlreadyExist) Error() string {
return fmt.Sprintf("release tag already exist [tag_name: %s]", err.TagName)
}
// ErrReleaseNotExist represents a "ReleaseNotExist" kind of error.
type ErrReleaseNotExist struct {
ID int64
TagName string
}
// IsErrReleaseNotExist checks if an error is a ErrReleaseNotExist.
func IsErrReleaseNotExist(err error) bool {
_, ok := err.(ErrReleaseNotExist)
return ok
@@ -404,10 +458,12 @@ func (err ErrReleaseNotExist) Error() string {
return fmt.Sprintf("release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName)
}
// ErrInvalidTagName represents a "InvalidTagName" kind of error.
type ErrInvalidTagName struct {
TagName string
}
// IsErrInvalidTagName checks if an error is a ErrInvalidTagName.
func IsErrInvalidTagName(err error) bool {
_, ok := err.(ErrInvalidTagName)
return ok
@@ -417,10 +473,12 @@ func (err ErrInvalidTagName) Error() string {
return fmt.Sprintf("release tag name is not valid [tag_name: %s]", err.TagName)
}
// ErrRepoFileAlreadyExist represents a "RepoFileAlreadyExist" kind of error.
type ErrRepoFileAlreadyExist struct {
FileName string
}
// IsErrRepoFileAlreadyExist checks if an error is a ErrRepoFileAlreadyExist.
func IsErrRepoFileAlreadyExist(err error) bool {
_, ok := err.(ErrRepoFileAlreadyExist)
return ok
@@ -437,10 +495,12 @@ func (err ErrRepoFileAlreadyExist) Error() string {
// |______ / |__| (____ /___| /\___ >___| /
// \/ \/ \/ \/ \/
// ErrBranchNotExist represents a "BranchNotExist" kind of error.
type ErrBranchNotExist struct {
Name string
}
// IsErrBranchNotExist checks if an error is a ErrBranchNotExist.
func IsErrBranchNotExist(err error) bool {
_, ok := err.(ErrBranchNotExist)
return ok
@@ -457,10 +517,12 @@ func (err ErrBranchNotExist) Error() string {
// \__/\ / \___ >___ /___| /\____/ \____/|__|_ \
// \/ \/ \/ \/ \/
// ErrWebhookNotExist represents a "WebhookNotExist" kind of error.
type ErrWebhookNotExist struct {
ID int64
}
// IsErrWebhookNotExist checks if an error is a ErrWebhookNotExist.
func IsErrWebhookNotExist(err error) bool {
_, ok := err.(ErrWebhookNotExist)
return ok
@@ -477,12 +539,14 @@ func (err ErrWebhookNotExist) Error() string {
// |___/____ >____ >____/ \___ >
// \/ \/ \/
// ErrIssueNotExist represents a "IssueNotExist" kind of error.
type ErrIssueNotExist struct {
ID int64
RepoID int64
Index int64
}
// IsErrIssueNotExist checks if an error is a ErrIssueNotExist.
func IsErrIssueNotExist(err error) bool {
_, ok := err.(ErrIssueNotExist)
return ok
@@ -499,6 +563,7 @@ func (err ErrIssueNotExist) Error() string {
// |____| |____/|____/____/____|_ /\___ >__ |____/ \___ >____ > |__|
// \/ \/ |__| \/ \/
// ErrPullRequestNotExist represents a "PullRequestNotExist" kind of error.
type ErrPullRequestNotExist struct {
ID int64
IssueID int64
@@ -508,6 +573,7 @@ type ErrPullRequestNotExist struct {
BaseBranch string
}
// IsErrPullRequestNotExist checks if an error is a ErrPullRequestNotExist.
func IsErrPullRequestNotExist(err error) bool {
_, ok := err.(ErrPullRequestNotExist)
return ok
@@ -518,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)
}
// _________ __
// \_ ___ \ ____ _____ _____ ____ _____/ |_
// / \ \/ / _ \ / \ / \_/ __ \ / \ __\
@@ -525,11 +613,13 @@ func (err ErrPullRequestNotExist) Error() string {
// \______ /\____/|__|_| /__|_| /\___ >___| /__|
// \/ \/ \/ \/ \/
// ErrCommentNotExist represents a "CommentNotExist" kind of error.
type ErrCommentNotExist struct {
ID int64
IssueID int64
}
// IsErrCommentNotExist checks if an error is a ErrCommentNotExist.
func IsErrCommentNotExist(err error) bool {
_, ok := err.(ErrCommentNotExist)
return ok
@@ -546,11 +636,13 @@ func (err ErrCommentNotExist) Error() string {
// |_______ (____ /___ /\___ >____/
// \/ \/ \/ \/
// ErrLabelNotExist represents a "LabelNotExist" kind of error.
type ErrLabelNotExist struct {
LabelID int64
RepoID int64
}
// IsErrLabelNotExist checks if an error is a ErrLabelNotExist.
func IsErrLabelNotExist(err error) bool {
_, ok := err.(ErrLabelNotExist)
return ok
@@ -567,11 +659,13 @@ func (err ErrLabelNotExist) Error() string {
// \____|__ /__|____/\___ >____ > |__| \____/|___| /\___ >
// \/ \/ \/ \/ \/
// ErrMilestoneNotExist represents a "MilestoneNotExist" kind of error.
type ErrMilestoneNotExist struct {
ID int64
RepoID int64
}
// IsErrMilestoneNotExist checks if an error is a ErrMilestoneNotExist.
func IsErrMilestoneNotExist(err error) bool {
_, ok := err.(ErrMilestoneNotExist)
return ok
@@ -588,11 +682,13 @@ func (err ErrMilestoneNotExist) Error() string {
// \____|__ /__| |__| (____ /\___ >___| /__|_| /\___ >___| /__|
// \/ \/ \/ \/ \/ \/ \/
// ErrAttachmentNotExist represents a "AttachmentNotExist" kind of error.
type ErrAttachmentNotExist struct {
ID int64
UUID string
}
// IsErrAttachmentNotExist checks if an error is a ErrAttachmentNotExist.
func IsErrAttachmentNotExist(err error) bool {
_, ok := err.(ErrAttachmentNotExist)
return ok
@@ -609,10 +705,12 @@ func (err ErrAttachmentNotExist) Error() string {
// |_______ \____/\___ /|__|___| / /_______ /\____/|____/ |__| \___ >___ >
// \/ /_____/ \/ \/ \/ \/
// ErrLoginSourceNotExist represents a "LoginSourceNotExist" kind of error.
type ErrLoginSourceNotExist struct {
ID int64
}
// IsErrLoginSourceNotExist checks if an error is a ErrLoginSourceNotExist.
func IsErrLoginSourceNotExist(err error) bool {
_, ok := err.(ErrLoginSourceNotExist)
return ok
@@ -622,10 +720,12 @@ func (err ErrLoginSourceNotExist) Error() string {
return fmt.Sprintf("login source does not exist [id: %d]", err.ID)
}
// ErrLoginSourceAlreadyExist represents a "LoginSourceAlreadyExist" kind of error.
type ErrLoginSourceAlreadyExist struct {
Name string
}
// IsErrLoginSourceAlreadyExist checks if an error is a ErrLoginSourceAlreadyExist.
func IsErrLoginSourceAlreadyExist(err error) bool {
_, ok := err.(ErrLoginSourceAlreadyExist)
return ok
@@ -635,10 +735,12 @@ func (err ErrLoginSourceAlreadyExist) Error() string {
return fmt.Sprintf("login source already exists [name: %s]", err.Name)
}
// ErrLoginSourceInUse represents a "LoginSourceInUse" kind of error.
type ErrLoginSourceInUse struct {
ID int64
}
// IsErrLoginSourceInUse checks if an error is a ErrLoginSourceInUse.
func IsErrLoginSourceInUse(err error) bool {
_, ok := err.(ErrLoginSourceInUse)
return ok
@@ -655,11 +757,13 @@ func (err ErrLoginSourceInUse) Error() string {
// |____| \___ >____ /__|_| /
// \/ \/ \/
// ErrTeamAlreadyExist represents a "TeamAlreadyExist" kind of error.
type ErrTeamAlreadyExist struct {
OrgID int64
Name string
}
// IsErrTeamAlreadyExist checks if an error is a ErrTeamAlreadyExist.
func IsErrTeamAlreadyExist(err error) bool {
_, ok := err.(ErrTeamAlreadyExist)
return ok
@@ -677,11 +781,13 @@ func (err ErrTeamAlreadyExist) Error() string {
// |__| \/ \/
//
// ErrUploadNotExist represents a "UploadNotExist" kind of error.
type ErrUploadNotExist struct {
ID int64
UUID string
}
// IsErrUploadNotExist checks if an error is a ErrUploadNotExist.
func IsErrUploadNotExist(err error) bool {
_, ok := err.(ErrAttachmentNotExist)
return ok

View File

@@ -16,38 +16,41 @@ import (
"os/exec"
"strings"
"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"
"github.com/Unknwon/com"
"github.com/sergi/go-diff/diffmatchpatch"
"golang.org/x/net/html/charset"
"golang.org/x/text/transform"
"github.com/gogits/git-module"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/template/highlight"
)
// DiffLineType represents the type of a DiffLine.
type DiffLineType uint8
// DiffLineType possible values.
const (
DIFF_LINE_PLAIN DiffLineType = iota + 1
DIFF_LINE_ADD
DIFF_LINE_DEL
DIFF_LINE_SECTION
DiffLinePlain DiffLineType = iota + 1
DiffLineAdd
DiffLineDel
DiffLineSection
)
// DiffFileType represents the type of a DiffFile.
type DiffFileType uint8
// DiffFileType possible values.
const (
DIFF_FILE_ADD DiffFileType = iota + 1
DIFF_FILE_CHANGE
DIFF_FILE_DEL
DIFF_FILE_RENAME
DiffFileAdd DiffFileType = iota + 1
DiffFileChange
DiffFileDel
DiffFileRename
)
// DiffLine represents a line difference in a DiffSection.
type DiffLine struct {
LeftIdx int
RightIdx int
@@ -55,10 +58,12 @@ type DiffLine struct {
Content string
}
// GetType returns the type of a DiffLine.
func (d *DiffLine) GetType() int {
return int(d.Type)
}
// DiffSection represents a section of a DiffFile.
type DiffSection struct {
Name string
Lines []*DiffLine
@@ -75,19 +80,19 @@ func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTM
// Reproduce signs which are cutted for inline diff before.
switch lineType {
case DIFF_LINE_ADD:
case DiffLineAdd:
buf.WriteByte('+')
case DIFF_LINE_DEL:
case DiffLineDel:
buf.WriteByte('-')
}
for i := range diffs {
switch {
case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DIFF_LINE_ADD:
case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd:
buf.Write(addedCodePrefix)
buf.WriteString(html.EscapeString(diffs[i].Text))
buf.Write(codeTagSuffix)
case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DIFF_LINE_DEL:
case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DiffLineDel:
buf.Write(removedCodePrefix)
buf.WriteString(html.EscapeString(diffs[i].Text))
buf.Write(codeTagSuffix)
@@ -99,7 +104,7 @@ func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTM
return template.HTML(buf.Bytes())
}
// get an specific line by type (add or del) and file line number
// GetLine gets a specific line by type (add or del) and file line number
func (diffSection *DiffSection) GetLine(lineType DiffLineType, idx int) *DiffLine {
var (
difference = 0
@@ -111,9 +116,9 @@ func (diffSection *DiffSection) GetLine(lineType DiffLineType, idx int) *DiffLin
LOOP:
for _, diffLine := range diffSection.Lines {
switch diffLine.Type {
case DIFF_LINE_ADD:
case DiffLineAdd:
addCount++
case DIFF_LINE_DEL:
case DiffLineDel:
delCount++
default:
if matchDiffLine != nil {
@@ -125,11 +130,11 @@ LOOP:
}
switch lineType {
case DIFF_LINE_DEL:
case DiffLineDel:
if diffLine.RightIdx == 0 && diffLine.LeftIdx == idx-difference {
matchDiffLine = diffLine
}
case DIFF_LINE_ADD:
case DiffLineAdd:
if diffLine.LeftIdx == 0 && diffLine.RightIdx == idx+difference {
matchDiffLine = diffLine
}
@@ -148,7 +153,7 @@ func init() {
diffMatchPatch.DiffEditCost = 100
}
// computes inline diff for the given line
// GetComputedInlineDiffFor computes inline diff for the given line.
func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) template.HTML {
if setting.Git.DisableDiffHighlight {
return template.HTML(html.EscapeString(diffLine.Content[1:]))
@@ -161,15 +166,15 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem
// try to find equivalent diff line. ignore, otherwise
switch diffLine.Type {
case DIFF_LINE_ADD:
compareDiffLine = diffSection.GetLine(DIFF_LINE_DEL, diffLine.RightIdx)
case DiffLineAdd:
compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx)
if compareDiffLine == nil {
return template.HTML(html.EscapeString(diffLine.Content))
}
diff1 = compareDiffLine.Content
diff2 = diffLine.Content
case DIFF_LINE_DEL:
compareDiffLine = diffSection.GetLine(DIFF_LINE_ADD, diffLine.LeftIdx)
case DiffLineDel:
compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx)
if compareDiffLine == nil {
return template.HTML(html.EscapeString(diffLine.Content))
}
@@ -185,6 +190,7 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem
return diffToHTML(diffRecord, diffLine.Type)
}
// DiffFile represents a file diff.
type DiffFile struct {
Name string
OldName string
@@ -200,26 +206,32 @@ type DiffFile struct {
IsIncomplete bool
}
// GetType returns type of diff file.
func (diffFile *DiffFile) GetType() int {
return int(diffFile.Type)
}
// GetHighlightClass returns highlight class for a filename.
func (diffFile *DiffFile) GetHighlightClass() string {
return highlight.FileNameToHighlightClass(diffFile.Name)
}
// Diff represents a difference between two git trees.
type Diff struct {
TotalAddition, TotalDeletion int
Files []*DiffFile
IsIncomplete bool
}
// NumFiles returns number of files changes in a diff.
func (diff *Diff) NumFiles() int {
return len(diff.Files)
}
const DIFF_HEAD = "diff --git "
const cmdDiffHead = "diff --git "
// ParsePatch builds a Diff object from a io.Reader and some
// parameters.
// TODO: move this function to gogits/git-module
func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*Diff, error) {
var (
@@ -266,7 +278,7 @@ func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*
switch {
case line[0] == ' ':
diffLine := &DiffLine{Type: DIFF_LINE_PLAIN, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
diffLine := &DiffLine{Type: DiffLinePlain, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
leftLine++
rightLine++
curSection.Lines = append(curSection.Lines, diffLine)
@@ -275,7 +287,7 @@ func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*
curSection = &DiffSection{}
curFile.Sections = append(curFile.Sections, curSection)
ss := strings.Split(line, "@@")
diffLine := &DiffLine{Type: DIFF_LINE_SECTION, Content: line}
diffLine := &DiffLine{Type: DiffLineSection, Content: line}
curSection.Lines = append(curSection.Lines, diffLine)
// Parse line number.
@@ -291,14 +303,14 @@ func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*
case line[0] == '+':
curFile.Addition++
diff.TotalAddition++
diffLine := &DiffLine{Type: DIFF_LINE_ADD, Content: line, RightIdx: rightLine}
diffLine := &DiffLine{Type: DiffLineAdd, Content: line, RightIdx: rightLine}
rightLine++
curSection.Lines = append(curSection.Lines, diffLine)
continue
case line[0] == '-':
curFile.Deletion++
diff.TotalDeletion++
diffLine := &DiffLine{Type: DIFF_LINE_DEL, Content: line, LeftIdx: leftLine}
diffLine := &DiffLine{Type: DiffLineDel, Content: line, LeftIdx: leftLine}
if leftLine > 0 {
leftLine++
}
@@ -309,19 +321,19 @@ func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*
}
// Get new file.
if strings.HasPrefix(line, DIFF_HEAD) {
if strings.HasPrefix(line, cmdDiffHead) {
middle := -1
// Note: In case file name is surrounded by double quotes (it happens only in git-shell).
// e.g. diff --git "a/xxx" "b/xxx"
hasQuote := line[len(DIFF_HEAD)] == '"'
hasQuote := line[len(cmdDiffHead)] == '"'
if hasQuote {
middle = strings.Index(line, ` "b/`)
} else {
middle = strings.Index(line, " b/")
}
beg := len(DIFF_HEAD)
beg := len(cmdDiffHead)
a := line[beg+2 : middle]
b := line[middle+3:]
if hasQuote {
@@ -332,7 +344,7 @@ func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*
curFile = &DiffFile{
Name: a,
Index: len(diff.Files) + 1,
Type: DIFF_FILE_CHANGE,
Type: DiffFileChange,
Sections: make([]*DiffSection, 0, 10),
}
diff.Files = append(diff.Files, curFile)
@@ -356,15 +368,15 @@ func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*
switch {
case strings.HasPrefix(line, "new file"):
curFile.Type = DIFF_FILE_ADD
curFile.Type = DiffFileAdd
curFile.IsCreated = true
case strings.HasPrefix(line, "deleted"):
curFile.Type = DIFF_FILE_DEL
curFile.Type = DiffFileDel
curFile.IsDeleted = true
case strings.HasPrefix(line, "index"):
curFile.Type = DIFF_FILE_CHANGE
curFile.Type = DiffFileChange
case strings.HasPrefix(line, "similarity index 100%"):
curFile.Type = DIFF_FILE_RENAME
curFile.Type = DiffFileRename
curFile.IsRenamed = true
curFile.OldName = curFile.Name
curFile.Name = b
@@ -407,6 +419,9 @@ func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*
return diff, nil
}
// GetDiffRange builds a Diff between two commits of a repository.
// passing the empty string as beforeCommitID returns a diff from the
// parent commit.
func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
@@ -458,11 +473,13 @@ func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxL
return diff, nil
}
// RawDiffType type of a raw diff.
type RawDiffType string
// RawDiffType possible values.
const (
RAW_DIFF_NORMAL RawDiffType = "diff"
RAW_DIFF_PATCH RawDiffType = "patch"
RawDiffNormal RawDiffType = "diff"
RawDiffPatch RawDiffType = "patch"
)
// GetRawDiff dumps diff results of repository in given commit ID to io.Writer.
@@ -480,14 +497,14 @@ func GetRawDiff(repoPath, commitID string, diffType RawDiffType, writer io.Write
var cmd *exec.Cmd
switch diffType {
case RAW_DIFF_NORMAL:
case RawDiffNormal:
if commit.ParentCount() == 0 {
cmd = exec.Command("git", "show", commitID)
} else {
c, _ := commit.Parent(0)
cmd = exec.Command("git", "diff", "-M", c.ID.String(), commitID)
}
case RAW_DIFF_PATCH:
case RawDiffPatch:
if commit.ParentCount() == 0 {
cmd = exec.Command("git", "format-patch", "--no-signature", "--stdout", "--root", commitID)
} else {
@@ -511,6 +528,7 @@ func GetRawDiff(repoPath, commitID string, diffType RawDiffType, writer io.Write
return nil
}
// GetDiffCommit builds a Diff representing the given commitID.
func GetDiffCommit(repoPath, commitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
return GetDiffRange(repoPath, "", commitID, maxLines, maxLineCharacteres, maxFiles)
}

View File

@@ -24,12 +24,12 @@ func TestDiffToHTML(t *testing.T) {
dmp.Diff{dmp.DiffInsert, "bar"},
dmp.Diff{dmp.DiffDelete, " baz"},
dmp.Diff{dmp.DiffEqual, " biz"},
}, DIFF_LINE_ADD))
}, DiffLineAdd))
assertEqual(t, "-foo <span class=\"removed-code\">bar</span> biz", diffToHTML([]dmp.Diff{
dmp.Diff{dmp.DiffEqual, "foo "},
dmp.Diff{dmp.DiffDelete, "bar"},
dmp.Diff{dmp.DiffInsert, " baz"},
dmp.Diff{dmp.DiffEqual, " biz"},
}, DIFF_LINE_DEL))
}, DiffLineDel))
}

View File

@@ -14,18 +14,18 @@ import (
"strings"
"time"
api "code.gitea.io/sdk/gitea"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
api "github.com/gogits/go-gogs-client"
gouuid "github.com/satori/go.uuid"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
var (
ErrMissingIssueNumber = errors.New("No issue number specified")
errMissingIssueNumber = errors.New("No issue number specified")
)
// Issue represents an issue or pull request of repository.
@@ -62,16 +62,20 @@ type Issue struct {
Comments []*Comment `xorm:"-"`
}
// BeforeInsert is invoked from XORM before inserting an object of this type.
func (issue *Issue) BeforeInsert() {
issue.CreatedUnix = time.Now().Unix()
issue.UpdatedUnix = issue.CreatedUnix
}
// BeforeUpdate is invoked from XORM before updating this object.
func (issue *Issue) BeforeUpdate() {
issue.UpdatedUnix = time.Now().Unix()
issue.DeadlineUnix = issue.Deadline.Unix()
}
// AfterSet is invoked from XORM after setting the value of a field of
// this object.
func (issue *Issue) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "deadline_unix":
@@ -83,23 +87,30 @@ 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)
if err != nil {
if IsErrUserNotExist(err) {
issue.PosterID = -1
issue.Poster = NewGhostUser()
} else {
issue.PosterID = -1
issue.Poster = NewGhostUser()
if !IsErrUserNotExist(err) {
return fmt.Errorf("getUserByID.(poster) [%d]: %v", issue.PosterID, err)
}
err = nil
return
}
}
@@ -150,10 +161,12 @@ func (issue *Issue) loadAttributes(e Engine) (err error) {
return nil
}
// LoadAttributes loads the attribute of this issue.
func (issue *Issue) LoadAttributes() error {
return issue.loadAttributes(x)
}
// HTMLURL returns the absolute URL to this issue.
func (issue *Issue) HTMLURL() string {
var path string
if issue.IsPull {
@@ -164,15 +177,31 @@ func (issue *Issue) HTMLURL() string {
return fmt.Sprintf("%s/%s/%d", issue.Repo.HTMLURL(), path, issue.Index)
}
// State returns string representation of issue status.
func (i *Issue) State() api.StateType {
if i.IsClosed {
return api.STATE_CLOSED
// 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 api.STATE_OPEN
return ""
}
// This method assumes some fields assigned with values:
// 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 {
return api.StateClosed
}
return api.StateOpen
}
// APIFormat assumes some fields assigned with values:
// Required - Poster, Labels,
// Optional - Milestone, Assignee, PullRequest
func (issue *Issue) APIFormat() *api.Issue {
@@ -213,22 +242,22 @@ func (issue *Issue) APIFormat() *api.Issue {
}
// HashTag returns unique hash tag for issue.
func (i *Issue) HashTag() string {
return "issue-" + com.ToStr(i.ID)
func (issue *Issue) HashTag() string {
return "issue-" + com.ToStr(issue.ID)
}
// IsPoster returns true if given user by ID is the poster.
func (i *Issue) IsPoster(uid int64) bool {
return i.PosterID == uid
func (issue *Issue) IsPoster(uid int64) bool {
return issue.PosterID == uid
}
func (i *Issue) hasLabel(e Engine, labelID int64) bool {
return hasIssueLabel(e, i.ID, labelID)
func (issue *Issue) hasLabel(e Engine, labelID int64) bool {
return hasIssueLabel(e, issue.ID, labelID)
}
// HasLabel returns true if issue has been labeled by given ID.
func (i *Issue) HasLabel(labelID int64) bool {
return i.hasLabel(x, labelID)
func (issue *Issue) HasLabel(labelID int64) bool {
return issue.hasLabel(x, labelID)
}
func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
@@ -239,11 +268,11 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
log.Error(4, "LoadIssue: %v", err)
return
}
err = PrepareWebhooks(issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
Action: api.HOOK_ISSUE_LABEL_UPDATED,
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
Action: api.HookIssueLabelUpdated,
Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(),
Repository: issue.Repo.APIFormat(nil),
Repository: issue.Repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
})
}
@@ -254,8 +283,8 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
}
}
func (i *Issue) addLabel(e *xorm.Session, label *Label) error {
return newIssueLabel(e, i, label)
func (issue *Issue) addLabel(e *xorm.Session, label *Label) error {
return newIssueLabel(e, issue, label)
}
// AddLabel adds a new label to the issue.
@@ -300,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
}
@@ -322,6 +361,8 @@ func (issue *Issue) clearLabels(e *xorm.Session) (err error) {
return nil
}
// ClearLabels removes all issue labels as the given user.
// Triggers appropriate WebHooks, if any.
func (issue *Issue) ClearLabels(doer *User) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
@@ -329,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
}
@@ -343,11 +394,11 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
log.Error(4, "LoadIssue: %v", err)
return
}
err = PrepareWebhooks(issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
Action: api.HOOK_ISSUE_LABEL_CLEARED,
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
Action: api.HookIssueLabelCleared,
Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(),
Repository: issue.Repo.APIFormat(nil),
Repository: issue.Repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
})
}
@@ -361,6 +412,7 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
}
// ReplaceLabels removes all current labels and add new labels to the issue.
// Triggers appropriate WebHooks, if any.
func (issue *Issue) ReplaceLabels(labels []*Label) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
@@ -377,12 +429,13 @@ func (issue *Issue) ReplaceLabels(labels []*Label) (err error) {
return sess.Commit()
}
func (i *Issue) GetAssignee() (err error) {
if i.AssigneeID == 0 || i.Assignee != nil {
// GetAssignee sets the Assignee attribute of this issue.
func (issue *Issue) GetAssignee() (err error) {
if issue.AssigneeID == 0 || issue.Assignee != nil {
return nil
}
i.Assignee, err = GetUserByID(i.AssigneeID)
issue.Assignee, err = GetUserByID(issue.AssigneeID)
if IsErrUserNotExist(err) {
return nil
}
@@ -390,8 +443,8 @@ func (i *Issue) GetAssignee() (err error) {
}
// ReadBy sets issue to be read by given user.
func (i *Issue) ReadBy(uid int64) error {
return UpdateIssueUserByRead(uid, i.ID)
func (issue *Issue) ReadBy(uid int64) error {
return UpdateIssueUserByRead(uid, issue.ID)
}
func updateIssueCols(e Engine, issue *Issue, cols ...string) error {
@@ -404,41 +457,41 @@ func UpdateIssueCols(issue *Issue, cols ...string) error {
return updateIssueCols(x, issue, cols...)
}
func (i *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository, isClosed bool) (err error) {
func (issue *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository, isClosed bool) (err error) {
// Nothing should be performed if current status is same as target status
if i.IsClosed == isClosed {
if issue.IsClosed == isClosed {
return nil
}
i.IsClosed = isClosed
issue.IsClosed = isClosed
if err = updateIssueCols(e, i, "is_closed"); err != nil {
if err = updateIssueCols(e, issue, "is_closed"); err != nil {
return err
} else if err = updateIssueUsersByStatus(e, i.ID, isClosed); err != nil {
} else if err = updateIssueUsersByStatus(e, issue.ID, isClosed); err != nil {
return err
}
// Update issue count of labels
if err = i.getLabels(e); err != nil {
if err = issue.getLabels(e); err != nil {
return err
}
for idx := range i.Labels {
if i.IsClosed {
i.Labels[idx].NumClosedIssues++
for idx := range issue.Labels {
if issue.IsClosed {
issue.Labels[idx].NumClosedIssues++
} else {
i.Labels[idx].NumClosedIssues--
issue.Labels[idx].NumClosedIssues--
}
if err = updateLabel(e, i.Labels[idx]); err != nil {
if err = updateLabel(e, issue.Labels[idx]); err != nil {
return err
}
}
// Update issue count of milestone
if err = changeMilestoneIssueStats(e, i); err != nil {
if err = changeMilestoneIssueStats(e, issue); err != nil {
return err
}
// New action comment
if _, err = createStatusComment(e, doer, repo, i); err != nil {
if _, err = createStatusComment(e, doer, repo, issue); err != nil {
return err
}
@@ -467,15 +520,15 @@ 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 {
apiPullRequest.Action = api.HOOK_ISSUE_CLOSED
apiPullRequest.Action = api.HookIssueClosed
} else {
apiPullRequest.Action = api.HOOK_ISSUE_REOPENED
apiPullRequest.Action = api.HookIssueReOpened
}
err = PrepareWebhooks(repo, HOOK_EVENT_PULL_REQUEST, apiPullRequest)
err = PrepareWebhooks(repo, HookEventPullRequest, apiPullRequest)
}
if err != nil {
log.Error(4, "PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
@@ -486,6 +539,7 @@ func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (e
return nil
}
// ChangeTitle changes the title of this issue, as the given user.
func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
oldTitle := issue.Title
issue.Title = title
@@ -495,8 +549,8 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
if issue.IsPull {
issue.PullRequest.Issue = issue
err = PrepareWebhooks(issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
Action: api.HOOK_ISSUE_EDITED,
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
Action: api.HookIssueEdited,
Index: issue.Index,
Changes: &api.ChangesPayload{
Title: &api.ChangesFromPayload{
@@ -504,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(),
})
}
@@ -517,6 +571,7 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
return nil
}
// ChangeContent changes issue content, as the given user.
func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
oldContent := issue.Content
issue.Content = content
@@ -526,8 +581,8 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
if issue.IsPull {
issue.PullRequest.Issue = issue
err = PrepareWebhooks(issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
Action: api.HOOK_ISSUE_EDITED,
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
Action: api.HookIssueEdited,
Index: issue.Index,
Changes: &api.ChangesPayload{
Body: &api.ChangesFromPayload{
@@ -535,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(),
})
}
@@ -548,6 +603,7 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
return nil
}
// ChangeAssignee changes the Asssignee field of this issue.
func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
issue.AssigneeID = assigneeID
if err = UpdateIssueUserByAssignee(issue); err != nil {
@@ -567,15 +623,15 @@ 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 {
apiPullRequest.Action = api.HOOK_ISSUE_UNASSIGNED
apiPullRequest.Action = api.HookIssueUnassigned
} else {
apiPullRequest.Action = api.HOOK_ISSUE_ASSIGNED
apiPullRequest.Action = api.HookIssueAssigned
}
err = PrepareWebhooks(issue.Repo, HOOK_EVENT_PULL_REQUEST, apiPullRequest)
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, apiPullRequest)
}
if err != nil {
log.Error(4, "PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, isRemoveAssignee, err)
@@ -586,6 +642,7 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
return nil
}
// NewIssueOptions represents the options of a new issue.
type NewIssueOptions struct {
Repo *Repository
Issue *Issue
@@ -624,7 +681,7 @@ func newIssue(e *xorm.Session, opts NewIssueOptions) (err error) {
// Assume assignee is invalid and drop silently.
opts.Issue.AssigneeID = 0
if assignee != nil {
valid, err := hasAccess(e, assignee, opts.Repo, ACCESS_MODE_WRITE)
valid, err := hasAccess(e, assignee, opts.Repo, AccessModeWrite)
if err != nil {
return fmt.Errorf("hasAccess [user_id: %d, repo_id: %d]: %v", assignee.ID, opts.Repo.ID, err)
}
@@ -650,7 +707,7 @@ func newIssue(e *xorm.Session, opts NewIssueOptions) (err error) {
}
if len(opts.LableIDs) > 0 {
// During the session, SQLite3 dirver cannot handle retrieve objects after update something.
// During the session, SQLite3 driver cannot handle retrieve objects after update something.
// So we have to get all needed labels first.
labels := make([]*Label, 0, len(opts.LableIDs))
if err = e.In("id", opts.LableIDs).Find(&labels); err != nil {
@@ -714,7 +771,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
if err = NotifyWatchers(&Action{
ActUserID: issue.Poster.ID,
ActUserName: issue.Poster.Name,
OpType: ACTION_CREATE_ISSUE,
OpType: ActionCreateIssue,
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title),
RepoID: repo.ID,
RepoUserName: repo.Owner.Name,
@@ -735,7 +792,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
func GetIssueByRef(ref string) (*Issue, error) {
n := strings.IndexByte(ref, byte('#'))
if n == -1 {
return nil, ErrMissingIssueNumber
return nil, errMissingIssueNumber
}
index, err := com.StrTo(ref[n+1:]).Int64()
@@ -756,7 +813,7 @@ func GetIssueByRef(ref string) (*Issue, error) {
return issue, issue.LoadAttributes()
}
// GetIssueByIndex returns raw issue without loading attributes by index in a repository.
// GetRawIssueByIndex returns raw issue without loading attributes by index in a repository.
func GetRawIssueByIndex(repoID, index int64) (*Issue, error) {
issue := &Issue{
RepoID: repoID,
@@ -796,6 +853,7 @@ func GetIssueByID(id int64) (*Issue, error) {
return getIssueByID(x, id)
}
// IssuesOptions represents options of an issue.
type IssuesOptions struct {
UserID int64
AssigneeID int64
@@ -820,16 +878,12 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
sess := x.Limit(setting.UI.IssuePagingNum, (opts.Page-1)*setting.UI.IssuePagingNum)
if opts.RepoID > 0 {
sess.Where("issue.repo_id=?", opts.RepoID).And("issue.is_closed=?", opts.IsClosed)
} else if opts.RepoIDs != nil {
sess.And("issue.repo_id=?", opts.RepoID)
} else if len(opts.RepoIDs) > 0 {
// In case repository IDs are provided but actually no repository has issue.
if len(opts.RepoIDs) == 0 {
return make([]*Issue, 0), nil
}
sess.In("issue.repo_id", base.Int64sToStrings(opts.RepoIDs)).And("issue.is_closed=?", opts.IsClosed)
} else {
sess.Where("issue.is_closed=?", opts.IsClosed)
sess.In("issue.repo_id", opts.RepoIDs)
}
sess.And("issue.is_closed=?", opts.IsClosed)
if opts.AssigneeID > 0 {
sess.And("issue.assignee_id=?", opts.AssigneeID)
@@ -861,14 +915,21 @@ 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").In("issue_label.label_id", labelIDs)
sess.
Join("INNER", "issue_label", "issue.id = issue_label.issue_id").
In("issue_label.label_id", labelIDs)
}
}
if opts.IsMention {
sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").And("issue_user.is_mentioned = ?", true)
sess.
Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
And("issue_user.is_mentioned = ?", true)
if opts.UserID > 0 {
sess.And("issue_user.uid = ?", opts.UserID)
@@ -967,9 +1028,9 @@ func NewIssueUsers(repo *Repository, issue *Issue) (err error) {
}
// PairsContains returns true when pairs list contains given issue.
func PairsContains(ius []*IssueUser, issueId, uid int64) int {
func PairsContains(ius []*IssueUser, issueID, uid int64) int {
for i := range ius {
if ius[i].IssueID == issueId &&
if ius[i].IssueID == issueID &&
ius[i].UID == uid {
return i
}
@@ -991,7 +1052,10 @@ func GetIssueUserPairsByRepoIds(rids []int64, isClosed bool, page int) ([]*Issue
}
ius := make([]*IssueUser, 0, 10)
sess := x.Limit(20, (page-1)*20).Where("is_closed=?", isClosed).In("repo_id", rids)
sess := x.
Limit(20, (page-1)*20).
Where("is_closed=?", isClosed).
In("repo_id", rids)
err := sess.Find(&ius)
return ius, err
}
@@ -999,15 +1063,18 @@ func GetIssueUserPairsByRepoIds(rids []int64, isClosed bool, page int) ([]*Issue
// GetIssueUserPairsByMode returns issue-user pairs by given repository and user.
func GetIssueUserPairsByMode(uid, rid int64, isClosed bool, page, filterMode int) ([]*IssueUser, error) {
ius := make([]*IssueUser, 0, 10)
sess := x.Limit(20, (page-1)*20).Where("uid=?", uid).And("is_closed=?", isClosed)
sess := x.
Limit(20, (page-1)*20).
Where("uid=?", uid).
And("is_closed=?", isClosed)
if rid > 0 {
sess.And("repo_id=?", rid)
}
switch filterMode {
case FM_ASSIGN:
case FilterModeAssign:
sess.And("is_assigned=?", true)
case FM_CREATE:
case FilterModeCreate:
sess.And("is_poster=?", true)
default:
return ius, nil
@@ -1018,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
}
@@ -1028,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)
}
@@ -1052,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)
}
@@ -1070,10 +1137,10 @@ type IssueStats struct {
// Filter modes.
const (
FM_ALL = iota
FM_ASSIGN
FM_CREATE
FM_MENTION
FilterModeAll = iota
FilterModeAssign
FilterModeCreate
FilterModeMention
)
func parseCountResult(results []map[string][]byte) int64 {
@@ -1086,6 +1153,7 @@ func parseCountResult(results []map[string][]byte) int64 {
return 0
}
// IssueStatsOptions contains parameters accepted by GetIssueStats.
type IssueStatsOptions struct {
RepoID int64
UserID int64
@@ -1101,12 +1169,17 @@ func GetIssueStats(opts *IssueStatsOptions) *IssueStats {
stats := &IssueStats{}
countSession := func(opts *IssueStatsOptions) *xorm.Session {
sess := x.Where("issue.repo_id = ?", opts.RepoID).And("is_pull = ?", opts.IsPull)
sess := x.
Where("issue.repo_id = ?", opts.RepoID).
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").In("label_id", labelIDs)
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)
}
}
@@ -1122,7 +1195,7 @@ func GetIssueStats(opts *IssueStatsOptions) *IssueStats {
}
switch opts.FilterMode {
case FM_ALL, FM_ASSIGN:
case FilterModeAll, FilterModeAssign:
stats.OpenCount, _ = countSession(opts).
And("is_closed = ?", false).
Count(&Issue{})
@@ -1130,7 +1203,7 @@ func GetIssueStats(opts *IssueStatsOptions) *IssueStats {
stats.ClosedCount, _ = countSession(opts).
And("is_closed = ?", true).
Count(&Issue{})
case FM_CREATE:
case FilterModeCreate:
stats.OpenCount, _ = countSession(opts).
And("poster_id = ?", opts.UserID).
And("is_closed = ?", false).
@@ -1140,7 +1213,7 @@ func GetIssueStats(opts *IssueStatsOptions) *IssueStats {
And("poster_id = ?", opts.UserID).
And("is_closed = ?", true).
Count(&Issue{})
case FM_MENTION:
case FilterModeMention:
stats.OpenCount, _ = countSession(opts).
Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
And("issue_user.uid = ?", opts.UserID).
@@ -1163,11 +1236,13 @@ func GetUserIssueStats(repoID, uid int64, repoIDs []int64, filterMode int, isPul
stats := &IssueStats{}
countSession := func(isClosed, isPull bool, repoID int64, repoIDs []int64) *xorm.Session {
sess := x.Where("issue.is_closed = ?", isClosed).And("issue.is_pull = ?", isPull)
sess := x.
Where("issue.is_closed = ?", isClosed).
And("issue.is_pull = ?", isPull)
if repoID > 0 || len(repoIDs) == 0 {
if repoID > 0 {
sess.And("repo_id = ?", repoID)
} else {
} else if len(repoIDs) > 0 {
sess.In("repo_id", repoIDs)
}
@@ -1186,10 +1261,10 @@ func GetUserIssueStats(repoID, uid int64, repoIDs []int64, filterMode int, isPul
closedCountSession := countSession(true, isPull, repoID, repoIDs)
switch filterMode {
case FM_ASSIGN:
case FilterModeAssign:
openCountSession.And("assignee_id = ?", uid)
closedCountSession.And("assignee_id = ?", uid)
case FM_CREATE:
case FilterModeCreate:
openCountSession.And("poster_id = ?", uid)
closedCountSession.And("poster_id = ?", uid)
}
@@ -1203,7 +1278,8 @@ func GetUserIssueStats(repoID, uid int64, repoIDs []int64, filterMode int, isPul
// GetRepoIssueStats returns number of open and closed repository issues by given filter mode.
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).
sess := x.
Where("is_closed = ?", isClosed).
And("is_pull = ?", isPull).
And("repo_id = ?", repoID)
@@ -1214,10 +1290,10 @@ func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen
closedCountSession := countSession(true, isPull, repoID)
switch filterMode {
case FM_ASSIGN:
case FilterModeAssign:
openCountSession.And("assignee_id = ?", uid)
closedCountSession.And("assignee_id = ?", uid)
case FM_CREATE:
case FilterModeCreate:
openCountSession.And("poster_id = ?", uid)
closedCountSession.And("poster_id = ?", uid)
}
@@ -1285,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
@@ -1337,10 +1413,12 @@ type Milestone struct {
ClosedDateUnix int64
}
// BeforeInsert is invoked from XORM before inserting an object of this type.
func (m *Milestone) BeforeInsert() {
m.DeadlineUnix = m.Deadline.Unix()
}
// BeforeUpdate is invoked from XORM before updating this object.
func (m *Milestone) BeforeUpdate() {
if m.NumIssues > 0 {
m.Completeness = m.NumClosedIssues * 100 / m.NumIssues
@@ -1352,6 +1430,8 @@ func (m *Milestone) BeforeUpdate() {
m.ClosedDateUnix = m.ClosedDate.Unix()
}
// AfterSet is invoked from XORM after setting the value of a field of
// this object.
func (m *Milestone) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "num_closed_issues":
@@ -1376,11 +1456,12 @@ func (m *Milestone) AfterSet(colName string, _ xorm.Cell) {
// State returns string representation of milestone status.
func (m *Milestone) State() api.StateType {
if m.IsClosed {
return api.STATE_CLOSED
return api.StateClosed
}
return api.STATE_OPEN
return api.StateOpen
}
// APIFormat returns this Milestone in API format.
func (m *Milestone) APIFormat() *api.Milestone {
apiMilestone := &api.Milestone{
ID: m.ID,
@@ -1431,7 +1512,7 @@ func getMilestoneByRepoID(e Engine, repoID, id int64) (*Milestone, error) {
return m, nil
}
// GetWebhookByRepoID returns the milestone in a repository.
// GetMilestoneByRepoID returns the milestone in a repository.
func GetMilestoneByRepoID(repoID, id int64) (*Milestone, error) {
return getMilestoneByRepoID(x, repoID, id)
}
@@ -1463,7 +1544,9 @@ func UpdateMilestone(m *Milestone) error {
}
func countRepoMilestones(e Engine, repoID int64) int64 {
count, _ := e.Where("repo_id=?", repoID).Count(new(Milestone))
count, _ := e.
Where("repo_id=?", repoID).
Count(new(Milestone))
return count
}
@@ -1473,7 +1556,9 @@ func CountRepoMilestones(repoID int64) int64 {
}
func countRepoClosedMilestones(e Engine, repoID int64) int64 {
closed, _ := e.Where("repo_id=? AND is_closed=?", repoID, true).Count(new(Milestone))
closed, _ := e.
Where("repo_id=? AND is_closed=?", repoID, true).
Count(new(Milestone))
return closed
}
@@ -1484,7 +1569,9 @@ func CountRepoClosedMilestones(repoID int64) int64 {
// MilestoneStats returns number of open and closed milestones of given repository.
func MilestoneStats(repoID int64) (open int64, closed int64) {
open, _ = x.Where("repo_id=? AND is_closed=?", repoID, false).Count(new(Milestone))
open, _ = x.
Where("repo_id=? AND is_closed=?", repoID, false).
Count(new(Milestone))
return open, CountRepoClosedMilestones(repoID)
}
@@ -1657,10 +1744,13 @@ type Attachment struct {
CreatedUnix int64
}
// BeforeInsert is invoked from XORM before inserting an object of this type.
func (a *Attachment) BeforeInsert() {
a.CreatedUnix = time.Now().Unix()
}
// AfterSet is invoked from XORM after setting the value of a field of
// this object.
func (a *Attachment) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
@@ -1668,14 +1758,15 @@ func (a *Attachment) AfterSet(colName string, _ xorm.Cell) {
}
}
// AttachmentLocalPath returns where attachment is stored in local file system based on given UUID.
// AttachmentLocalPath returns where attachment is stored in local file
// system based on given UUID.
func AttachmentLocalPath(uuid string) string {
return path.Join(setting.AttachmentPath, uuid[0:1], uuid[1:2], uuid)
}
// LocalPath returns where attachment is stored in local file system.
func (attach *Attachment) LocalPath() string {
return AttachmentLocalPath(attach.UUID)
func (a *Attachment) LocalPath() string {
return AttachmentLocalPath(a.UUID)
}
// NewAttachment creates a new attachment object.
@@ -1775,8 +1866,8 @@ func DeleteAttachments(attachments []*Attachment, remove bool) (int, error) {
}
// DeleteAttachmentsByIssue deletes all attachments associated with the given issue.
func DeleteAttachmentsByIssue(issueId int64, remove bool) (int, error) {
attachments, err := GetAttachmentsByIssueID(issueId)
func DeleteAttachmentsByIssue(issueID int64, remove bool) (int, error) {
attachments, err := GetAttachmentsByIssueID(issueID)
if err != nil {
return 0, err
@@ -1786,8 +1877,8 @@ func DeleteAttachmentsByIssue(issueId int64, remove bool) (int, error) {
}
// DeleteAttachmentsByComment deletes all attachments associated with the given comment.
func DeleteAttachmentsByComment(commentId int64, remove bool) (int, error) {
attachments, err := GetAttachmentsByCommentID(commentId)
func DeleteAttachmentsByComment(commentID int64, remove bool) (int, error) {
attachments, err := GetAttachmentsByCommentID(commentID)
if err != nil {
return 0, err

View File

@@ -12,38 +12,41 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
api "github.com/gogits/go-gogs-client"
api "code.gitea.io/sdk/gitea"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markdown"
)
// CommentType defines whether a comment is just a simple comment, an action (like close) or a reference.
type CommentType int
// Enumerate all the comment types
const (
// Plain comment, can be associated with a commit (CommitID > 0) and a line (LineNum > 0)
COMMENT_TYPE_COMMENT CommentType = iota
COMMENT_TYPE_REOPEN
COMMENT_TYPE_CLOSE
CommentTypeComment CommentType = iota
CommentTypeReopen
CommentTypeClose
// References.
COMMENT_TYPE_ISSUE_REF
CommentTypeIssueRef
// Reference from a commit (not part of a pull request)
COMMENT_TYPE_COMMIT_REF
CommentTypeCommitRef
// Reference from a comment
COMMENT_TYPE_COMMENT_REF
CommentTypeCommentRef
// Reference from a pull request
COMMENT_TYPE_PULL_REF
CommentTypePullRef
)
// CommentTag defines comment tag type
type CommentTag int
// Enumerate all the comment tag types
const (
COMMENT_TAG_NONE CommentTag = iota
COMMENT_TAG_POSTER
COMMENT_TAG_WRITER
COMMENT_TAG_OWNER
CommentTagNone CommentTag = iota
CommentTagPoster
CommentTagWriter
CommentTagOwner
)
// Comment represents a comment in commit and issue page.
@@ -72,15 +75,19 @@ type Comment struct {
ShowTag CommentTag `xorm:"-"`
}
// BeforeInsert will be invoked by XORM before inserting a record
// representing this object.
func (c *Comment) BeforeInsert() {
c.CreatedUnix = time.Now().Unix()
c.UpdatedUnix = c.CreatedUnix
}
// BeforeUpdate is invoked from XORM before updating this object.
func (c *Comment) BeforeUpdate() {
c.UpdatedUnix = time.Now().Unix()
}
// AfterSet is invoked from XORM after setting the value of a field of this object.
func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
var err error
switch colName {
@@ -107,6 +114,7 @@ func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
}
}
// AfterDelete is invoked from XORM after the object is deleted.
func (c *Comment) AfterDelete() {
_, err := DeleteAttachmentsByComment(c.ID, true)
@@ -115,13 +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,
}
}
@@ -137,21 +187,21 @@ func (c *Comment) EventTag() string {
// MailParticipants sends new comment emails to repository watchers
// and mentioned people.
func (cmt *Comment) MailParticipants(opType ActionType, issue *Issue) (err error) {
mentions := markdown.FindAllMentions(cmt.Content)
if err = UpdateIssueMentions(cmt.IssueID, mentions); err != nil {
return fmt.Errorf("UpdateIssueMentions [%d]: %v", cmt.IssueID, err)
func (c *Comment) MailParticipants(e Engine, opType ActionType, issue *Issue) (err error) {
mentions := markdown.FindAllMentions(c.Content)
if err = UpdateIssueMentions(e, c.IssueID, mentions); err != nil {
return fmt.Errorf("UpdateIssueMentions [%d]: %v", c.IssueID, err)
}
switch opType {
case ACTION_COMMENT_ISSUE:
issue.Content = cmt.Content
case ACTION_CLOSE_ISSUE:
case ActionCommentIssue:
issue.Content = c.Content
case ActionCloseIssue:
issue.Content = fmt.Sprintf("Closed #%d", issue.Index)
case ACTION_REOPEN_ISSUE:
case ActionReopenIssue:
issue.Content = fmt.Sprintf("Reopened #%d", issue.Index)
}
if err = mailIssueCommentToParticipants(issue, cmt.Poster, mentions); err != nil {
if err = mailIssueCommentToParticipants(issue, c.Poster, mentions); err != nil {
log.Error(4, "mailIssueCommentToParticipants: %v", err)
}
@@ -187,8 +237,8 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
// Check comment type.
switch opts.Type {
case COMMENT_TYPE_COMMENT:
act.OpType = ACTION_COMMENT_ISSUE
case CommentTypeComment:
act.OpType = ActionCommentIssue
if _, err = e.Exec("UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil {
return nil, err
@@ -216,10 +266,10 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
}
}
case COMMENT_TYPE_REOPEN:
act.OpType = ACTION_REOPEN_ISSUE
case CommentTypeReopen:
act.OpType = ActionReopenIssue
if opts.Issue.IsPull {
act.OpType = ACTION_REOPEN_PULL_REQUEST
act.OpType = ActionReopenPullRequest
}
if opts.Issue.IsPull {
@@ -231,10 +281,10 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
return nil, err
}
case COMMENT_TYPE_CLOSE:
act.OpType = ACTION_CLOSE_ISSUE
case CommentTypeClose:
act.OpType = ActionCloseIssue
if opts.Issue.IsPull {
act.OpType = ACTION_CLOSE_PULL_REQUEST
act.OpType = ActionClosePullRequest
}
if opts.Issue.IsPull {
@@ -253,16 +303,18 @@ 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
}
func createStatusComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue) (*Comment, error) {
cmtType := COMMENT_TYPE_CLOSE
cmtType := CommentTypeClose
if !issue.IsClosed {
cmtType = COMMENT_TYPE_REOPEN
cmtType = CommentTypeReopen
}
return createComment(e, &CreateCommentOptions{
Type: cmtType,
@@ -272,6 +324,7 @@ func createStatusComment(e *xorm.Session, doer *User, repo *Repository, issue *I
})
}
// CreateCommentOptions defines options for creating comment
type CreateCommentOptions struct {
Type CommentType
Doer *User
@@ -304,7 +357,7 @@ func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) {
// CreateIssueComment creates a plain issue comment.
func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content string, attachments []string) (*Comment, error) {
return CreateComment(&CreateCommentOptions{
Type: COMMENT_TYPE_COMMENT,
Type: CommentTypeComment,
Doer: doer,
Repo: repo,
Issue: issue,
@@ -321,7 +374,7 @@ func CreateRefComment(doer *User, repo *Repository, issue *Issue, content, commi
// Check if same reference from same commit has already existed.
has, err := x.Get(&Comment{
Type: COMMENT_TYPE_COMMIT_REF,
Type: CommentTypeCommitRef,
IssueID: issue.ID,
CommitSHA: commitSHA,
})
@@ -332,7 +385,7 @@ func CreateRefComment(doer *User, repo *Repository, issue *Issue, content, commi
}
_, err = CreateComment(&CreateCommentOptions{
Type: COMMENT_TYPE_COMMIT_REF,
Type: CommentTypeCommitRef,
Doer: doer,
Repo: repo,
Issue: issue,
@@ -356,7 +409,18 @@ func GetCommentByID(id int64) (*Comment, error) {
func getCommentsByIssueIDSince(e Engine, issueID, since int64) ([]*Comment, error) {
comments := make([]*Comment, 0, 10)
sess := e.Where("issue_id = ?", issueID).Asc("created_unix")
sess := e.
Where("issue_id = ?", issueID).
Asc("created_unix")
if since > 0 {
sess.And("updated_unix >= ?", since)
}
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)
}
@@ -372,11 +436,16 @@ func GetCommentsByIssueID(issueID int64) ([]*Comment, error) {
return getCommentsByIssueID(x, issueID)
}
// GetCommentsByIssueID returns a list of comments of an issue since a given time point.
// GetCommentsByIssueIDSince returns a list of comments of an issue since a given time point.
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)
@@ -403,7 +472,7 @@ func DeleteCommentByID(id int64) error {
return err
}
if comment.Type == COMMENT_TYPE_COMMENT {
if comment.Type == CommentTypeComment {
if _, err = sess.Exec("UPDATE `issue` SET num_comments = num_comments - 1 WHERE id = ?", comment.IssueID); err != nil {
return err
}

View File

@@ -13,9 +13,7 @@ import (
"github.com/go-xorm/xorm"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/base"
api "code.gitea.io/sdk/gitea"
)
var labelColorPattern = regexp.MustCompile("#([a-fA-F0-9]{6})")
@@ -64,11 +62,12 @@ type Label struct {
IsChecked bool `xorm:"-"`
}
// APIFormat converts a Label to the api.Label format
func (label *Label) APIFormat() *api.Label {
return &api.Label{
ID: label.ID,
Name: label.Name,
Color: label.Color,
Color: strings.TrimLeft(label.Color, "#"),
}
}
@@ -79,9 +78,9 @@ func (label *Label) CalOpenIssues() {
// ForegroundColor calculates the text color for labels based
// on their background color.
func (l *Label) ForegroundColor() template.CSS {
if strings.HasPrefix(l.Color, "#") {
if color, err := strconv.ParseUint(l.Color[1:], 16, 64); err == nil {
func (label *Label) ForegroundColor() template.CSS {
if strings.HasPrefix(label.Color, "#") {
if color, err := strconv.ParseUint(label.Color[1:], 16, 64); err == nil {
r := float32(0xFF & (color >> 16))
g := float32(0xFF & (color >> 8))
b := float32(0xFF & color)
@@ -103,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.
@@ -129,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)
@@ -138,13 +163,20 @@ func GetLabelInRepoByID(repoID, labelID int64) (*Label, error) {
// it silently ignores label IDs that are not belong to the repository.
func GetLabelsInRepoByIDs(repoID int64, labelIDs []int64) ([]*Label, error) {
labels := make([]*Label, 0, len(labelIDs))
return labels, x.Where("repo_id = ?", repoID).In("id", base.Int64sToStrings(labelIDs)).Asc("name").Find(&labels)
return labels, x.
Where("repo_id = ?", repoID).
In("id", labelIDs).
Asc("name").
Find(&labels)
}
// GetLabelsByRepoID returns all labels that belong to given repository by ID.
func GetLabelsByRepoID(repoID int64) ([]*Label, error) {
labels := make([]*Label, 0, 10)
return labels, x.Where("repo_id = ?", repoID).Asc("name").Find(&labels)
return labels, x.
Where("repo_id = ?", repoID).
Asc("name").
Find(&labels)
}
func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) {
@@ -161,7 +193,11 @@ func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) {
}
labels := make([]*Label, 0, len(labelIDs))
return labels, e.Where("id > 0").In("id", base.Int64sToStrings(labelIDs)).Asc("name").Find(&labels)
return labels, e.
Where("id > 0").
In("id", labelIDs).
Asc("name").
Find(&labels)
}
// GetLabelsByIssueID returns all labels that belong to given issue by ID.
@@ -197,7 +233,9 @@ func DeleteLabel(repoID, labelID int64) error {
if _, err = sess.Id(labelID).Delete(new(Label)); err != nil {
return err
} else if _, err = sess.Where("label_id = ?", labelID).Delete(new(IssueLabel)); err != nil {
} else if _, err = sess.
Where("label_id = ?", labelID).
Delete(new(IssueLabel)); err != nil {
return err
}
@@ -293,7 +331,10 @@ func NewIssueLabels(issue *Issue, labels []*Label) (err error) {
func getIssueLabels(e Engine, issueID int64) ([]*IssueLabel, error) {
issueLabels := make([]*IssueLabel, 0, 10)
return issueLabels, e.Where("issue_id=?", issueID).Asc("label_id").Find(&issueLabels)
return issueLabels, e.
Where("issue_id=?", issueID).
Asc("label_id").
Find(&issueLabels)
}
// GetIssueLabels returns all issue-label relations of given issue by ID.

View File

@@ -9,12 +9,12 @@ import (
"github.com/Unknwon/com"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markdown"
"code.gitea.io/gitea/modules/setting"
)
func (issue *Issue) MailSubject() string {
func (issue *Issue) mailSubject() string {
return fmt.Sprintf("[%s] %s (#%d)", issue.Repo.Name, issue.Title, issue.Index)
}
@@ -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

@@ -19,34 +19,37 @@ import (
"github.com/go-xorm/core"
"github.com/go-xorm/xorm"
"github.com/gogits/gogs/modules/auth/ldap"
"github.com/gogits/gogs/modules/auth/pam"
"github.com/gogits/gogs/modules/log"
"code.gitea.io/gitea/modules/auth/ldap"
"code.gitea.io/gitea/modules/auth/pam"
"code.gitea.io/gitea/modules/log"
)
// LoginType represents an login type.
type LoginType int
// Note: new type must append to the end of list to maintain compatibility.
const (
LOGIN_NOTYPE LoginType = iota
LOGIN_PLAIN // 1
LOGIN_LDAP // 2
LOGIN_SMTP // 3
LOGIN_PAM // 4
LOGIN_DLDAP // 5
LoginNoType LoginType = iota
LoginPlain // 1
LoginLDAP // 2
LoginSMTP // 3
LoginPAM // 4
LoginDLDAP // 5
)
// LoginNames contains the name of LoginType values.
var LoginNames = map[LoginType]string{
LOGIN_LDAP: "LDAP (via BindDN)",
LOGIN_DLDAP: "LDAP (simple auth)", // Via direct bind
LOGIN_SMTP: "SMTP",
LOGIN_PAM: "PAM",
LoginLDAP: "LDAP (via BindDN)",
LoginDLDAP: "LDAP (simple auth)", // Via direct bind
LoginSMTP: "SMTP",
LoginPAM: "PAM",
}
// SecurityProtocolNames contains the name of SecurityProtocol values.
var SecurityProtocolNames = map[ldap.SecurityProtocol]string{
ldap.SECURITY_PROTOCOL_UNENCRYPTED: "Unencrypted",
ldap.SECURITY_PROTOCOL_LDAPS: "LDAPS",
ldap.SECURITY_PROTOCOL_START_TLS: "StartTLS",
ldap.SecurityProtocolUnencrypted: "Unencrypted",
ldap.SecurityProtocolLDAPS: "LDAPS",
ldap.SecurityProtocolStartTLS: "StartTLS",
}
// Ensure structs implemented interface.
@@ -56,22 +59,28 @@ var (
_ core.Conversion = &PAMConfig{}
)
// LDAPConfig holds configuration for LDAP login source.
type LDAPConfig struct {
*ldap.Source
}
// FromDB fills up a LDAPConfig from serialized format.
func (cfg *LDAPConfig) FromDB(bs []byte) error {
return json.Unmarshal(bs, &cfg)
}
// ToDB exports a LDAPConfig to a serialized format.
func (cfg *LDAPConfig) ToDB() ([]byte, error) {
return json.Marshal(cfg)
}
// SecurityProtocolName returns the name of configured security
// protocol.
func (cfg *LDAPConfig) SecurityProtocolName() string {
return SecurityProtocolNames[cfg.SecurityProtocol]
}
// SMTPConfig holds configuration for the SMTP login source.
type SMTPConfig struct {
Auth string
Host string
@@ -81,22 +90,27 @@ type SMTPConfig struct {
SkipVerify bool
}
// FromDB fills up an SMTPConfig from serialized format.
func (cfg *SMTPConfig) FromDB(bs []byte) error {
return json.Unmarshal(bs, cfg)
}
// ToDB exports an SMTPConfig to a serialized format.
func (cfg *SMTPConfig) ToDB() ([]byte, error) {
return json.Marshal(cfg)
}
// PAMConfig holds configuration for the PAM login source.
type PAMConfig struct {
ServiceName string // pam service (e.g. system-auth)
}
// FromDB fills up a PAMConfig from serialized format.
func (cfg *PAMConfig) FromDB(bs []byte) error {
return json.Unmarshal(bs, &cfg)
}
// ToDB exports a PAMConfig to a serialized format.
func (cfg *PAMConfig) ToDB() ([]byte, error) {
return json.Marshal(cfg)
}
@@ -115,13 +129,15 @@ type LoginSource struct {
UpdatedUnix int64
}
func (s *LoginSource) BeforeInsert() {
s.CreatedUnix = time.Now().Unix()
s.UpdatedUnix = s.CreatedUnix
// BeforeInsert is invoked from XORM before inserting an object of this type.
func (source *LoginSource) BeforeInsert() {
source.CreatedUnix = time.Now().Unix()
source.UpdatedUnix = source.CreatedUnix
}
func (s *LoginSource) BeforeUpdate() {
s.UpdatedUnix = time.Now().Unix()
// BeforeUpdate is invoked from XORM before updating this object.
func (source *LoginSource) BeforeUpdate() {
source.UpdatedUnix = time.Now().Unix()
}
// Cell2Int64 converts a xorm.Cell type to int64,
@@ -135,15 +151,16 @@ func Cell2Int64(val xorm.Cell) int64 {
return (*val).(int64)
}
// BeforeSet is invoked from XORM before setting the value of a field of this object.
func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
switch colName {
case "type":
switch LoginType(Cell2Int64(val)) {
case LOGIN_LDAP, LOGIN_DLDAP:
case LoginLDAP, LoginDLDAP:
source.Cfg = new(LDAPConfig)
case LOGIN_SMTP:
case LoginSMTP:
source.Cfg = new(SMTPConfig)
case LOGIN_PAM:
case LoginPAM:
source.Cfg = new(PAMConfig)
default:
panic("unrecognized login source type: " + com.ToStr(*val))
@@ -151,74 +168,90 @@ func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
}
}
func (s *LoginSource) AfterSet(colName string, _ xorm.Cell) {
// AfterSet is invoked from XORM after setting the value of a field of this object.
func (source *LoginSource) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
s.Created = time.Unix(s.CreatedUnix, 0).Local()
source.Created = time.Unix(source.CreatedUnix, 0).Local()
case "updated_unix":
s.Updated = time.Unix(s.UpdatedUnix, 0).Local()
source.Updated = time.Unix(source.UpdatedUnix, 0).Local()
}
}
// TypeName return name of this login source type.
func (source *LoginSource) TypeName() string {
return LoginNames[source.Type]
}
// IsLDAP returns true of this source is of the LDAP type.
func (source *LoginSource) IsLDAP() bool {
return source.Type == LOGIN_LDAP
return source.Type == LoginLDAP
}
// IsDLDAP returns true of this source is of the DLDAP type.
func (source *LoginSource) IsDLDAP() bool {
return source.Type == LOGIN_DLDAP
return source.Type == LoginDLDAP
}
// IsSMTP returns true of this source is of the SMTP type.
func (source *LoginSource) IsSMTP() bool {
return source.Type == LOGIN_SMTP
return source.Type == LoginSMTP
}
// IsPAM returns true of this source is of the PAM type.
func (source *LoginSource) IsPAM() bool {
return source.Type == LOGIN_PAM
return source.Type == LoginPAM
}
// HasTLS returns true of this source supports TLS.
func (source *LoginSource) HasTLS() bool {
return ((source.IsLDAP() || source.IsDLDAP()) &&
source.LDAP().SecurityProtocol > ldap.SECURITY_PROTOCOL_UNENCRYPTED) ||
source.LDAP().SecurityProtocol > ldap.SecurityProtocolUnencrypted) ||
source.IsSMTP()
}
// UseTLS returns true of this source is configured to use TLS.
func (source *LoginSource) UseTLS() bool {
switch source.Type {
case LOGIN_LDAP, LOGIN_DLDAP:
return source.LDAP().SecurityProtocol != ldap.SECURITY_PROTOCOL_UNENCRYPTED
case LOGIN_SMTP:
case LoginLDAP, LoginDLDAP:
return source.LDAP().SecurityProtocol != ldap.SecurityProtocolUnencrypted
case LoginSMTP:
return source.SMTP().TLS
}
return false
}
// SkipVerify returns true if this source is configured to skip SSL
// verification.
func (source *LoginSource) SkipVerify() bool {
switch source.Type {
case LOGIN_LDAP, LOGIN_DLDAP:
case LoginLDAP, LoginDLDAP:
return source.LDAP().SkipVerify
case LOGIN_SMTP:
case LoginSMTP:
return source.SMTP().SkipVerify
}
return false
}
// LDAP returns LDAPConfig for this source, if of LDAP type.
func (source *LoginSource) LDAP() *LDAPConfig {
return source.Cfg.(*LDAPConfig)
}
// SMTP returns SMTPConfig for this source, if of SMTP type.
func (source *LoginSource) SMTP() *SMTPConfig {
return source.Cfg.(*SMTPConfig)
}
// PAM returns PAMConfig for this source, if of PAM type.
func (source *LoginSource) PAM() *PAMConfig {
return source.Cfg.(*PAMConfig)
}
// CreateLoginSource inserts a LoginSource in the DB if not already
// existing with the given name.
func CreateLoginSource(source *LoginSource) error {
has, err := x.Get(&LoginSource{Name: source.Name})
if err != nil {
@@ -231,6 +264,7 @@ func CreateLoginSource(source *LoginSource) error {
return err
}
// LoginSources returns a slice of all login sources found in DB.
func LoginSources() ([]*LoginSource, error) {
auths := make([]*LoginSource, 0, 5)
return auths, x.Find(&auths)
@@ -248,11 +282,13 @@ func GetLoginSourceByID(id int64) (*LoginSource, error) {
return source, nil
}
// UpdateSource updates a LoginSource record in DB.
func UpdateSource(source *LoginSource) error {
_, err := x.Id(source.ID).AllCols().Update(source)
return err
}
// DeleteSource deletes a LoginSource record in DB.
func DeleteSource(source *LoginSource) error {
count, err := x.Count(&User{LoginSource: source.ID})
if err != nil {
@@ -292,11 +328,11 @@ func composeFullName(firstname, surname, username string) string {
// LoginViaLDAP queries if login/password is valid against the LDAP directory pool,
// and create a local user if success when enabled.
func LoginViaLDAP(user *User, login, passowrd string, source *LoginSource, autoRegister bool) (*User, error) {
username, fn, sn, mail, isAdmin, succeed := source.Cfg.(*LDAPConfig).SearchEntry(login, passowrd, source.Type == LOGIN_DLDAP)
func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoRegister bool) (*User, error) {
username, fn, sn, mail, isAdmin, succeed := source.Cfg.(*LDAPConfig).SearchEntry(login, password, source.Type == LoginDLDAP)
if !succeed {
// User not in LDAP, do nothing
return nil, ErrUserNotExist{0, login}
return nil, ErrUserNotExist{0, login, 0}
}
if !autoRegister {
@@ -357,13 +393,16 @@ func (auth *smtpLoginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
return nil, nil
}
// SMTP authentication type names.
const (
SMTP_PLAIN = "PLAIN"
SMTP_LOGIN = "LOGIN"
SMTPPlain = "PLAIN"
SMTPLogin = "LOGIN"
)
var SMTPAuths = []string{SMTP_PLAIN, SMTP_LOGIN}
// SMTPAuths contains available SMTP authentication type names.
var SMTPAuths = []string{SMTPPlain, SMTPLogin}
// SMTPAuth performs an SMTP authentication.
func SMTPAuth(a smtp.Auth, cfg *SMTPConfig) error {
c, err := smtp.Dial(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port))
if err != nil {
@@ -404,16 +443,16 @@ func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPC
if len(cfg.AllowedDomains) > 0 {
idx := strings.Index(login, "@")
if idx == -1 {
return nil, ErrUserNotExist{0, login}
return nil, ErrUserNotExist{0, login, 0}
} else if !com.IsSliceContainsStr(strings.Split(cfg.AllowedDomains, ","), login[idx+1:]) {
return nil, ErrUserNotExist{0, login}
return nil, ErrUserNotExist{0, login, 0}
}
}
var auth smtp.Auth
if cfg.Auth == SMTP_PLAIN {
if cfg.Auth == SMTPPlain {
auth = smtp.PlainAuth("", login, password, cfg.Host)
} else if cfg.Auth == SMTP_LOGIN {
} else if cfg.Auth == SMTPLogin {
auth = &smtpLoginAuth{login, password}
} else {
return nil, errors.New("Unsupported SMTP auth type")
@@ -425,7 +464,7 @@ func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPC
tperr, ok := err.(*textproto.Error)
if (ok && tperr.Code == 535) ||
strings.Contains(err.Error(), "Username and Password not accepted") {
return nil, ErrUserNotExist{0, login}
return nil, ErrUserNotExist{0, login, 0}
}
return nil, err
}
@@ -445,7 +484,7 @@ func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPC
Name: strings.ToLower(username),
Email: login,
Passwd: password,
LoginType: LOGIN_SMTP,
LoginType: LoginSMTP,
LoginSource: sourceID,
LoginName: login,
IsActive: true,
@@ -463,9 +502,9 @@ func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPC
// LoginViaPAM queries if login/password is valid against the PAM,
// and create a local user if success when enabled.
func LoginViaPAM(user *User, login, password string, sourceID int64, cfg *PAMConfig, autoRegister bool) (*User, error) {
if err := pam.PAMAuth(cfg.ServiceName, login, password); err != nil {
if err := pam.Auth(cfg.ServiceName, login, password); err != nil {
if strings.Contains(err.Error(), "Authentication failure") {
return nil, ErrUserNotExist{0, login}
return nil, ErrUserNotExist{0, login, 0}
}
return nil, err
}
@@ -479,7 +518,7 @@ func LoginViaPAM(user *User, login, password string, sourceID int64, cfg *PAMCon
Name: login,
Email: login,
Passwd: password,
LoginType: LOGIN_PAM,
LoginType: LoginPAM,
LoginSource: sourceID,
LoginName: login,
IsActive: true,
@@ -487,17 +526,18 @@ func LoginViaPAM(user *User, login, password string, sourceID int64, cfg *PAMCon
return user, CreateUser(user)
}
// ExternalUserLogin attempts a login using external source types.
func ExternalUserLogin(user *User, login, password string, source *LoginSource, autoRegister bool) (*User, error) {
if !source.IsActived {
return nil, ErrLoginSourceNotActived
}
switch source.Type {
case LOGIN_LDAP, LOGIN_DLDAP:
case LoginLDAP, LoginDLDAP:
return LoginViaLDAP(user, login, password, source, autoRegister)
case LOGIN_SMTP:
case LoginSMTP:
return LoginViaSMTP(user, login, password, source.ID, source.Cfg.(*SMTPConfig), autoRegister)
case LOGIN_PAM:
case LoginPAM:
return LoginViaPAM(user, login, password, source.ID, source.Cfg.(*PAMConfig), autoRegister)
}
@@ -505,12 +545,12 @@ func ExternalUserLogin(user *User, login, password string, source *LoginSource,
}
// UserSignIn validates user name and password.
func UserSignIn(username, passowrd string) (*User, error) {
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)
@@ -520,12 +560,12 @@ func UserSignIn(username, passowrd string) (*User, error) {
if hasUser {
switch user.LoginType {
case LOGIN_NOTYPE, LOGIN_PLAIN:
if user.ValidatePassword(passowrd) {
case LoginNoType, LoginPlain:
if user.ValidatePassword(password) {
return user, nil
}
return nil, ErrUserNotExist{user.ID, user.Name}
return nil, ErrUserNotExist{user.ID, user.Name, 0}
default:
var source LoginSource
@@ -536,7 +576,7 @@ func UserSignIn(username, passowrd string) (*User, error) {
return nil, ErrLoginSourceNotExist{user.LoginSource}
}
return ExternalUserLogin(user, user.LoginName, passowrd, &source, false)
return ExternalUserLogin(user, user.LoginName, password, &source, false)
}
}
@@ -546,7 +586,7 @@ func UserSignIn(username, passowrd string) (*User, error) {
}
for _, source := range sources {
authUser, err := ExternalUserLogin(nil, username, passowrd, source, true)
authUser, err := ExternalUserLogin(nil, username, password, source, true)
if err == nil {
return authUser, nil
}
@@ -554,5 +594,5 @@ func UserSignIn(username, passowrd string) (*User, error) {
log.Warn("Failed to login '%s' via '%s': %v", username, source.Name, err)
}
return nil, ErrUserNotExist{user.ID, user.Name}
return nil, ErrUserNotExist{user.ID, user.Name, 0}
}

View File

@@ -5,58 +5,45 @@
package models
import (
"bytes"
"fmt"
"html/template"
"path"
"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"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/mailer"
"github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting"
)
const (
MAIL_AUTH_ACTIVATE base.TplName = "auth/activate"
MAIL_AUTH_ACTIVATE_EMAIL base.TplName = "auth/activate_email"
MAIL_AUTH_RESET_PASSWORD base.TplName = "auth/reset_passwd"
MAIL_AUTH_REGISTER_NOTIFY base.TplName = "auth/register_notify"
mailAuthActivate base.TplName = "auth/activate"
mailAuthActivateEmail base.TplName = "auth/activate_email"
mailAuthResetPassword base.TplName = "auth/reset_passwd"
mailAuthRegisterNotify base.TplName = "auth/register_notify"
MAIL_ISSUE_COMMENT base.TplName = "issue/comment"
MAIL_ISSUE_MENTION base.TplName = "issue/mention"
mailIssueComment base.TplName = "issue/comment"
mailIssueMention base.TplName = "issue/mention"
MAIL_NOTIFY_COLLABORATOR base.TplName = "notify/collaborator"
mailNotifyCollaborator base.TplName = "notify/collaborator"
)
type MailRender interface {
HTMLString(string, interface{}, ...macaron.HTMLOptions) (string, error)
}
var mailRender MailRender
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,
}
var templates *template.Template
// InitMailRender initializes the macaron mail renderer
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
func SendUserMail(c *macaron.Context, u *User, tpl base.TplName, code, subject, info string) {
data := map[string]interface{}{
"Username": u.DisplayName(),
@@ -64,27 +51,31 @@ 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)
}
// SendActivateAccountMail sends an activation mail to the user
func SendActivateAccountMail(c *macaron.Context, u *User) {
SendUserMail(c, u, MAIL_AUTH_ACTIVATE, u.GenerateActivateCode(), c.Tr("mail.activate_account"), "activate account")
SendUserMail(c, u, mailAuthActivate, u.GenerateActivateCode(), c.Tr("mail.activate_account"), "activate account")
}
// SendResetPasswordMail sends a password reset mail to the user
func SendResetPasswordMail(c *macaron.Context, u *User) {
SendUserMail(c, u, MAIL_AUTH_RESET_PASSWORD, u.GenerateActivateCode(), c.Tr("mail.reset_password"), "reset password")
SendUserMail(c, u, mailAuthResetPassword, u.GenerateActivateCode(), c.Tr("mail.reset_password"), "reset password")
}
// SendActivateAccountMail sends confirmation email.
// SendActivateEmailMail sends confirmation email.
func SendActivateEmailMail(c *macaron.Context, u *User, email *EmailAddress) {
data := map[string]interface{}{
"Username": u.DisplayName(),
@@ -92,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(MAIL_AUTH_ACTIVATE_EMAIL), 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)
@@ -109,13 +102,15 @@ func SendRegisterNotifyMail(c *macaron.Context, u *User) {
data := map[string]interface{}{
"Username": u.DisplayName(),
}
body, err := mailRender.HTMLString(string(MAIL_AUTH_REGISTER_NOTIFY), 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)
@@ -131,13 +126,15 @@ func SendCollaboratorMail(u, doer *User, repo *Repository) {
"RepoName": repoName,
"Link": repo.HTMLURL(),
}
body, err := mailRender.HTMLString(string(MAIL_NOTIFY_COLLABORATOR), 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)
@@ -152,15 +149,18 @@ func composeTplData(subject, body, link string) map[string]interface{} {
}
func composeIssueMessage(issue *Issue, doer *User, tplName base.TplName, tos []string, info string) *mailer.Message {
subject := issue.MailSubject()
subject := issue.mailSubject()
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.User), 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
}
@@ -171,7 +171,7 @@ func SendIssueCommentMail(issue *Issue, doer *User, tos []string) {
return
}
mailer.SendAsync(composeIssueMessage(issue, doer, MAIL_ISSUE_COMMENT, tos, "issue comment"))
mailer.SendAsync(composeIssueMessage(issue, doer, mailIssueComment, tos, "issue comment"))
}
// SendIssueMentionMail composes and sends issue mention emails to target receivers.
@@ -179,5 +179,5 @@ func SendIssueMentionMail(issue *Issue, doer *User, tos []string) {
if len(tos) == 0 {
return
}
mailer.SendAsync(composeIssueMessage(issue, doer, MAIL_ISSUE_MENTION, tos, "issue mention"))
mailer.SendAsync(composeIssueMessage(issue, doer, mailIssueMention, tos, "issue mention"))
}

View File

@@ -20,13 +20,14 @@ import (
gouuid "github.com/satori/go.uuid"
"gopkg.in/ini.v1"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
const _MIN_DB_VER = 4
const minDBVersion = 4
// Migration describes on migration from lower version to high version
type Migration interface {
Description() string
Migrate(*xorm.Engine) error
@@ -37,19 +38,22 @@ type migration struct {
migrate func(*xorm.Engine) error
}
// NewMigration creates a new migration
func NewMigration(desc string, fn func(*xorm.Engine) error) Migration {
return &migration{desc, fn}
}
// Description returns the migration's description
func (m *migration) Description() string {
return m.description
}
// Migrate executes the migration
func (m *migration) Migrate(x *xorm.Engine) error {
return m.migrate(x)
}
// The version table. Should have only one row with id==1
// Version describes the version table. Should have only one row with id==1
type Version struct {
ID int64 `xorm:"pk autoincr"`
Version int64
@@ -57,11 +61,11 @@ type Version struct {
// This is a sequence of migrations. Add new migrations to the bottom of the list.
// If you want to "retire" a migration, remove it from the top of the list and
// update _MIN_VER_DB accordingly
// update minDBVersion accordingly
var migrations = []Migration{
// v0 -> v4: before 0.6.0 -> 0.7.33
NewMigration("fix locale file load panic", fixLocaleFileLoadPanic), // V4 -> V5:v0.6.0
NewMigration("trim action compare URL prefix", trimCommitActionAppUrlPrefix), // V5 -> V6:v0.6.3
NewMigration("trim action compare URL prefix", trimCommitActionAppURLPrefix), // V5 -> V6:v0.6.3
NewMigration("generate issue-label from issue", issueToIssueLabel), // V6 -> V7:v0.6.4
NewMigration("refactor attachment table", attachmentRefactor), // V7 -> V8:v0.6.4
NewMigration("rename pull request fields", renamePullRequestFields), // V8 -> V9:v0.6.16
@@ -72,6 +76,8 @@ var migrations = []Migration{
// v13 -> v14:v0.9.87
NewMigration("set comment updated with created", setCommentUpdatedWithCreated),
NewMigration("create user column diff view style", createUserColumnDiffViewStyle),
}
// Migrate database to current version
@@ -87,7 +93,7 @@ func Migrate(x *xorm.Engine) error {
} else if !has {
// If the version record does not exist we think
// it is a fresh installation and we can skip all migrations.
currentVersion.Version = int64(_MIN_DB_VER + len(migrations))
currentVersion.Version = int64(minDBVersion + len(migrations))
if _, err = x.InsertOne(currentVersion); err != nil {
return fmt.Errorf("insert: %v", err)
@@ -95,19 +101,19 @@ func Migrate(x *xorm.Engine) error {
}
v := currentVersion.Version
if _MIN_DB_VER > v {
log.Fatal(4, `Gogs no longer supports auto-migration from your previously installed version.
if minDBVersion > v {
log.Fatal(4, `Gogs no longer supports auto-migration from your previously installed version.
Please try to upgrade to a lower version (>= v0.6.0) first, then upgrade to current version.`)
return nil
}
if int(v-_MIN_DB_VER) > len(migrations) {
if int(v-minDBVersion) > len(migrations) {
// User downgraded Gogs.
currentVersion.Version = int64(len(migrations) + _MIN_DB_VER)
currentVersion.Version = int64(len(migrations) + minDBVersion)
_, err = x.Id(1).Update(currentVersion)
return err
}
for i, m := range migrations[v-_MIN_DB_VER:] {
for i, m := range migrations[v-minDBVersion:] {
log.Info("Migration: %s", m.Description())
if err = m.Migrate(x); err != nil {
return fmt.Errorf("do migrate: %v", err)
@@ -142,7 +148,7 @@ func fixLocaleFileLoadPanic(_ *xorm.Engine) error {
return nil
}
func trimCommitActionAppUrlPrefix(x *xorm.Engine) error {
func trimCommitActionAppURLPrefix(x *xorm.Engine) error {
type PushCommit struct {
Sha1 string
Message string
@@ -153,7 +159,7 @@ func trimCommitActionAppUrlPrefix(x *xorm.Engine) error {
type PushCommits struct {
Len int
Commits []*PushCommit
CompareUrl string
CompareURL string `json:"CompareUrl"`
}
type Action struct {
@@ -184,11 +190,11 @@ func trimCommitActionAppUrlPrefix(x *xorm.Engine) error {
return fmt.Errorf("unmarshal action content[%d]: %v", actID, err)
}
infos := strings.Split(pushCommits.CompareUrl, "/")
infos := strings.Split(pushCommits.CompareURL, "/")
if len(infos) <= 4 {
continue
}
pushCommits.CompareUrl = strings.Join(infos[len(infos)-4:], "/")
pushCommits.CompareURL = strings.Join(infos[len(infos)-4:], "/")
p, err := json.Marshal(pushCommits)
if err != nil {
@@ -451,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
}
@@ -461,27 +471,34 @@ func generateOrgRandsAndSalt(x *xorm.Engine) (err error) {
return sess.Commit()
}
// TAction defines the struct for migrating table action
type TAction struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TAction) TableName() string { return "action" }
// TNotice defines the struct for migrating table notice
type TNotice struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TNotice) TableName() string { return "notice" }
// TComment defines the struct for migrating table comment
type TComment struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TComment) TableName() string { return "comment" }
// TIssue defines the struct for migrating table issue
type TIssue struct {
ID int64 `xorm:"pk autoincr"`
DeadlineUnix int64
@@ -489,99 +506,124 @@ type TIssue struct {
UpdatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TIssue) TableName() string { return "issue" }
// TMilestone defines the struct for migrating table milestone
type TMilestone struct {
ID int64 `xorm:"pk autoincr"`
DeadlineUnix int64
ClosedDateUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TMilestone) TableName() string { return "milestone" }
// TAttachment defines the struct for migrating table attachment
type TAttachment struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TAttachment) TableName() string { return "attachment" }
// TLoginSource defines the struct for migrating table login_source
type TLoginSource struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TLoginSource) TableName() string { return "login_source" }
// TPull defines the struct for migrating table pull_request
type TPull struct {
ID int64 `xorm:"pk autoincr"`
MergedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TPull) TableName() string { return "pull_request" }
// TRelease defines the struct for migrating table release
type TRelease struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TRelease) TableName() string { return "release" }
// TRepo defines the struct for migrating table repository
type TRepo struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TRepo) TableName() string { return "repository" }
// TMirror defines the struct for migrating table mirror
type TMirror struct {
ID int64 `xorm:"pk autoincr"`
UpdatedUnix int64
NextUpdateUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TMirror) TableName() string { return "mirror" }
// TPublicKey defines the struct for migrating table public_key
type TPublicKey struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TPublicKey) TableName() string { return "public_key" }
// TDeployKey defines the struct for migrating table deploy_key
type TDeployKey struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TDeployKey) TableName() string { return "deploy_key" }
// TAccessToken defines the struct for migrating table access_token
type TAccessToken struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TAccessToken) TableName() string { return "access_token" }
// TUser defines the struct for migrating table user
type TUser struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TUser) TableName() string { return "user" }
// TWebhook defines the struct for migrating table webhook
type TWebhook struct {
ID int64 `xorm:"pk autoincr"`
CreatedUnix int64
UpdatedUnix int64
}
// TableName will be invoked by XORM to customrize the table name
func (t *TWebhook) TableName() string { return "webhook" }
func convertDateToUnix(x *xorm.Engine) (err error) {
@@ -628,7 +670,7 @@ func convertDateToUnix(x *xorm.Engine) (err error) {
offset := 0
for {
beans := make([]*Bean, 0, 100)
if err = x.Sql(fmt.Sprintf("SELECT * FROM `%s` ORDER BY id ASC LIMIT 100 OFFSET %d",
if err = x.SQL(fmt.Sprintf("SELECT * FROM `%s` ORDER BY id ASC LIMIT 100 OFFSET %d",
table.name, offset)).Find(&beans); err != nil {
return fmt.Errorf("select beans [table: %s, offset: %d]: %v", table.name, offset, err)
}

View File

@@ -22,3 +22,17 @@ func setCommentUpdatedWithCreated(x *xorm.Engine) (err error) {
}
return nil
}
// UserV14 describes the added fields for migrating from v13 -> v14
type UserV14 struct {
DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"`
}
// TableName will be invoked by XORM to customrize the table name
func (*UserV14) TableName() string {
return "user"
}
func createUserColumnDiffViewStyle(x *xorm.Engine) error {
return x.Sync2(new(UserV14))
}

View File

@@ -13,13 +13,16 @@ import (
"path"
"strings"
// Needed for the MySQL driver
_ "github.com/go-sql-driver/mysql"
"github.com/go-xorm/core"
"github.com/go-xorm/xorm"
// Needed for the Postgresql driver
_ "github.com/lib/pq"
"github.com/gogits/gogs/models/migrations"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/models/migrations"
"code.gitea.io/gitea/modules/setting"
)
// Engine represents a xorm engine or session.
@@ -33,7 +36,7 @@ type Engine interface {
Insert(...interface{}) (int64, error)
InsertOne(interface{}) (int64, error)
Iterate(interface{}, xorm.IterFunc) error
Sql(string, ...interface{}) *xorm.Session
SQL(interface{}, ...interface{}) *xorm.Session
Where(interface{}, ...interface{}) *xorm.Session
}
@@ -45,16 +48,22 @@ func sessionRelease(sess *xorm.Session) {
}
var (
x *xorm.Engine
tables []interface{}
x *xorm.Engine
tables []interface{}
// HasEngine specifies if we have a xorm.Engine
HasEngine bool
// DbCfg holds the database settings
DbCfg struct {
Type, Host, Name, User, Passwd, Path, SSLMode string
}
// EnableSQLite3 use SQLite3
EnableSQLite3 bool
EnableTiDB bool
// EnableTiDB enable TiDB
EnableTiDB bool
)
func init() {
@@ -69,12 +78,13 @@ func init() {
new(Team), new(OrgUser), new(TeamUser), new(TeamRepo),
new(Notice), new(EmailAddress))
gonicNames := []string{"SSL"}
gonicNames := []string{"SSL", "UID"}
for _, name := range gonicNames {
core.LintGonicMapper[name] = true
}
}
// LoadConfigs loads the database settings
func LoadConfigs() {
sec := setting.Cfg.Section("database")
DbCfg.Type = sec.Key("DB_TYPE").String()
@@ -95,7 +105,7 @@ func LoadConfigs() {
DbCfg.Passwd = sec.Key("PASSWD").String()
}
DbCfg.SSLMode = sec.Key("SSL_MODE").String()
DbCfg.Path = sec.Key("PATH").MustString("data/gogs.db")
DbCfg.Path = sec.Key("PATH").MustString("data/gitea.db")
}
// parsePostgreSQLHostPort parses given input in various forms defined in
@@ -115,7 +125,7 @@ func parsePostgreSQLHostPort(info string) (string, string) {
func getEngine() (*xorm.Engine, error) {
connStr := ""
var Param string = "?"
var Param = "?"
if strings.Contains(DbCfg.Name, Param) {
Param = "&"
}
@@ -139,7 +149,7 @@ func getEngine() (*xorm.Engine, error) {
}
case "sqlite3":
if !EnableSQLite3 {
return nil, errors.New("This binary version does not build support for SQLite3.")
return nil, errors.New("this binary version does not build support for SQLite3")
}
if err := os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm); err != nil {
return nil, fmt.Errorf("Fail to create directories: %v", err)
@@ -147,7 +157,7 @@ func getEngine() (*xorm.Engine, error) {
connStr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc"
case "tidb":
if !EnableTiDB {
return nil, errors.New("This binary version does not build support for TiDB.")
return nil, errors.New("this binary version does not build support for TiDB")
}
if err := os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm); err != nil {
return nil, fmt.Errorf("Fail to create directories: %v", err)
@@ -159,6 +169,7 @@ func getEngine() (*xorm.Engine, error) {
return xorm.NewEngine(DbCfg.Type, connStr)
}
// NewTestEngine sets a new test xorm.Engine
func NewTestEngine(x *xorm.Engine) (err error) {
x, err = getEngine()
if err != nil {
@@ -169,6 +180,7 @@ func NewTestEngine(x *xorm.Engine) (err error) {
return x.StoreEngine("InnoDB").Sync2(tables...)
}
// SetEngine sets the xorm.Engine
func SetEngine() (err error) {
x, err = getEngine()
if err != nil {
@@ -180,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 {
@@ -191,22 +206,28 @@ func SetEngine() (err error) {
return nil
}
// NewEngine initializes a new xorm.Engine
func NewEngine() (err error) {
if err = SetEngine(); err != nil {
return err
}
if err = x.Ping(); err != nil {
return err
}
if err = migrations.Migrate(x); err != nil {
return fmt.Errorf("migrate: %v", err)
}
if err = x.StoreEngine("InnoDB").Sync2(tables...); err != nil {
return fmt.Errorf("sync database struct error: %v\n", err)
return fmt.Errorf("sync database struct error: %v", err)
}
return nil
}
// Statistic contains the database statistics
type Statistic struct {
Counter struct {
User, Org, PublicKey,
@@ -218,6 +239,7 @@ type Statistic struct {
}
}
// GetStatistic returns the database statistics
func GetStatistic() (stats Statistic) {
stats.Counter.User = CountUsers()
stats.Counter.Org = CountOrganizations()
@@ -244,6 +266,7 @@ func GetStatistic() (stats Statistic) {
return
}
// Ping tests if database is alive
func Ping() error {
return x.Ping()
}

View File

@@ -1,4 +1,4 @@
// +build tidb go1.4.2
// +build tidb
// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style

View File

@@ -10,14 +10,14 @@ import (
"os"
"strings"
"github.com/go-xorm/builder"
"github.com/go-xorm/xorm"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
)
var (
ErrOrgNotExist = errors.New("Organization does not exist")
// ErrOrgNotExist organization does not exist
ErrOrgNotExist = errors.New("Organization does not exist")
// ErrTeamNotExist team does not exist
ErrTeamNotExist = errors.New("Team does not exist")
)
@@ -41,7 +41,7 @@ func (org *User) GetTeam(name string) (*Team, error) {
}
func (org *User) getOwnerTeam(e Engine) (*Team, error) {
return org.getTeam(e, OWNER_TEAM)
return org.getTeam(e, ownerTeamName)
}
// GetOwnerTeam returns owner team of organization.
@@ -50,7 +50,10 @@ func (org *User) GetOwnerTeam() (*Team, error) {
}
func (org *User) getTeams(e Engine) error {
return e.Where("org_id=?", org.ID).Find(&org.Teams)
return e.
Where("org_id=?", org.ID).
OrderBy("CASE WHEN name LIKE '" + ownerTeamName + "' THEN '' ELSE name END").
Find(&org.Teams)
}
// GetTeams returns all teams that belong to organization.
@@ -65,14 +68,12 @@ func (org *User) GetMembers() error {
return err
}
org.Members = make([]*User, len(ous))
var ids = make([]int64, len(ous))
for i, ou := range ous {
org.Members[i], err = GetUserByID(ou.Uid)
if err != nil {
return err
}
ids[i] = ou.UID
}
return nil
org.Members, err = GetUsersByIDs(ids)
return err
}
// AddMember adds new member to organization.
@@ -108,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
@@ -128,7 +133,7 @@ func CreateOrganization(org, owner *User) (err error) {
// Add initial creator to organization and owner team.
if _, err = sess.Insert(&OrgUser{
Uid: owner.ID,
UID: owner.ID,
OrgID: org.ID,
IsOwner: true,
NumTeams: 1,
@@ -139,9 +144,9 @@ func CreateOrganization(org, owner *User) (err error) {
// Create default owner team.
t := &Team{
OrgID: org.ID,
LowerName: strings.ToLower(OWNER_TEAM),
Name: OWNER_TEAM,
Authorize: ACCESS_MODE_OWNER,
LowerName: strings.ToLower(ownerTeamName),
Name: ownerTeamName,
Authorize: AccessModeOwner,
NumMembers: 1,
}
if _, err = sess.Insert(t); err != nil {
@@ -149,7 +154,7 @@ func CreateOrganization(org, owner *User) (err error) {
}
if _, err = sess.Insert(&TeamUser{
Uid: owner.ID,
UID: owner.ID,
OrgID: org.ID,
TeamID: t.ID,
}); err != nil {
@@ -170,7 +175,7 @@ func GetOrgByName(name string) (*User, error) {
}
u := &User{
LowerName: strings.ToLower(name),
Type: USER_TYPE_ORGANIZATION,
Type: UserTypeOrganization,
}
has, err := x.Get(u)
if err != nil {
@@ -183,24 +188,27 @@ func GetOrgByName(name string) (*User, error) {
// CountOrganizations returns number of organizations.
func CountOrganizations() int64 {
count, _ := x.Where("type=1").Count(new(User))
count, _ := x.
Where("type=1").
Count(new(User))
return count
}
// Organizations returns number of organizations in given page.
func Organizations(page, pageSize int) ([]*User, error) {
orgs := make([]*User, 0, pageSize)
return orgs, x.Limit(pageSize, (page-1)*pageSize).Where("type=1").Asc("id").Find(&orgs)
return orgs, x.
Limit(pageSize, (page-1)*pageSize).
Where("type=1").
Asc("name").
Find(&orgs)
}
// 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
}
@@ -217,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()
}
// ________ ____ ___
@@ -230,7 +242,7 @@ func DeleteOrganization(org *User) (err error) {
// OrgUser represents an organization-user relation.
type OrgUser struct {
ID int64 `xorm:"pk autoincr"`
Uid int64 `xorm:"INDEX UNIQUE(s)"`
UID int64 `xorm:"INDEX UNIQUE(s)"`
OrgID int64 `xorm:"INDEX UNIQUE(s)"`
IsPublic bool
IsOwner bool
@@ -238,20 +250,31 @@ type OrgUser struct {
}
// IsOrganizationOwner returns true if given user is in the owner team.
func IsOrganizationOwner(orgId, uid int64) bool {
has, _ := x.Where("is_owner=?", true).And("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
func IsOrganizationOwner(orgID, uid int64) bool {
has, _ := x.
Where("is_owner=?", true).
And("uid=?", uid).
And("org_id=?", orgID).
Get(new(OrgUser))
return has
}
// IsOrganizationMember returns true if given user is member of organization.
func IsOrganizationMember(orgId, uid int64) bool {
has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
func IsOrganizationMember(orgID, uid int64) bool {
has, _ := x.
Where("uid=?", uid).
And("org_id=?", orgID).
Get(new(OrgUser))
return has
}
// IsPublicMembership returns true if given user public his/her membership.
func IsPublicMembership(orgId, uid int64) bool {
has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("is_public=?", true).Get(new(OrgUser))
func IsPublicMembership(orgID, uid int64) bool {
has, _ := x.
Where("uid=?", uid).
And("org_id=?", orgID).
And("is_public=?", true).
Get(new(OrgUser))
return has
}
@@ -260,8 +283,11 @@ func getOrgsByUserID(sess *xorm.Session, userID int64, showAll bool) ([]*User, e
if !showAll {
sess.And("`org_user`.is_public=?", true)
}
return orgs, sess.And("`org_user`.uid=?", userID).
Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
return orgs, sess.
And("`org_user`.uid=?", userID).
Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").
Asc("`user`.name").
Find(&orgs)
}
// GetOrgsByUserID returns a list of organizations that the given user ID
@@ -278,8 +304,12 @@ func GetOrgsByUserIDDesc(userID int64, desc string, showAll bool) ([]*User, erro
func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
orgs := make([]*User, 0, 10)
return orgs, sess.Where("`org_user`.uid=?", userID).And("`org_user`.is_owner=?", true).
Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
return orgs, sess.
Where("`org_user`.uid=?", userID).
And("`org_user`.is_owner=?", true).
Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").
Asc("`user`.name").
Find(&orgs)
}
// GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
@@ -288,7 +318,7 @@ func GetOwnedOrgsByUserID(userID int64) ([]*User, error) {
return getOwnedOrgsByUserID(sess, userID)
}
// GetOwnedOrganizationsByUserIDDesc returns a list of organizations are owned by
// GetOwnedOrgsByUserIDDesc returns a list of organizations are owned by
// given user ID, ordered descending by the given condition.
func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
sess := x.NewSession()
@@ -298,26 +328,35 @@ func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
// GetOrgUsersByUserID returns all organization-user relations by user ID.
func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
ous := make([]*OrgUser, 0, 10)
sess := x.Where("uid=?", uid)
sess := x.
Join("LEFT", "user", "`org_user`.org_id=`user`.id").
Where("`org_user`.uid=?", uid)
if !all {
// Only show public organizations
sess.And("is_public=?", true)
}
err := sess.Find(&ous)
err := sess.
Asc("`user`.name").
Find(&ous)
return ous, err
}
// GetOrgUsersByOrgID returns all organization-user relations by organization ID.
func GetOrgUsersByOrgID(orgID int64) ([]*OrgUser, error) {
ous := make([]*OrgUser, 0, 10)
err := x.Where("org_id=?", orgID).Find(&ous)
err := x.
Where("org_id=?", orgID).
Find(&ous)
return ous, err
}
// ChangeOrgUserStatus changes public or private membership status.
func ChangeOrgUserStatus(orgID, uid int64, public bool) error {
ou := new(OrgUser)
has, err := x.Where("uid=?", uid).And("org_id=?", orgID).Get(ou)
has, err := x.
Where("uid=?", uid).
And("org_id=?", orgID).
Get(ou)
if err != nil {
return err
} else if !has {
@@ -342,7 +381,7 @@ func AddOrgUser(orgID, uid int64) error {
}
ou := &OrgUser{
Uid: uid,
UID: uid,
OrgID: orgID,
}
@@ -361,7 +400,10 @@ func AddOrgUser(orgID, uid int64) error {
func RemoveOrgUser(orgID, userID int64) error {
ou := new(OrgUser)
has, err := x.Where("uid=?", userID).And("org_id=?", orgID).Get(ou)
has, err := x.
Where("uid=?", userID).
And("org_id=?", orgID).
Get(ou)
if err != nil {
return fmt.Errorf("get org-user: %v", err)
} else if !has {
@@ -416,7 +458,10 @@ func RemoveOrgUser(orgID, userID int64) error {
}
if len(repoIDs) > 0 {
if _, err = sess.Where("user_id = ?", user.ID).In("repo_id", repoIDs).Delete(new(Access)); err != nil {
if _, err = sess.
Where("user_id = ?", user.ID).
In("repo_id", repoIDs).
Delete(new(Access)); err != nil {
return err
}
}
@@ -450,13 +495,17 @@ func RemoveOrgRepo(orgID, repoID int64) error {
func (org *User) getUserTeams(e Engine, userID int64, cols ...string) ([]*Team, error) {
teams := make([]*Team, 0, org.NumTeams)
return teams, e.Where("team_user.org_id = ?", org.ID).
And("team_user.uid = ?", userID).
Join("INNER", "team_user", "team_user.team_id = team.id").
Cols(cols...).Find(&teams)
return teams, e.
Where("`team_user`.org_id = ?", org.ID).
Join("INNER", "team_user", "`team_user`.team_id = team.id").
Join("INNER", "user", "`user`.id=team_user.uid").
And("`team_user`.uid = ?", userID).
Asc("`user`.name").
Cols(cols...).
Find(&teams)
}
// GetUserTeamIDs returns of all team IDs of the organization that user is memeber of.
// GetUserTeamIDs returns of all team IDs of the organization that user is member of.
func (org *User) GetUserTeamIDs(userID int64) ([]int64, error) {
teams, err := org.getUserTeams(x, userID, "team.id")
if err != nil {
@@ -470,7 +519,7 @@ func (org *User) GetUserTeamIDs(userID int64) ([]int64, error) {
return teamIDs, nil
}
// GetTeams returns all teams that belong to organization,
// GetUserTeams returns all teams that belong to user,
// and that the user has joined.
func (org *User) GetUserTeams(userID int64) ([]*Team, error) {
return org.getUserTeams(x, userID)
@@ -493,35 +542,32 @@ func (org *User) GetUserRepositories(userID int64, page, pageSize int) ([]*Repos
page = 1
}
repos := make([]*Repository, 0, pageSize)
// FIXME: use XORM chain operations instead of raw SQL.
if err = x.Sql(fmt.Sprintf(`SELECT repository.* FROM repository
INNER JOIN team_repo
ON team_repo.repo_id = repository.id
WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (%s)
GROUP BY repository.id
ORDER BY updated_unix DESC
LIMIT %d OFFSET %d`,
strings.Join(base.Int64sToStrings(teamIDs), ","), pageSize, (page-1)*pageSize),
org.ID, false).Find(&repos); err != nil {
if err := x.
Select("`repository`.*").
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
Where("(`repository`.owner_id=? AND `repository`.is_private=?)", org.ID, false).
Or(builder.In("team_repo.team_id", teamIDs)).
GroupBy("`repository`.id").
OrderBy("updated_unix DESC").
Limit(pageSize, (page-1)*pageSize).
Find(&repos); err != nil {
return nil, 0, fmt.Errorf("get repositories: %v", err)
}
results, err := x.Query(fmt.Sprintf(`SELECT repository.id FROM repository
INNER JOIN team_repo
ON team_repo.repo_id = repository.id
WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (%s)
GROUP BY repository.id
ORDER BY updated_unix DESC`,
strings.Join(base.Int64sToStrings(teamIDs), ",")),
org.ID, false)
repoCount, err := x.
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
Where("(`repository`.owner_id=? AND `repository`.is_private=?)", org.ID, false).
Or(builder.In("team_repo.team_id", teamIDs)).
GroupBy("`repository`.id").
Count(&Repository{})
if err != nil {
log.Error(4, "count user repositories in organization: %v", err)
return nil, 0, fmt.Errorf("count user repositories in organization: %v", err)
}
return repos, int64(len(results)), nil
return repos, repoCount, nil
}
// GetUserRepositories returns mirror repositories of the organization
// GetUserMirrorRepositories returns mirror repositories of the user
// that the user with the given userID has access to.
func (org *User) GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
teamIDs, err := org.GetUserTeamIDs(userID)
@@ -533,15 +579,12 @@ func (org *User) GetUserMirrorRepositories(userID int64) ([]*Repository, error)
}
repos := make([]*Repository, 0, 10)
if err = x.Sql(fmt.Sprintf(`SELECT repository.* FROM repository
INNER JOIN team_repo
ON team_repo.repo_id = repository.id AND repository.is_mirror = ?
WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (%s)
GROUP BY repository.id
ORDER BY updated_unix DESC`,
strings.Join(base.Int64sToStrings(teamIDs), ",")),
true, org.ID, false).Find(&repos); err != nil {
return nil, fmt.Errorf("get repositories: %v", err)
}
return repos, nil
return repos, x.
Select("`repository`.*").
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true).
Where("(`repository`.owner_id=? AND `repository`.is_private=?)", org.ID, false).
Or(builder.In("team_repo.team_id", teamIDs)).
GroupBy("`repository`.id").
OrderBy("updated_unix DESC").
Find(&repos)
}

View File

@@ -10,7 +10,7 @@ import (
"strings"
)
const OWNER_TEAM = "Owners"
const ownerTeamName = "Owners"
// Team represents a organization team.
type Team struct {
@@ -28,17 +28,19 @@ type Team struct {
// IsOwnerTeam returns true if team is owner team.
func (t *Team) IsOwnerTeam() bool {
return t.Name == OWNER_TEAM
return t.Name == ownerTeamName
}
// IsTeamMember returns true if given user is a member of team.
func (t *Team) IsMember(uid int64) bool {
return IsTeamMember(t.OrgID, t.ID, uid)
// IsMember returns true if given user is a member of team.
func (t *Team) IsMember(userID int64) bool {
return IsTeamMember(t.OrgID, t.ID, userID)
}
func (t *Team) getRepositories(e Engine) (err error) {
teamRepos := make([]*TeamRepo, 0, t.NumRepos)
if err = x.Where("team_id=?", t.ID).Find(&teamRepos); err != nil {
if err = x.
Where("team_id=?", t.ID).
Find(&teamRepos); err != nil {
return fmt.Errorf("get team-repos: %v", err)
}
@@ -70,13 +72,13 @@ func (t *Team) GetMembers() (err error) {
// AddMember adds new membership of the team to the organization,
// the user will have membership to the organization automatically when needed.
func (t *Team) AddMember(uid int64) error {
return AddTeamMember(t.OrgID, t.ID, uid)
func (t *Team) AddMember(userID int64) error {
return AddTeamMember(t.OrgID, t.ID, userID)
}
// RemoveMember removes member from team of organization.
func (t *Team) RemoveMember(uid int64) error {
return RemoveTeamMember(t.OrgID, t.ID, uid)
func (t *Team) RemoveMember(userID int64) error {
return RemoveTeamMember(t.OrgID, t.ID, userID)
}
func (t *Team) hasRepository(e Engine, repoID int64) bool {
@@ -155,7 +157,7 @@ func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (e
return fmt.Errorf("get team members: %v", err)
}
for _, u := range t.Members {
has, err := hasAccess(e, u, repo, ACCESS_MODE_READ)
has, err := hasAccess(e, u, repo, AccessModeRead)
if err != nil {
return err
} else if has {
@@ -194,13 +196,30 @@ func (t *Team) RemoveRepository(repoID int64) error {
return sess.Commit()
}
// IsUsableTeamName tests if a name could be as team name
func IsUsableTeamName(name string) (err error) {
var reservedTeamNames = []string{"new"}
for i := range reservedTeamNames {
if name == reservedTeamNames[i] {
return ErrNameReserved{name}
}
}
return nil
}
// NewTeam creates a record of new team.
// It's caller's responsibility to assign organization ID.
func NewTeam(t *Team) error {
func NewTeam(t *Team) (err error) {
if len(t.Name) == 0 {
return errors.New("empty team name")
}
if err = IsUsableTeamName(t.Name); err != nil {
return err
}
has, err := x.Id(t.OrgID).Get(new(User))
if err != nil {
return err
@@ -209,7 +228,10 @@ func NewTeam(t *Team) error {
}
t.LowerName = strings.ToLower(t.Name)
has, err = x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).Get(new(Team))
has, err = x.
Where("org_id=?", t.OrgID).
And("lower_name=?", t.LowerName).
Get(new(Team))
if err != nil {
return err
} else if has {
@@ -235,9 +257,9 @@ func NewTeam(t *Team) error {
return sess.Commit()
}
func getTeam(e Engine, orgId int64, name string) (*Team, error) {
func getTeam(e Engine, orgID int64, name string) (*Team, error) {
t := &Team{
OrgID: orgId,
OrgID: orgID,
LowerName: strings.ToLower(name),
}
has, err := e.Get(t)
@@ -250,13 +272,13 @@ func getTeam(e Engine, orgId int64, name string) (*Team, error) {
}
// GetTeam returns team by given team name and organization.
func GetTeam(orgId int64, name string) (*Team, error) {
return getTeam(x, orgId, name)
func GetTeam(orgID int64, name string) (*Team, error) {
return getTeam(x, orgID, name)
}
func getTeamByID(e Engine, teamId int64) (*Team, error) {
func getTeamByID(e Engine, teamID int64) (*Team, error) {
t := new(Team)
has, err := e.Id(teamId).Get(t)
has, err := e.Id(teamID).Get(t)
if err != nil {
return nil, err
} else if !has {
@@ -266,8 +288,8 @@ func getTeamByID(e Engine, teamId int64) (*Team, error) {
}
// GetTeamByID returns team by given ID.
func GetTeamByID(teamId int64) (*Team, error) {
return getTeamByID(x, teamId)
func GetTeamByID(teamID int64) (*Team, error) {
return getTeamByID(x, teamID)
}
// UpdateTeam updates information of team.
@@ -287,7 +309,11 @@ func UpdateTeam(t *Team, authChanged bool) (err error) {
}
t.LowerName = strings.ToLower(t.Name)
has, err := x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).And("id!=?", t.ID).Get(new(Team))
has, err := x.
Where("org_id=?", t.OrgID).
And("lower_name=?", t.LowerName).
And("id!=?", t.ID).
Get(new(Team))
if err != nil {
return err
} else if has {
@@ -341,7 +367,10 @@ func DeleteTeam(t *Team) error {
}
// Delete team-user.
if _, err = sess.Where("org_id=?", org.ID).Where("team_id=?", t.ID).Delete(new(TeamUser)); err != nil {
if _, err = sess.
Where("org_id=?", org.ID).
Where("team_id=?", t.ID).
Delete(new(TeamUser)); err != nil {
return err
}
@@ -369,29 +398,35 @@ type TeamUser struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"INDEX"`
TeamID int64 `xorm:"UNIQUE(s)"`
Uid int64 `xorm:"UNIQUE(s)"`
UID int64 `xorm:"UNIQUE(s)"`
}
func isTeamMember(e Engine, orgID, teamID, uid int64) bool {
has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("uid=?", uid).Get(new(TeamUser))
func isTeamMember(e Engine, orgID, teamID, userID int64) bool {
has, _ := e.
Where("org_id=?", orgID).
And("team_id=?", teamID).
And("uid=?", userID).
Get(new(TeamUser))
return has
}
// IsTeamMember returns true if given user is a member of team.
func IsTeamMember(orgID, teamID, uid int64) bool {
return isTeamMember(x, orgID, teamID, uid)
func IsTeamMember(orgID, teamID, userID int64) bool {
return isTeamMember(x, orgID, teamID, userID)
}
func getTeamMembers(e Engine, teamID int64) (_ []*User, err error) {
teamUsers := make([]*TeamUser, 0, 10)
if err = e.Where("team_id=?", teamID).Find(&teamUsers); err != nil {
if err = e.
Where("team_id=?", teamID).
Find(&teamUsers); err != nil {
return nil, fmt.Errorf("get team-users: %v", err)
}
members := make([]*User, 0, len(teamUsers))
for i := range teamUsers {
member := new(User)
if _, err = e.Id(teamUsers[i].Uid).Get(member); err != nil {
return nil, fmt.Errorf("get user '%d': %v", teamUsers[i].Uid, err)
if _, err = e.Id(teamUsers[i].UID).Get(member); err != nil {
return nil, fmt.Errorf("get user '%d': %v", teamUsers[i].UID, err)
}
members = append(members, member)
}
@@ -403,9 +438,12 @@ func GetTeamMembers(teamID int64) ([]*User, error) {
return getTeamMembers(x, teamID)
}
func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) {
func getUserTeams(e Engine, orgID, userID int64) ([]*Team, error) {
tus := make([]*TeamUser, 0, 5)
if err := e.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {
if err := e.
Where("uid=?", userID).
And("org_id=?", orgID).
Find(&tus); err != nil {
return nil, err
}
@@ -424,18 +462,18 @@ func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) {
}
// GetUserTeams returns all teams that user belongs to in given organization.
func GetUserTeams(orgId, uid int64) ([]*Team, error) {
return getUserTeams(x, orgId, uid)
func GetUserTeams(orgID, userID int64) ([]*Team, error) {
return getUserTeams(x, orgID, userID)
}
// AddTeamMember adds new membership of given team to given organization,
// the user will have membership to given organization automatically when needed.
func AddTeamMember(orgID, teamID, uid int64) error {
if IsTeamMember(orgID, teamID, uid) {
func AddTeamMember(orgID, teamID, userID int64) error {
if IsTeamMember(orgID, teamID, userID) {
return nil
}
if err := AddOrgUser(orgID, uid); err != nil {
if err := AddOrgUser(orgID, userID); err != nil {
return err
}
@@ -457,7 +495,7 @@ func AddTeamMember(orgID, teamID, uid int64) error {
}
tu := &TeamUser{
Uid: uid,
UID: userID,
OrgID: orgID,
TeamID: teamID,
}
@@ -476,7 +514,10 @@ func AddTeamMember(orgID, teamID, uid int64) error {
// We make sure it exists before.
ou := new(OrgUser)
if _, err = sess.Where("uid = ?", uid).And("org_id = ?", orgID).Get(ou); err != nil {
if _, err = sess.
Where("uid = ?", userID).
And("org_id = ?", orgID).
Get(ou); err != nil {
return err
}
ou.NumTeams++
@@ -490,8 +531,8 @@ func AddTeamMember(orgID, teamID, uid int64) error {
return sess.Commit()
}
func removeTeamMember(e Engine, orgID, teamID, uid int64) error {
if !isTeamMember(e, orgID, teamID, uid) {
func removeTeamMember(e Engine, orgID, teamID, userID int64) error {
if !isTeamMember(e, orgID, teamID, userID) {
return nil
}
@@ -503,7 +544,7 @@ func removeTeamMember(e Engine, orgID, teamID, uid int64) error {
// Check if the user to delete is the last member in owner team.
if t.IsOwnerTeam() && t.NumMembers == 1 {
return ErrLastOrgOwner{UID: uid}
return ErrLastOrgOwner{UID: userID}
}
t.NumMembers--
@@ -519,13 +560,16 @@ func removeTeamMember(e Engine, orgID, teamID, uid int64) error {
}
tu := &TeamUser{
Uid: uid,
UID: userID,
OrgID: orgID,
TeamID: teamID,
}
if _, err := e.Delete(tu); err != nil {
return err
} else if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
} else if _, err = e.
Id(t.ID).
AllCols().
Update(t); err != nil {
return err
}
@@ -538,7 +582,10 @@ func removeTeamMember(e Engine, orgID, teamID, uid int64) error {
// This must exist.
ou := new(OrgUser)
_, err = e.Where("uid = ?", uid).And("org_id = ?", org.ID).Get(ou)
_, err = e.
Where("uid = ?", userID).
And("org_id = ?", org.ID).
Get(ou)
if err != nil {
return err
}
@@ -546,20 +593,23 @@ func removeTeamMember(e Engine, orgID, teamID, uid int64) error {
if t.IsOwnerTeam() {
ou.IsOwner = false
}
if _, err = e.Id(ou.ID).AllCols().Update(ou); err != nil {
if _, err = e.
Id(ou.ID).
AllCols().
Update(ou); err != nil {
return err
}
return nil
}
// RemoveTeamMember removes member from given team of given organization.
func RemoveTeamMember(orgID, teamID, uid int64) error {
func RemoveTeamMember(orgID, teamID, userID int64) error {
sess := x.NewSession()
defer sessionRelease(sess)
if err := sess.Begin(); err != nil {
return err
}
if err := removeTeamMember(sess, orgID, teamID, uid); err != nil {
if err := removeTeamMember(sess, orgID, teamID, userID); err != nil {
return err
}
return sess.Commit()
@@ -581,7 +631,11 @@ type TeamRepo struct {
}
func hasTeamRepo(e Engine, orgID, teamID, repoID int64) bool {
has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("repo_id=?", repoID).Get(new(TeamRepo))
has, _ := e.
Where("org_id=?", orgID).
And("team_id=?", teamID).
And("repo_id=?", repoID).
Get(new(TeamRepo))
return has
}

View File

@@ -11,33 +11,35 @@ import (
"strings"
"time"
"code.gitea.io/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/sync"
api "code.gitea.io/sdk/gitea"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/sync"
)
var PullRequestQueue = sync.NewUniqueQueue(setting.Repository.PullRequestQueueLength)
var pullRequestQueue = sync.NewUniqueQueue(setting.Repository.PullRequestQueueLength)
// PullRequestType defines pull request type
type PullRequestType int
// Enumerate all the pull request types
const (
PULL_REQUEST_GOGS PullRequestType = iota
PLLL_ERQUEST_GIT
PullRequestGitea PullRequestType = iota
PullRequestGit
)
// PullRequestStatus defines pull request status
type PullRequestStatus int
// Enumerate all the pull request status
const (
PULL_REQUEST_STATUS_CONFLICT PullRequestStatus = iota
PULL_REQUEST_STATUS_CHECKING
PULL_REQUEST_STATUS_MERGEABLE
PullRequestStatusConflict PullRequestStatus = iota
PullRequestStatusChecking
PullRequestStatusMergeable
)
// PullRequest represents relation between pull request and repositories.
@@ -67,10 +69,12 @@ type PullRequest struct {
MergedUnix int64
}
// BeforeUpdate is invoked from XORM before updating an object of this type.
func (pr *PullRequest) BeforeUpdate() {
pr.MergedUnix = pr.Merged.Unix()
}
// AfterSet is invoked from XORM after setting the value of a field of this object.
// Note: don't try to get Issue because will end up recursive querying.
func (pr *PullRequest) AfterSet(colName string, _ xorm.Cell) {
switch colName {
@@ -98,10 +102,12 @@ func (pr *PullRequest) loadAttributes(e Engine) (err error) {
return nil
}
// LoadAttributes loads pull request attributes from database
func (pr *PullRequest) LoadAttributes() error {
return pr.loadAttributes(x)
}
// LoadIssue loads issue information from database
func (pr *PullRequest) LoadIssue() (err error) {
if pr.Issue != nil {
return nil
@@ -111,11 +117,58 @@ func (pr *PullRequest) LoadIssue() (err error) {
return err
}
// This method assumes following fields have been assigned with valid values:
// APIFormat assumes following fields have been assigned with valid values:
// 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,
@@ -128,12 +181,17 @@ 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 != PULL_REQUEST_STATUS_CHECKING {
mergeable := pr.Status != PULL_REQUEST_STATUS_CONFLICT
apiPullRequest.Mergeable = &mergeable
if pr.Status != PullRequestStatusChecking {
mergeable := pr.Status != PullRequestStatusConflict
apiPullRequest.Mergeable = mergeable
}
if pr.HasMerged {
apiPullRequest.Merged = &pr.Merged
@@ -152,10 +210,12 @@ func (pr *PullRequest) getHeadRepo(e Engine) (err error) {
return nil
}
// GetHeadRepo loads the head repository
func (pr *PullRequest) GetHeadRepo() error {
return pr.getHeadRepo(x)
}
// GetBaseRepo loads the target repository
func (pr *PullRequest) GetBaseRepo() (err error) {
if pr.BaseRepo != nil {
return nil
@@ -170,12 +230,12 @@ func (pr *PullRequest) GetBaseRepo() (err error) {
// IsChecking returns true if this pull request is still checking conflict.
func (pr *PullRequest) IsChecking() bool {
return pr.Status == PULL_REQUEST_STATUS_CHECKING
return pr.Status == PullRequestStatusChecking
}
// CanAutoMerge returns true if this pull request can be merged automatically.
func (pr *PullRequest) CanAutoMerge() bool {
return pr.Status == PULL_REQUEST_STATUS_MERGEABLE
return pr.Status == PullRequestStatusMergeable
}
// Merge merges pull request to base repository.
@@ -210,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
@@ -287,11 +351,11 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
log.Error(4, "LoadAttributes: %v", err)
return nil
}
if err = PrepareWebhooks(pr.Issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
Action: api.HOOK_ISSUE_CLOSED,
if err = PrepareWebhooks(pr.Issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
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)
@@ -316,22 +380,22 @@ 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),
CompareURL: setting.AppURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
Commits: ListToPushCommits(l).ToAPIPayloadCommits(pr.BaseRepo.HTMLURL()),
Repo: pr.BaseRepo.APIFormat(AccessModeNone),
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
Sender: doer.APIFormat(),
}
if err = PrepareWebhooks(pr.BaseRepo, HOOK_EVENT_PUSH, p); err != nil {
if err = PrepareWebhooks(pr.BaseRepo, HookEventPush, p); err != nil {
return fmt.Errorf("PrepareWebhooks: %v", err)
}
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",
@@ -339,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)
@@ -365,20 +428,23 @@ 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)
}
pr.Status = PULL_REQUEST_STATUS_CHECKING
pr.Status = PullRequestStatusChecking
_, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
fmt.Sprintf("testPatch (git apply --check): %d", pr.BaseRepo.ID),
"git", "apply", "--check", patchPath)
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 = PULL_REQUEST_STATUS_CONFLICT
pr.Status = PullRequestStatusConflict
return nil
}
}
@@ -416,8 +482,8 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
return fmt.Errorf("testPatch: %v", err)
}
// No conflict appears after test means mergeable.
if pr.Status == PULL_REQUEST_STATUS_CHECKING {
pr.Status = PULL_REQUEST_STATUS_MERGEABLE
if pr.Status == PullRequestStatusChecking {
pr.Status = PullRequestStatusMergeable
}
pr.IssueID = pull.ID
@@ -432,7 +498,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
if err = NotifyWatchers(&Action{
ActUserID: pull.Poster.ID,
ActUserName: pull.Poster.Name,
OpType: ACTION_CREATE_PULL_REQUEST,
OpType: ActionCreatePullRequest,
Content: fmt.Sprintf("%d|%s", pull.Index, pull.Title),
RepoID: repo.ID,
RepoUserName: repo.Owner.Name,
@@ -446,11 +512,11 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
pr.Issue = pull
pull.PullRequest = pr
if err = PrepareWebhooks(repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
Action: api.HOOK_ISSUE_OPENED,
if err = PrepareWebhooks(repo, HookEventPullRequest, &api.PullRequestPayload{
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)
@@ -460,13 +526,55 @@ 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) {
pr := new(PullRequest)
has, err := x.Where("head_repo_id=? AND head_branch=? AND base_repo_id=? AND base_branch=? AND has_merged=? AND issue.is_closed=?",
headRepoID, headBranch, baseRepoID, baseBranch, false, false).
Join("INNER", "issue", "issue.id=pull_request.issue_id").Get(pr)
has, err := x.
Where("head_repo_id=? AND head_branch=? AND base_repo_id=? AND base_branch=? AND has_merged=? AND issue.is_closed=?",
headRepoID, headBranch, baseRepoID, baseBranch, false, false).
Join("INNER", "issue", "issue.id=pull_request.issue_id").
Get(pr)
if err != nil {
return nil, err
} else if !has {
@@ -480,18 +588,46 @@ func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch
// by given head information (repo and branch).
func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequest, error) {
prs := make([]*PullRequest, 0, 2)
return prs, x.Where("head_repo_id = ? AND head_branch = ? AND has_merged = ? AND issue.is_closed = ?",
repoID, branch, false, false).
Join("INNER", "issue", "issue.id = pull_request.issue_id").Find(&prs)
return prs, x.
Where("head_repo_id = ? AND head_branch = ? AND has_merged = ? AND issue.is_closed = ?",
repoID, branch, false, false).
Join("INNER", "issue", "issue.id = pull_request.issue_id").
Find(&prs)
}
// GetUnmergedPullRequestsByBaseInfo returnss all pull requests that are open and has not been merged
// by given base information (repo and branch).
func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequest, error) {
prs := make([]*PullRequest, 0, 2)
return prs, x.Where("base_repo_id=? AND base_branch=? AND has_merged=? AND issue.is_closed=?",
repoID, branch, false, false).
Join("INNER", "issue", "issue.id=pull_request.issue_id").Find(&prs)
return prs, x.
Where("base_repo_id=? AND base_branch=? AND has_merged=? AND issue.is_closed=?",
repoID, branch, false, false).
Join("INNER", "issue", "issue.id=pull_request.issue_id").
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) {
@@ -534,7 +670,7 @@ func (pr *PullRequest) Update() error {
return err
}
// Update updates specific fields of pull request.
// UpdateCols updates specific fields of pull request.
func (pr *PullRequest) UpdateCols(cols ...string) error {
_, err := x.Id(pr.ID).Cols(cols...).Update(pr)
return err
@@ -608,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)
@@ -619,14 +757,15 @@ func (pr *PullRequest) PushToBaseRepo() (err error) {
// AddToTaskQueue adds itself to pull request test task queue.
func (pr *PullRequest) AddToTaskQueue() {
go PullRequestQueue.AddFunc(pr.ID, func() {
pr.Status = PULL_REQUEST_STATUS_CHECKING
go pullRequestQueue.AddFunc(pr.ID, func() {
pr.Status = PullRequestStatusChecking
if err := pr.UpdateCols("status"); err != nil {
log.Error(5, "AddToTaskQueue.UpdateCols[%d].(add to queue): %v", pr.ID, err)
}
})
}
// PullRequestList defines a list of pull requests
type PullRequestList []*PullRequest
func (prs PullRequestList) loadAttributes(e Engine) error {
@@ -640,7 +779,10 @@ func (prs PullRequestList) loadAttributes(e Engine) error {
issueIDs = append(issueIDs, prs[i].IssueID)
}
issues := make([]*Issue, 0, len(issueIDs))
if err := e.Where("id > 0").In("id", issueIDs).Find(&issues); err != nil {
if err := e.
Where("id > 0").
In("id", issueIDs).
Find(&issues); err != nil {
return fmt.Errorf("find issues: %v", err)
}
@@ -654,6 +796,7 @@ func (prs PullRequestList) loadAttributes(e Engine) error {
return nil
}
// LoadAttributes load all the prs attributes
func (prs PullRequestList) LoadAttributes() error {
return prs.loadAttributes(x)
}
@@ -695,11 +838,11 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool
log.Error(4, "LoadAttributes: %v", err)
continue
}
if err = PrepareWebhooks(pr.Issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
Action: api.HOOK_ISSUE_SYNCHRONIZED,
if err = PrepareWebhooks(pr.Issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
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)
@@ -723,11 +866,15 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool
}
}
// ChangeUsernameInPullRequests changes the name of head_user_name
func ChangeUsernameInPullRequests(oldUserName, newUserName string) error {
pr := PullRequest{
HeadUserName: strings.ToLower(newUserName),
}
_, err := x.Cols("head_user_name").Where("head_user_name = ?", strings.ToLower(oldUserName)).Update(pr)
_, err := x.
Cols("head_user_name").
Where("head_user_name = ?", strings.ToLower(oldUserName)).
Update(pr)
return err
}
@@ -735,12 +882,12 @@ func ChangeUsernameInPullRequests(oldUserName, newUserName string) error {
// and set to be either conflict or mergeable.
func (pr *PullRequest) checkAndUpdateStatus() {
// Status is not changed to conflict means mergeable.
if pr.Status == PULL_REQUEST_STATUS_CHECKING {
pr.Status = PULL_REQUEST_STATUS_MERGEABLE
if pr.Status == PullRequestStatusChecking {
pr.Status = PullRequestStatusMergeable
}
// Make sure there is no waiting test to process before levaing the checking status.
if !PullRequestQueue.Exist(pr.ID) {
if !pullRequestQueue.Exist(pr.ID) {
if err := pr.UpdateCols("status"); err != nil {
log.Error(4, "Update[%d]: %v", pr.ID, err)
}
@@ -752,7 +899,7 @@ func (pr *PullRequest) checkAndUpdateStatus() {
func TestPullRequests() {
prs := make([]*PullRequest, 0, 10)
x.Iterate(PullRequest{
Status: PULL_REQUEST_STATUS_CHECKING,
Status: PullRequestStatusChecking,
},
func(idx int, bean interface{}) error {
pr := bean.(*PullRequest)
@@ -776,13 +923,13 @@ func TestPullRequests() {
}
// Start listening on new test requests.
for prID := range PullRequestQueue.Queue() {
for prID := range pullRequestQueue.Queue() {
log.Trace("TestPullRequests[%v]: processing test task", prID)
PullRequestQueue.Remove(prID)
pullRequestQueue.Remove(prID)
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)
@@ -793,6 +940,7 @@ func TestPullRequests() {
}
}
// InitTestPullRequests runs the task to test all the checking status pull requests
func InitTestPullRequests() {
go TestPullRequests()
}

View File

@@ -12,9 +12,9 @@ import (
"github.com/go-xorm/xorm"
"github.com/gogits/git-module"
"code.gitea.io/git"
"github.com/gogits/gogs/modules/process"
"code.gitea.io/gitea/modules/process"
)
// Release represents a release of repository.
@@ -38,12 +38,14 @@ type Release struct {
CreatedUnix int64
}
// BeforeInsert is invoked from XORM before inserting an object of this type.
func (r *Release) BeforeInsert() {
if r.CreatedUnix == 0 {
r.CreatedUnix = time.Now().Unix()
}
}
// AfterSet is invoked from XORM after setting the value of a field of this object.
func (r *Release) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
@@ -127,7 +129,9 @@ func GetRelease(repoID int64, tagName string) (*Release, error) {
// GetReleaseByID returns release with given ID.
func GetReleaseByID(id int64) (*Release, error) {
rel := new(Release)
has, err := x.Id(id).Get(rel)
has, err := x.
Id(id).
Get(rel)
if err != nil {
return nil, err
} else if !has {
@@ -138,20 +142,26 @@ func GetReleaseByID(id int64) (*Release, error) {
}
// GetReleasesByRepoID returns a list of releases of repository.
func GetReleasesByRepoID(repoID int64) (rels []*Release, err error) {
err = x.Desc("created_unix").Find(&rels, Release{RepoID: repoID})
func GetReleasesByRepoID(repoID int64, page, pageSize int) (rels []*Release, err error) {
if page <= 0 {
page = 1
}
err = x.
Desc("created_unix").
Limit(pageSize, (page-1)*pageSize).
Find(&rels, Release{RepoID: repoID})
return rels, err
}
type ReleaseSorter struct {
type releaseSorter struct {
rels []*Release
}
func (rs *ReleaseSorter) Len() int {
func (rs *releaseSorter) Len() int {
return len(rs.rels)
}
func (rs *ReleaseSorter) Less(i, j int) bool {
func (rs *releaseSorter) Less(i, j int) bool {
diffNum := rs.rels[i].NumCommits - rs.rels[j].NumCommits
if diffNum != 0 {
return diffNum > 0
@@ -159,13 +169,13 @@ func (rs *ReleaseSorter) Less(i, j int) bool {
return rs.rels[i].Created.After(rs.rels[j].Created)
}
func (rs *ReleaseSorter) Swap(i, j int) {
func (rs *releaseSorter) Swap(i, j int) {
rs.rels[i], rs.rels[j] = rs.rels[j], rs.rels[i]
}
// SortReleases sorts releases by number of commits and created time.
func SortReleases(rels []*Release) {
sorter := &ReleaseSorter{rels: rels}
sorter := &releaseSorter{rels: rels}
sort.Sort(sorter)
}
@@ -179,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)
@@ -190,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

@@ -19,54 +19,72 @@ import (
"strings"
"time"
"code.gitea.io/git"
"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"
api "code.gitea.io/sdk/gitea"
"github.com/Unknwon/cae/zip"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/mcuadros/go-version"
"gopkg.in/ini.v1"
git "github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/bindata"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/sync"
version "github.com/mcuadros/go-version"
ini "gopkg.in/ini.v1"
)
const (
_TPL_UPDATE_HOOK = "#!/usr/bin/env %s\n%s update $1 $2 $3 --config='%s'\n"
tplUpdateHook = "#!/usr/bin/env %s\n%s update $1 $2 $3 --config='%s'\n"
)
var repoWorkingPool = sync.NewExclusivePool()
var (
ErrRepoFileNotExist = errors.New("Repository file does not exist")
// ErrRepoFileNotExist repository file does not exist error
ErrRepoFileNotExist = errors.New("Repository file does not exist")
// ErrRepoFileNotLoaded repository file not loaded error
ErrRepoFileNotLoaded = errors.New("Repository file not loaded")
ErrMirrorNotExist = errors.New("Mirror does not exist")
ErrInvalidReference = errors.New("Invalid reference specified")
ErrNameEmpty = errors.New("Name is empty")
// ErrMirrorNotExist mirror does not exist error
ErrMirrorNotExist = errors.New("Mirror does not exist")
// ErrInvalidReference invalid reference specified error
ErrInvalidReference = errors.New("Invalid reference specified")
// ErrNameEmpty name is empty error
ErrNameEmpty = errors.New("Name is empty")
)
var (
Gitignores, Licenses, Readmes, LabelTemplates []string
// Gitignores contains the gitiginore files
Gitignores []string
// Maximum items per page in forks, watchers and stars of a repo
// Licenses contains the license files
Licenses []string
// Readmes contains the readme files
Readmes []string
// LabelTemplates contains the label template files
LabelTemplates []string
// ItemsPerPage maximum items per page in forks, watchers and stars of a repo
ItemsPerPage = 40
)
// LoadRepoConfig loads the repository config
func LoadRepoConfig() {
// Load .gitignore and license files and readme templates.
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 {
@@ -106,6 +124,7 @@ func LoadRepoConfig() {
Licenses = sortedLicenses
}
// NewRepoContext creates a new repository context
func NewRepoContext() {
zip.Verbose = false
@@ -186,6 +205,7 @@ type Repository struct {
ExternalWikiURL string
EnableIssues bool `xorm:"NOT NULL DEFAULT true"`
EnableExternalTracker bool
ExternalTrackerURL string
ExternalTrackerFormat string
ExternalTrackerStyle string
ExternalMetas map[string]string `xorm:"-"`
@@ -201,15 +221,18 @@ type Repository struct {
UpdatedUnix int64
}
// BeforeInsert is invoked from XORM before inserting an object of this type.
func (repo *Repository) BeforeInsert() {
repo.CreatedUnix = time.Now().Unix()
repo.UpdatedUnix = repo.CreatedUnix
}
// BeforeUpdate is invoked from XORM before updating this object.
func (repo *Repository) BeforeUpdate() {
repo.UpdatedUnix = time.Now().Unix()
}
// AfterSet is invoked from XORM after setting the value of a field of this object.
func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "default_branch":
@@ -225,7 +248,7 @@ func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
case "external_tracker_style":
if len(repo.ExternalTrackerStyle) == 0 {
repo.ExternalTrackerStyle = markdown.ISSUE_NAME_STYLE_NUMERIC
repo.ExternalTrackerStyle = markdown.IssueNameStyleNumeric
}
case "created_unix":
repo.Created = time.Unix(repo.CreatedUnix, 0).Local()
@@ -242,17 +265,24 @@ func (repo *Repository) MustOwner() *User {
return repo.mustOwner(x)
}
// FullName returns the repository full name
func (repo *Repository) FullName() string {
return repo.MustOwner().Name + "/" + repo.Name
}
// HTMLURL returns the repository HTML URL
func (repo *Repository) HTMLURL() string {
return setting.AppUrl + repo.FullName()
return setting.AppURL + repo.FullName()
}
// Arguments that are allowed to be nil: permission
func (repo *Repository) APIFormat(permission *api.Permission) *api.Repository {
// APIFormat converts a Repository to 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(),
@@ -285,6 +315,7 @@ func (repo *Repository) getOwner(e Engine) (err error) {
return err
}
// GetOwner returns the repository owner
func (repo *Repository) GetOwner() error {
return repo.getOwner(x)
}
@@ -311,10 +342,10 @@ func (repo *Repository) ComposeMetas() map[string]string {
"repo": repo.Name,
}
switch repo.ExternalTrackerStyle {
case markdown.ISSUE_NAME_STYLE_ALPHANUMERIC:
repo.ExternalMetas["style"] = markdown.ISSUE_NAME_STYLE_ALPHANUMERIC
case markdown.IssueNameStyleAlphanumeric:
repo.ExternalMetas["style"] = markdown.IssueNameStyleAlphanumeric
default:
repo.ExternalMetas["style"] = markdown.ISSUE_NAME_STYLE_NUMERIC
repo.ExternalMetas["style"] = markdown.IssueNameStyleNumeric
}
}
@@ -335,7 +366,9 @@ func (repo *Repository) getAssignees(e Engine) (_ []*User, err error) {
}
accesses := make([]*Access, 0, 10)
if err = e.Where("repo_id = ? AND mode >= ?", repo.ID, ACCESS_MODE_WRITE).Find(&accesses); err != nil {
if err = e.
Where("repo_id = ? AND mode >= ?", repo.ID, AccessModeWrite).
Find(&accesses); err != nil {
return nil, err
}
@@ -380,11 +413,13 @@ func (repo *Repository) IssueStats(uid int64, filterMode int, isPull bool) (int6
return GetRepoIssueStats(repo.ID, uid, filterMode, isPull)
}
// GetMirror sets the repository mirror, returns an error upon failure
func (repo *Repository) GetMirror() (err error) {
repo.Mirror, err = GetMirrorByRepoID(repo.ID)
return err
}
// GetBaseRepo returns the base repository
func (repo *Repository) GetBaseRepo() (err error) {
if !repo.IsFork {
return nil
@@ -398,31 +433,38 @@ func (repo *Repository) repoPath(e Engine) string {
return RepoPath(repo.mustOwner(e).Name, repo.Name)
}
// RepoPath returns the repository path
func (repo *Repository) RepoPath() string {
return repo.repoPath(x)
}
// GitConfigPath returns the repository git config path
func (repo *Repository) GitConfigPath() string {
return filepath.Join(repo.RepoPath(), "config")
}
// RelLink returns the repository relative link
func (repo *Repository) RelLink() string {
return "/" + repo.FullName()
}
// Link returns the repository link
func (repo *Repository) Link() string {
return setting.AppSubUrl + "/" + repo.FullName()
return setting.AppSubURL + "/" + repo.FullName()
}
// ComposeCompareURL returns the repository comparison URL
func (repo *Repository) ComposeCompareURL(oldCommitID, newCommitID string) string {
return fmt.Sprintf("%s/%s/compare/%s...%s", repo.MustOwner().Name, repo.Name, oldCommitID, newCommitID)
}
// HasAccess returns true when user has access to this repository
func (repo *Repository) HasAccess(u *User) bool {
has, _ := HasAccess(u, repo, ACCESS_MODE_READ)
has, _ := HasAccess(u, repo, AccessModeRead)
return has
}
// IsOwnedBy returns true when user owns this repository
func (repo *Repository) IsOwnedBy(userID int64) bool {
return repo.OwnerID == userID
}
@@ -437,7 +479,7 @@ func (repo *Repository) CanEnablePulls() bool {
return !repo.IsMirror
}
// AllowPulls returns true if repository meets the requirements of accepting pulls and has them enabled.
// AllowsPulls returns true if repository meets the requirements of accepting pulls and has them enabled.
func (repo *Repository) AllowsPulls() bool {
return repo.CanEnablePulls() && repo.EnablePulls
}
@@ -447,6 +489,7 @@ func (repo *Repository) CanEnableEditor() bool {
return !repo.IsMirror
}
// NextIssueIndex returns the next issue index
// FIXME: should have a mutex to prevent producing same index for two issues that are created
// closely enough.
func (repo *Repository) NextIssueIndex() int64 {
@@ -454,22 +497,23 @@ func (repo *Repository) NextIssueIndex() int64 {
}
var (
DescPattern = regexp.MustCompile(`https?://\S+`)
descPattern = regexp.MustCompile(`https?://\S+`)
)
// DescriptionHtml does special handles to description and return HTML string.
func (repo *Repository) DescriptionHtml() template.HTML {
// 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))
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))
}
// UpdateLocalCopy pulls latest changes of given branch from repoPath to localPath.
// UpdateLocalCopyBranch pulls latest changes of given branch from repoPath to localPath.
// It creates a new clone if local copy does not exist.
// This function checks out target branch by default, it is safe to assume subsequent
// operations are operating against target branch when caller has confidence for no race condition.
@@ -518,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)
}
@@ -549,7 +597,7 @@ type CloneLink struct {
// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
func ComposeHTTPSCloneURL(owner, repo string) string {
return fmt.Sprintf("%s%s/%s.git", setting.AppUrl, owner, repo)
return fmt.Sprintf("%s%s/%s.git", setting.AppURL, owner, repo)
}
func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
@@ -574,6 +622,7 @@ func (repo *Repository) CloneLink() (cl *CloneLink) {
return repo.cloneLink(false)
}
// MigrateRepoOptions contains the repository migrate options
type MigrateRepoOptions struct {
Name string
Description string
@@ -628,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,
@@ -639,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)
}
}
}
@@ -707,10 +766,10 @@ func cleanUpMigrateGitConfig(configPath string) error {
func createUpdateHook(repoPath string) error {
return git.SetUpdateHook(repoPath,
fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf))
fmt.Sprintf(tplUpdateHook, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf))
}
// Finish migrating repository and/or wiki with things that don't need to be done for mirrors.
// CleanUpMigrateInfo finishes migrating repository and/or wiki with things that don't need to be done for mirrors.
func CleanUpMigrateInfo(repo *Repository) (*Repository, error) {
repoPath := repo.RepoPath()
if err := createUpdateHook(repoPath); err != nil {
@@ -758,6 +817,7 @@ func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
return nil
}
// CreateRepoOptions contains the create repository options
type CreateRepoOptions struct {
Name string
Description string
@@ -770,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 {
@@ -860,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 {
@@ -896,6 +973,7 @@ var (
reservedRepoPatterns = []string{"*.git", "*.wiki"}
)
// IsUsableRepoName returns true when repository is usable
func IsUsableRepoName(name string) error {
return isUsableName(reservedRepoNames, reservedRepoPatterns, name)
}
@@ -1029,6 +1107,7 @@ func CountUserRepositories(userID int64, private bool) int64 {
return countRepositories(userID, private)
}
// Repositories returns all repositories
func Repositories(page, pageSize int) (_ []*Repository, err error) {
repos := make([]*Repository, 0, pageSize)
return repos, x.Limit(pageSize, (page-1)*pageSize).Asc("id").Find(&repos)
@@ -1154,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)
}
@@ -1210,7 +1294,9 @@ func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error)
func getRepositoriesByForkID(e Engine, forkID int64) ([]*Repository, error) {
repos := make([]*Repository, 0, 10)
return repos, e.Where("fork_id=?", forkID).Find(&repos)
return repos, e.
Where("fork_id=?", forkID).
Find(&repos)
}
// GetRepositoriesByForkID returns all repositories with given fork ID.
@@ -1272,6 +1358,7 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e
return nil
}
// UpdateRepository updates a repository
func UpdateRepository(repo *Repository, visibilityChanged bool) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
@@ -1342,7 +1429,9 @@ func DeleteRepository(uid, repoID int64) error {
// Delete comments and attachments.
issues := make([]*Issue, 0, 25)
attachmentPaths := make([]string, 0, len(issues))
if err = sess.Where("repo_id=?", repoID).Find(&issues); err != nil {
if err = sess.
Where("repo_id=?", repoID).
Find(&issues); err != nil {
return err
}
for i := range issues {
@@ -1351,7 +1440,9 @@ func DeleteRepository(uid, repoID int64) error {
}
attachments := make([]*Attachment, 0, 5)
if err = sess.Where("issue_id=?", issues[i].ID).Find(&attachments); err != nil {
if err = sess.
Where("issue_id=?", issues[i].ID).
Find(&attachments); err != nil {
return err
}
for j := range attachments {
@@ -1451,7 +1542,9 @@ func GetRepositoryByID(id int64) (*Repository, error) {
// GetUserRepositories returns a list of repositories of given user.
func GetUserRepositories(userID int64, private bool, page, pageSize int) ([]*Repository, error) {
sess := x.Where("owner_id = ?", userID).Desc("updated_unix")
sess := x.
Where("owner_id = ?", userID).
Desc("updated_unix")
if !private {
sess.And("is_private=?", false)
}
@@ -1465,16 +1558,23 @@ func GetUserRepositories(userID int64, private bool, page, pageSize int) ([]*Rep
return repos, sess.Find(&repos)
}
// GetUserRepositories returns a list of mirror repositories of given user.
// GetUserMirrorRepositories returns a list of mirror repositories of given user.
func GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
repos := make([]*Repository, 0, 10)
return repos, x.Where("owner_id = ?", userID).And("is_mirror = ?", true).Find(&repos)
return repos, x.
Where("owner_id = ?", userID).
And("is_mirror = ?", true).
Find(&repos)
}
// GetRecentUpdatedRepositories returns the list of repositories that are recently updated.
func GetRecentUpdatedRepositories(page, pageSize int) (repos []*Repository, err error) {
return repos, x.Limit(pageSize, (page-1)*pageSize).
Where("is_private=?", false).Limit(pageSize).Desc("updated_unix").Find(&repos)
return repos, x.
Limit(pageSize, (page-1)*pageSize).
Where("is_private=?", false).
Limit(pageSize).
Desc("updated_unix").
Find(&repos)
}
func getRepositoryCount(e Engine, u *User) (int64, error) {
@@ -1486,6 +1586,7 @@ func GetRepositoryCount(u *User) (int64, error) {
return getRepositoryCount(x, u)
}
// SearchRepoOptions holds the search options
type SearchRepoOptions struct {
Keyword string
OwnerID int64
@@ -1533,23 +1634,27 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (repos []*Repository, _ int
// DeleteRepositoryArchives deletes all repositories' archives.
func DeleteRepositoryArchives() error {
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
return os.RemoveAll(filepath.Join(repo.RepoPath(), "archives"))
})
return x.
Where("id > 0").
Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
return os.RemoveAll(filepath.Join(repo.RepoPath(), "archives"))
})
}
func gatherMissingRepoRecords() ([]*Repository, error) {
repos := make([]*Repository, 0, 10)
if err := x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
if !com.IsDir(repo.RepoPath()) {
repos = append(repos, repo)
}
return nil
}); err != nil {
if err := x.
Where("id > 0").
Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
if !com.IsDir(repo.RepoPath()) {
repos = append(repos, repo)
}
return nil
}); err != nil {
if err2 := CreateRepositoryNotice(fmt.Sprintf("gatherMissingRepoRecords: %v", err)); err2 != nil {
return nil, fmt.Errorf("CreateRepositoryNotice: %v", err)
}
@@ -1603,66 +1708,73 @@ func ReinitMissingRepositories() error {
// RewriteRepositoryUpdateHook rewrites all repositories' update hook.
func RewriteRepositoryUpdateHook() error {
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
return createUpdateHook(repo.RepoPath())
})
return x.
Where("id > 0").
Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
return createUpdateHook(repo.RepoPath())
})
}
// Prevent duplicate running tasks.
var taskStatusTable = sync.NewStatusTable()
const (
_MIRROR_UPDATE = "mirror_update"
_GIT_FSCK = "git_fsck"
_CHECK_REPOs = "check_repos"
mirrorUpdate = "mirror_update"
gitFsck = "git_fsck"
checkRepos = "check_repos"
)
// GitFsck calls 'git fsck' to check repository health.
func GitFsck() {
if taskStatusTable.IsRunning(_GIT_FSCK) {
if taskStatusTable.IsRunning(gitFsck) {
return
}
taskStatusTable.Start(_GIT_FSCK)
defer taskStatusTable.Stop(_GIT_FSCK)
taskStatusTable.Start(gitFsck)
defer taskStatusTable.Stop(gitFsck)
log.Trace("Doing: GitFsck")
if err := x.Where("id>0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
repoPath := repo.RepoPath()
if err := git.Fsck(repoPath, setting.Cron.RepoHealthCheck.Timeout, setting.Cron.RepoHealthCheck.Args...); err != nil {
desc := fmt.Sprintf("Fail to health check repository (%s): %v", repoPath, err)
log.Warn(desc)
if err = CreateRepositoryNotice(desc); err != nil {
log.Error(4, "CreateRepositoryNotice: %v", err)
if err := x.
Where("id>0").
Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
repoPath := repo.RepoPath()
if err := git.Fsck(repoPath, setting.Cron.RepoHealthCheck.Timeout, setting.Cron.RepoHealthCheck.Args...); err != nil {
desc := fmt.Sprintf("Fail to health check repository (%s): %v", repoPath, err)
log.Warn(desc)
if err = CreateRepositoryNotice(desc); err != nil {
log.Error(4, "CreateRepositoryNotice: %v", err)
}
}
}
return nil
}); err != nil {
return nil
}); err != nil {
log.Error(4, "GitFsck: %v", err)
}
}
// GitGcRepos calls 'git gc' to remove unnecessary files and optimize the local repository
func GitGcRepos() error {
args := append([]string{"gc"}, setting.Git.GCArgs...)
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
if err := repo.GetOwner(); err != nil {
return err
}
_, stderr, err := process.ExecDir(
time.Duration(setting.Git.Timeout.GC)*time.Second,
RepoPath(repo.Owner.Name, repo.Name), "Repository garbage collection",
"git", args...)
if err != nil {
return fmt.Errorf("%v: %v", err, stderr)
}
return nil
})
return x.
Where("id > 0").
Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
if err := repo.GetOwner(); err != nil {
return err
}
_, stderr, err := process.ExecDir(
time.Duration(setting.Git.Timeout.GC)*time.Second,
RepoPath(repo.Owner.Name, repo.Name), "Repository garbage collection",
"git", args...)
if err != nil {
return fmt.Errorf("%v: %v", err, stderr)
}
return nil
})
}
type repoChecker struct {
@@ -1686,12 +1798,13 @@ func repoStatsCheck(checker *repoChecker) {
}
}
// CheckRepoStats checks the repository stats
func CheckRepoStats() {
if taskStatusTable.IsRunning(_CHECK_REPOs) {
if taskStatusTable.IsRunning(checkRepos) {
return
}
taskStatusTable.Start(_CHECK_REPOs)
defer taskStatusTable.Stop(_CHECK_REPOs)
taskStatusTable.Start(checkRepos)
defer taskStatusTable.Stop(checkRepos)
log.Trace("Doing: CheckRepoStats")
@@ -1780,6 +1893,7 @@ func CheckRepoStats() {
// ***** END: Repository.NumForks *****
}
// RepositoryList contains a list of repositories
type RepositoryList []*Repository
func (repos RepositoryList) loadAttributes(e Engine) error {
@@ -1797,7 +1911,10 @@ func (repos RepositoryList) loadAttributes(e Engine) error {
userIDs = append(userIDs, userID)
}
users := make([]*User, 0, len(userIDs))
if err := e.Where("id > 0").In("id", userIDs).Find(&users); err != nil {
if err := e.
Where("id > 0").
In("id", userIDs).
Find(&users); err != nil {
return fmt.Errorf("find users: %v", err)
}
for i := range users {
@@ -1809,10 +1926,12 @@ func (repos RepositoryList) loadAttributes(e Engine) error {
return nil
}
// LoadAttributes loads the attributes for the given RepositoryList
func (repos RepositoryList) LoadAttributes() error {
return repos.loadAttributes(x)
}
// MirrorRepositoryList contains the mirror repositories
type MirrorRepositoryList []*Repository
func (repos MirrorRepositoryList) loadAttributes(e Engine) error {
@@ -1830,7 +1949,10 @@ func (repos MirrorRepositoryList) loadAttributes(e Engine) error {
repoIDs = append(repoIDs, repos[i].ID)
}
mirrors := make([]*Mirror, 0, len(repoIDs))
if err := e.Where("id > 0").In("repo_id", repoIDs).Find(&mirrors); err != nil {
if err := e.
Where("id > 0").
In("repo_id", repoIDs).
Find(&mirrors); err != nil {
return fmt.Errorf("find mirrors: %v", err)
}
@@ -1844,6 +1966,7 @@ func (repos MirrorRepositoryList) loadAttributes(e Engine) error {
return nil
}
// LoadAttributes loads the attributes for the given MirrorRepositoryList
func (repos MirrorRepositoryList) LoadAttributes() error {
return repos.loadAttributes(x)
}
@@ -1893,7 +2016,7 @@ func watchRepo(e Engine, userID, repoID int64, watch bool) (err error) {
return err
}
// Watch or unwatch repository.
// WatchRepo watch or unwatch repository.
func WatchRepo(userID, repoID int64, watch bool) (err error) {
return watchRepo(x, userID, repoID, watch)
}
@@ -1908,10 +2031,12 @@ func GetWatchers(repoID int64) ([]*Watch, error) {
return getWatchers(x, repoID)
}
// Repository.GetWatchers returns range of users watching given repository.
// GetWatchers returns range of users watching given repository.
func (repo *Repository) GetWatchers(page int) ([]*User, error) {
users := make([]*User, 0, ItemsPerPage)
sess := x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).Where("watch.repo_id=?", repo.ID)
sess := x.
Limit(ItemsPerPage, (page-1)*ItemsPerPage).
Where("watch.repo_id=?", repo.ID)
if setting.UsePostgreSQL {
sess = sess.Join("LEFT", "watch", `"user".id=watch.user_id`)
} else {
@@ -1959,13 +2084,14 @@ func NotifyWatchers(act *Action) error {
// /_______ /|__| (____ /__|
// \/ \/
// Star contains the star information
type Star struct {
ID int64 `xorm:"pk autoincr"`
UID int64 `xorm:"UNIQUE(s)"`
RepoID int64 `xorm:"UNIQUE(s)"`
}
// Star or unstar repository.
// StarRepo star or unstar repository.
func StarRepo(userID, repoID int64, star bool) (err error) {
if star {
if IsStaring(userID, repoID) {
@@ -1997,9 +2123,12 @@ func IsStaring(userID, repoID int64) bool {
return has
}
// GetStargazers returns the users who gave stars to this repository
func (repo *Repository) GetStargazers(page int) ([]*User, error) {
users := make([]*User, 0, ItemsPerPage)
sess := x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).Where("star.repo_id=?", repo.ID)
sess := x.
Limit(ItemsPerPage, (page-1)*ItemsPerPage).
Where("star.repo_id=?", repo.ID)
if setting.UsePostgreSQL {
sess = sess.Join("LEFT", "star", `"user".id=star.uid`)
} else {
@@ -2018,10 +2147,13 @@ func (repo *Repository) GetStargazers(page int) ([]*User, error) {
// HasForkedRepo checks if given user has already forked a repository with given ID.
func HasForkedRepo(ownerID, repoID int64) (*Repository, bool) {
repo := new(Repository)
has, _ := x.Where("owner_id=? AND fork_id=?", ownerID, repoID).Get(repo)
has, _ := x.
Where("owner_id=? AND fork_id=?", ownerID, repoID).
Get(repo)
return repo, has
}
// ForkRepository forks a repository
func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) {
repo := &Repository{
OwnerID: u.ID,
@@ -2061,7 +2193,7 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
repoPath, fmt.Sprintf("ForkRepository(git update-server-info): %s", repoPath),
"git", "update-server-info")
if err != nil {
return nil, fmt.Errorf("git update-server-info: %v", err)
return nil, fmt.Errorf("git update-server-info: %v", stderr)
}
if err = createUpdateHook(repoPath); err != nil {
@@ -2071,6 +2203,7 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
return repo, sess.Commit()
}
// GetForks returns all the forks of the repository
func (repo *Repository) GetForks() ([]*Repository, error) {
forks := make([]*Repository, 0, repo.NumForks)
return forks, x.Find(&forks, &Repository{ForkID: repo.ID})
@@ -2084,6 +2217,7 @@ func (repo *Repository) GetForks() ([]*Repository, error) {
// \/ \/ \/ \/ \/
//
// CreateNewBranch creates a new repository branch
func (repo *Repository) CreateNewBranch(doer *User, oldBranchName, branchName string) (err error) {
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))

View File

@@ -5,14 +5,16 @@
package models
import (
"github.com/gogits/git-module"
"code.gitea.io/git"
)
// Branch holds the branch information
type Branch struct {
Path string
Name string
}
// GetBranchesByPath returns a branch by it's path
func GetBranchesByPath(path string) ([]*Branch, error) {
gitRepo, err := git.OpenRepository(path)
if err != nil {
@@ -34,24 +36,27 @@ func GetBranchesByPath(path string) ([]*Branch, error) {
return branches, nil
}
func (repo *Repository) GetBranch(br string) (*Branch, error) {
if !git.IsBranchExist(repo.RepoPath(), br) {
return nil, &ErrBranchNotExist{br}
// GetBranch returns a branch by it's name
func (repo *Repository) GetBranch(branch string) (*Branch, error) {
if !git.IsBranchExist(repo.RepoPath(), branch) {
return nil, &ErrBranchNotExist{branch}
}
return &Branch{
Path: repo.RepoPath(),
Name: br,
Name: branch,
}, nil
}
// GetBranches returns all the branches of a repository
func (repo *Repository) GetBranches() ([]*Branch, error) {
return GetBranchesByPath(repo.RepoPath())
}
func (br *Branch) GetCommit() (*git.Commit, error) {
gitRepo, err := git.OpenRepository(br.Path)
// GetCommit returns all the commits of a branch
func (branch *Branch) GetCommit() (*git.Commit, error) {
gitRepo, err := git.OpenRepository(branch.Path)
if err != nil {
return nil, err
}
return gitRepo.GetBranchCommit(br.Name)
return gitRepo.GetBranchCommit(branch.Name)
}

View File

@@ -16,13 +16,14 @@ type Collaboration struct {
Mode AccessMode `xorm:"DEFAULT 2 NOT NULL"`
}
// ModeI18nKey returns the collaboration mode I18n Key
func (c *Collaboration) ModeI18nKey() string {
switch c.Mode {
case ACCESS_MODE_READ:
case AccessModeRead:
return "repo.settings.collaboration.read"
case ACCESS_MODE_WRITE:
case AccessModeWrite:
return "repo.settings.collaboration.write"
case ACCESS_MODE_ADMIN:
case AccessModeAdmin:
return "repo.settings.collaboration.admin"
default:
return "repo.settings.collaboration.undefined"
@@ -42,7 +43,7 @@ func (repo *Repository) AddCollaborator(u *User) error {
} else if has {
return nil
}
collaboration.Mode = ACCESS_MODE_WRITE
collaboration.Mode = AccessModeWrite
sess := x.NewSession()
defer sessionRelease(sess)
@@ -67,7 +68,7 @@ func (repo *Repository) AddCollaborator(u *User) error {
}
func (repo *Repository) getCollaborations(e Engine) ([]*Collaboration, error) {
collaborations := make([]*Collaboration, 0)
var collaborations []*Collaboration
return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repo.ID})
}
@@ -105,7 +106,7 @@ func (repo *Repository) GetCollaborators() ([]*Collaborator, error) {
// ChangeCollaborationAccessMode sets new access mode for the collaboration.
func (repo *Repository) ChangeCollaborationAccessMode(uid int64, mode AccessMode) error {
// Discard invalid input
if mode <= ACCESS_MODE_NONE || mode > ACCESS_MODE_OWNER {
if mode <= AccessModeNone || mode > AccessModeOwner {
return nil
}
@@ -131,7 +132,10 @@ func (repo *Repository) ChangeCollaborationAccessMode(uid int64, mode AccessMode
return err
}
if _, err = sess.Id(collaboration.ID).AllCols().Update(collaboration); err != nil {
if _, err = sess.
Id(collaboration.ID).
AllCols().
Update(collaboration); err != nil {
return fmt.Errorf("update collaboration: %v", err)
} else if _, err = sess.Exec("UPDATE access SET mode = ? WHERE user_id = ? AND repo_id = ?", mode, uid, repo.ID); err != nil {
return fmt.Errorf("update access table: %v", err)

View File

@@ -18,11 +18,11 @@ import (
"github.com/Unknwon/com"
gouuid "github.com/satori/go.uuid"
git "github.com/gogits/git-module"
"code.gitea.io/git"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
)
// ___________ .___.__ __ ___________.__.__
@@ -50,6 +50,7 @@ func discardLocalRepoBranchChanges(localPath, branch string) error {
return nil
}
// DiscardLocalRepoBranchChanges discards the local repository branch changes
func (repo *Repository) DiscardLocalRepoBranchChanges(branch string) error {
return discardLocalRepoBranchChanges(repo.LocalCopyPath(), branch)
}
@@ -66,10 +67,12 @@ func checkoutNewBranch(repoPath, localPath, oldBranch, newBranch string) error {
return nil
}
// CheckoutNewBranch checks out a new branch
func (repo *Repository) CheckoutNewBranch(oldBranch, newBranch string) error {
return checkoutNewBranch(repo.RepoPath(), repo.LocalCopyPath(), oldBranch, newBranch)
}
// UpdateRepoFileOptions holds the repository file update options
type UpdateRepoFileOptions struct {
LastCommitID string
OldBranch string
@@ -101,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 {
@@ -151,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,
@@ -182,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)
}
@@ -223,6 +235,7 @@ func (repo *Repository) GetDiffPreview(branch, treePath, content string) (diff *
// \/ \/ \/ \/ \/ \/
//
// DeleteRepoFileOptions holds the repository delete file options
type DeleteRepoFileOptions struct {
LastCommitID string
OldBranch string
@@ -231,6 +244,7 @@ type DeleteRepoFileOptions struct {
Message string
}
// DeleteRepoFile deletes a repository file
func (repo *Repository) DeleteRepoFile(doer *User, opts DeleteRepoFileOptions) (err error) {
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
@@ -283,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,
@@ -351,6 +365,7 @@ func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err err
return upload, nil
}
// GetUploadByUUID returns the Upload by UUID
func GetUploadByUUID(uuid string) (*Upload, error) {
upload := &Upload{UUID: uuid}
has, err := x.Get(upload)
@@ -362,6 +377,7 @@ func GetUploadByUUID(uuid string) (*Upload, error) {
return upload, nil
}
// GetUploadsByUUIDs returns multiple uploads by UUIDS
func GetUploadsByUUIDs(uuids []string) ([]*Upload, error) {
if len(uuids) == 0 {
return []*Upload{}, nil
@@ -372,6 +388,7 @@ func GetUploadsByUUIDs(uuids []string) ([]*Upload, error) {
return uploads, x.In("uuid", uuids).Find(&uploads)
}
// DeleteUploads deletes multiple uploads
func DeleteUploads(uploads ...*Upload) (err error) {
if len(uploads) == 0 {
return nil
@@ -387,7 +404,9 @@ func DeleteUploads(uploads ...*Upload) (err error) {
for i := 0; i < len(uploads); i++ {
ids[i] = uploads[i].ID
}
if _, err = sess.In("id", ids).Delete(new(Upload)); err != nil {
if _, err = sess.
In("id", ids).
Delete(new(Upload)); err != nil {
return fmt.Errorf("delete uploads: %v", err)
}
@@ -405,10 +424,12 @@ func DeleteUploads(uploads ...*Upload) (err error) {
return sess.Commit()
}
// DeleteUpload delete a upload
func DeleteUpload(u *Upload) error {
return DeleteUploads(u)
}
// DeleteUploadByUUID deletes a upload by UUID
func DeleteUploadByUUID(uuid string) error {
upload, err := GetUploadByUUID(uuid)
if err != nil {
@@ -425,6 +446,7 @@ func DeleteUploadByUUID(uuid string) error {
return nil
}
// UploadRepoFileOptions contains the uploaded repository file options
type UploadRepoFileOptions struct {
LastCommitID string
OldBranch string
@@ -434,6 +456,7 @@ type UploadRepoFileOptions struct {
Files []string // In UUID format.
}
// UploadRepoFiles uploads files to a repository
func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions) (err error) {
if len(opts.Files) == 0 {
return nil
@@ -461,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 {
@@ -507,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

@@ -13,12 +13,13 @@ import (
"github.com/go-xorm/xorm"
"gopkg.in/ini.v1"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/sync"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/sync"
)
// MirrorQueue holds an UniqueQueue object of the mirror
var MirrorQueue = sync.NewUniqueQueue(setting.Repository.MirrorQueueLength)
// Mirror represents mirror information of a repository.
@@ -37,16 +38,19 @@ type Mirror struct {
address string `xorm:"-"`
}
// BeforeInsert will be invoked by XORM before inserting a record
func (m *Mirror) BeforeInsert() {
m.UpdatedUnix = time.Now().Unix()
m.NextUpdateUnix = m.NextUpdate.Unix()
}
// BeforeUpdate is invoked from XORM before updating this object.
func (m *Mirror) BeforeUpdate() {
m.UpdatedUnix = time.Now().Unix()
m.NextUpdateUnix = m.NextUpdate.Unix()
}
// AfterSet is invoked from XORM after setting the value of a field of this object.
func (m *Mirror) AfterSet(colName string, _ xorm.Cell) {
var err error
switch colName {
@@ -180,10 +184,12 @@ func updateMirror(e Engine, m *Mirror) error {
return err
}
// UpdateMirror updates the mirror
func UpdateMirror(m *Mirror) error {
return updateMirror(x, m)
}
// DeleteMirrorByRepoID deletes a mirror by repoID
func DeleteMirrorByRepoID(repoID int64) error {
_, err := x.Delete(&Mirror{RepoID: repoID})
return err
@@ -191,24 +197,26 @@ func DeleteMirrorByRepoID(repoID int64) error {
// MirrorUpdate checks and updates mirror repositories.
func MirrorUpdate() {
if taskStatusTable.IsRunning(_MIRROR_UPDATE) {
if taskStatusTable.IsRunning(mirrorUpdate) {
return
}
taskStatusTable.Start(_MIRROR_UPDATE)
defer taskStatusTable.Stop(_MIRROR_UPDATE)
taskStatusTable.Start(mirrorUpdate)
defer taskStatusTable.Stop(mirrorUpdate)
log.Trace("Doing: MirrorUpdate")
if err := x.Where("next_update_unix<=?", time.Now().Unix()).Iterate(new(Mirror), func(idx int, bean interface{}) error {
m := bean.(*Mirror)
if m.Repo == nil {
log.Error(4, "Disconnected mirror repository found: %d", m.ID)
return nil
}
if err := x.
Where("next_update_unix<=?", time.Now().Unix()).
Iterate(new(Mirror), func(idx int, bean interface{}) error {
m := bean.(*Mirror)
if m.Repo == nil {
log.Error(4, "Disconnected mirror repository found: %d", m.ID)
return nil
}
MirrorQueue.Add(m.RepoID)
return nil
}); err != nil {
MirrorQueue.Add(m.RepoID)
return nil
}); err != nil {
log.Error(4, "MirrorUpdate: %v", err)
}
}
@@ -223,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
}
@@ -233,12 +241,13 @@ 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
}
}
}
// InitSyncMirrors initializes a go routine to sync the mirros
func InitSyncMirrors() {
go SyncMirrors()
}

View File

@@ -1,11 +1,11 @@
package models_test
import (
. "github.com/gogits/gogs/models"
. "github.com/smartystreets/goconvey/convey"
"testing"
"github.com/gogits/gogs/modules/markdown"
. "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/markdown"
. "github.com/smartystreets/goconvey/convey"
)
func TestRepo(t *testing.T) {
@@ -24,7 +24,7 @@ func TestRepo(t *testing.T) {
Convey("It should be nil even if other settings are present", func() {
repo.EnableExternalTracker = false
repo.ExternalTrackerFormat = "http://someurl.com/{user}/{repo}/{issue}"
repo.ExternalTrackerStyle = markdown.ISSUE_NAME_STYLE_NUMERIC
repo.ExternalTrackerStyle = markdown.IssueNameStyleNumeric
So(repo.ComposeMetas(), ShouldEqual, map[string]string(nil))
})
})
@@ -33,17 +33,17 @@ func TestRepo(t *testing.T) {
repo.EnableExternalTracker = true
Convey("It should default to numeric issue style", func() {
metas := repo.ComposeMetas()
So(metas["style"], ShouldEqual, markdown.ISSUE_NAME_STYLE_NUMERIC)
So(metas["style"], ShouldEqual, markdown.IssueNameStyleNumeric)
})
Convey("It should pass through numeric issue style setting", func() {
repo.ExternalTrackerStyle = markdown.ISSUE_NAME_STYLE_NUMERIC
repo.ExternalTrackerStyle = markdown.IssueNameStyleNumeric
metas := repo.ComposeMetas()
So(metas["style"], ShouldEqual, markdown.ISSUE_NAME_STYLE_NUMERIC)
So(metas["style"], ShouldEqual, markdown.IssueNameStyleNumeric)
})
Convey("It should pass through alphanumeric issue style setting", func() {
repo.ExternalTrackerStyle = markdown.ISSUE_NAME_STYLE_ALPHANUMERIC
repo.ExternalTrackerStyle = markdown.IssueNameStyleAlphanumeric
metas := repo.ComposeMetas()
So(metas["style"], ShouldEqual, markdown.ISSUE_NAME_STYLE_ALPHANUMERIC)
So(metas["style"], ShouldEqual, markdown.IssueNameStyleAlphanumeric)
})
Convey("It should contain the user name", func() {
metas := repo.ComposeMetas()

View File

@@ -22,23 +22,25 @@ import (
"github.com/go-xorm/xorm"
"golang.org/x/crypto/ssh"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
)
const (
_TPL_PUBLICK_KEY = `command="%s serv key-%d --config='%s'",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n"
tplPublicKey = `command="%s serv key-%d --config='%s'",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n"
)
var sshOpLocker sync.Mutex
// KeyType specifies the key type
type KeyType int
const (
KEY_TYPE_USER = iota + 1
KEY_TYPE_DEPLOY
// KeyTypeUser specifies the user key
KeyTypeUser = iota + 1
// KeyTypeDeploy specifies the deploy key
KeyTypeDeploy
)
// PublicKey represents a user or deploy SSH public key.
@@ -59,33 +61,36 @@ type PublicKey struct {
HasUsed bool `xorm:"-"`
}
func (k *PublicKey) BeforeInsert() {
k.CreatedUnix = time.Now().Unix()
// BeforeInsert will be invoked by XORM before inserting a record
func (key *PublicKey) BeforeInsert() {
key.CreatedUnix = time.Now().Unix()
}
func (k *PublicKey) BeforeUpdate() {
k.UpdatedUnix = time.Now().Unix()
// BeforeUpdate is invoked from XORM before updating this object.
func (key *PublicKey) BeforeUpdate() {
key.UpdatedUnix = time.Now().Unix()
}
func (k *PublicKey) AfterSet(colName string, _ xorm.Cell) {
// AfterSet is invoked from XORM after setting the value of a field of this object.
func (key *PublicKey) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
k.Created = time.Unix(k.CreatedUnix, 0).Local()
key.Created = time.Unix(key.CreatedUnix, 0).Local()
case "updated_unix":
k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
k.HasUsed = k.Updated.After(k.Created)
k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(time.Now())
key.Updated = time.Unix(key.UpdatedUnix, 0).Local()
key.HasUsed = key.Updated.After(key.Created)
key.HasRecentActivity = key.Updated.Add(7 * 24 * time.Hour).After(time.Now())
}
}
// OmitEmail returns content of public key without email address.
func (k *PublicKey) OmitEmail() string {
return strings.Join(strings.Split(k.Content, " ")[:2], " ")
func (key *PublicKey) OmitEmail() string {
return strings.Join(strings.Split(key.Content, " ")[:2], " ")
}
// AuthorizedString returns formatted public key string for authorized_keys file.
func (key *PublicKey) AuthorizedString() string {
return fmt.Sprintf(_TPL_PUBLICK_KEY, setting.AppPath, key.ID, setting.CustomConf, key.Content)
return fmt.Sprintf(tplPublicKey, setting.AppPath, key.ID, setting.CustomConf, key.Content)
}
func extractTypeFromBase64Key(key string) (string, error) {
@@ -106,6 +111,8 @@ func extractTypeFromBase64Key(key string) (string, error) {
func parseKeyString(content string) (string, error) {
// Transform all legal line endings to a single "\n".
content = strings.NewReplacer("\r\n", "\n", "\r", "\n").Replace(content)
// remove trailing newline (and beginning spaces too)
content = strings.TrimSpace(content)
lines := strings.Split(content, "\n")
var keyType, keyContent, keyComment string
@@ -352,7 +359,7 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
func checkKeyContent(content string) error {
has, err := x.Get(&PublicKey{
Content: content,
Type: KEY_TYPE_USER,
Type: KeyTypeUser,
})
if err != nil {
return err
@@ -366,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
}
@@ -398,7 +410,9 @@ func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
}
// Key name of same user cannot be duplicated.
has, err := x.Where("owner_id = ? AND name = ?", ownerID, name).Get(new(PublicKey))
has, err := x.
Where("owner_id = ? AND name = ?", ownerID, name).
Get(new(PublicKey))
if err != nil {
return nil, err
} else if has {
@@ -415,8 +429,8 @@ func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
OwnerID: ownerID,
Name: name,
Content: content,
Mode: ACCESS_MODE_WRITE,
Type: KEY_TYPE_USER,
Mode: AccessModeWrite,
Type: KeyTypeUser,
}
if err = addKey(sess, key); err != nil {
return nil, fmt.Errorf("addKey: %v", err)
@@ -428,7 +442,9 @@ func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
// GetPublicKeyByID returns public key by given ID.
func GetPublicKeyByID(keyID int64) (*PublicKey, error) {
key := new(PublicKey)
has, err := x.Id(keyID).Get(key)
has, err := x.
Id(keyID).
Get(key)
if err != nil {
return nil, err
} else if !has {
@@ -441,7 +457,9 @@ func GetPublicKeyByID(keyID int64) (*PublicKey, error) {
// and returns public key found.
func SearchPublicKeyByContent(content string) (*PublicKey, error) {
key := new(PublicKey)
has, err := x.Where("content like ?", content+"%").Get(key)
has, err := x.
Where("content like ?", content+"%").
Get(key)
if err != nil {
return nil, err
} else if !has {
@@ -453,7 +471,9 @@ func SearchPublicKeyByContent(content string) (*PublicKey, error) {
// ListPublicKeys returns a list of public keys belongs to given user.
func ListPublicKeys(uid int64) ([]*PublicKey, error) {
keys := make([]*PublicKey, 0, 5)
return keys, x.Where("owner_id = ?", uid).Find(&keys)
return keys, x.
Where("owner_id = ?", uid).
Find(&keys)
}
// UpdatePublicKey updates given public key.
@@ -468,7 +488,7 @@ func deletePublicKeys(e *xorm.Session, keyIDs ...int64) error {
return nil
}
_, err := e.In("id", strings.Join(base.Int64sToStrings(keyIDs), ",")).Delete(new(PublicKey))
_, err := e.In("id", keyIDs).Delete(new(PublicKey))
return err
}
@@ -564,45 +584,52 @@ type DeployKey struct {
HasUsed bool `xorm:"-"`
}
func (k *DeployKey) BeforeInsert() {
k.CreatedUnix = time.Now().Unix()
// BeforeInsert will be invoked by XORM before inserting a record
func (key *DeployKey) BeforeInsert() {
key.CreatedUnix = time.Now().Unix()
}
func (k *DeployKey) BeforeUpdate() {
k.UpdatedUnix = time.Now().Unix()
// BeforeUpdate is invoked from XORM before updating this object.
func (key *DeployKey) BeforeUpdate() {
key.UpdatedUnix = time.Now().Unix()
}
func (k *DeployKey) AfterSet(colName string, _ xorm.Cell) {
// AfterSet is invoked from XORM after setting the value of a field of this object.
func (key *DeployKey) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
k.Created = time.Unix(k.CreatedUnix, 0).Local()
key.Created = time.Unix(key.CreatedUnix, 0).Local()
case "updated_unix":
k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
k.HasUsed = k.Updated.After(k.Created)
k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(time.Now())
key.Updated = time.Unix(key.UpdatedUnix, 0).Local()
key.HasUsed = key.Updated.After(key.Created)
key.HasRecentActivity = key.Updated.Add(7 * 24 * time.Hour).After(time.Now())
}
}
// GetContent gets associated public key content.
func (k *DeployKey) GetContent() error {
pkey, err := GetPublicKeyByID(k.KeyID)
func (key *DeployKey) GetContent() error {
pkey, err := GetPublicKeyByID(key.KeyID)
if err != nil {
return err
}
k.Content = pkey.Content
key.Content = pkey.Content
return nil
}
func checkDeployKey(e Engine, keyID, repoID int64, name string) error {
// Note: We want error detail, not just true or false here.
has, err := e.Where("key_id = ? AND repo_id = ?", keyID, repoID).Get(new(DeployKey))
has, err := e.
Where("key_id = ? AND repo_id = ?", keyID, repoID).
Get(new(DeployKey))
if err != nil {
return err
} else if has {
return ErrDeployKeyAlreadyExist{keyID, repoID}
}
has, err = e.Where("repo_id = ? AND name = ?", repoID, name).Get(new(DeployKey))
has, err = e.
Where("repo_id = ? AND name = ?", repoID, name).
Get(new(DeployKey))
if err != nil {
return err
} else if has {
@@ -630,7 +657,9 @@ func addDeployKey(e *xorm.Session, keyID, repoID int64, name, fingerprint string
// HasDeployKey returns true if public key is a deploy key of given repository.
func HasDeployKey(keyID, repoID int64) bool {
has, _ := x.Where("key_id = ? AND repo_id = ?", keyID, repoID).Get(new(DeployKey))
has, _ := x.
Where("key_id = ? AND repo_id = ?", keyID, repoID).
Get(new(DeployKey))
return has
}
@@ -642,8 +671,8 @@ func AddDeployKey(repoID int64, name, content string) (*DeployKey, error) {
pkey := &PublicKey{
Content: content,
Mode: ACCESS_MODE_READ,
Type: KEY_TYPE_DEPLOY,
Mode: AccessModeRead,
Type: KeyTypeDeploy,
}
has, err := x.Get(pkey)
if err != nil {
@@ -720,7 +749,7 @@ func DeleteDeployKey(doer *User, id int64) error {
if err != nil {
return fmt.Errorf("GetRepositoryByID: %v", err)
}
yes, err := HasAccess(doer, repo, ACCESS_MODE_ADMIN)
yes, err := HasAccess(doer, repo, AccessModeAdmin)
if err != nil {
return fmt.Errorf("HasAccess: %v", err)
} else if !yes {
@@ -739,7 +768,9 @@ func DeleteDeployKey(doer *User, id int64) error {
}
// Check if this is the last reference to same key content.
has, err := sess.Where("key_id = ?", key.KeyID).Get(new(DeployKey))
has, err := sess.
Where("key_id = ?", key.KeyID).
Get(new(DeployKey))
if err != nil {
return err
} else if !has {
@@ -754,5 +785,7 @@ func DeleteDeployKey(doer *User, id int64) error {
// ListDeployKeys returns all deploy keys by given repository ID.
func ListDeployKeys(repoID int64) ([]*DeployKey, error) {
keys := make([]*DeployKey, 0, 5)
return keys, x.Where("repo_id = ?", repoID).Find(&keys)
return keys, x.
Where("repo_id = ?", repoID).
Find(&keys)
}

View File

@@ -11,7 +11,7 @@ import (
. "github.com/smartystreets/goconvey/convey"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/modules/setting"
)
func init() {

View File

@@ -10,7 +10,7 @@ import (
"github.com/go-xorm/xorm"
gouuid "github.com/satori/go.uuid"
"github.com/gogits/gogs/modules/base"
"code.gitea.io/gitea/modules/base"
)
// AccessToken represents a personal access token.
@@ -28,14 +28,17 @@ type AccessToken struct {
HasUsed bool `xorm:"-"`
}
// BeforeInsert will be invoked by XORM before inserting a record representing this object.
func (t *AccessToken) BeforeInsert() {
t.CreatedUnix = time.Now().Unix()
}
// BeforeUpdate is invoked from XORM before updating this object.
func (t *AccessToken) BeforeUpdate() {
t.UpdatedUnix = time.Now().Unix()
}
// AfterSet is invoked from XORM after setting the value of a field of this object.
func (t *AccessToken) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
@@ -72,7 +75,10 @@ func GetAccessTokenBySHA(sha string) (*AccessToken, error) {
// ListAccessTokens returns a list of access tokens belongs to given user.
func ListAccessTokens(uid int64) ([]*AccessToken, error) {
tokens := make([]*AccessToken, 0, 5)
return tokens, x.Where("uid=?", uid).Desc("id").Find(&tokens)
return tokens, x.
Where("uid=?", uid).
Desc("id").
Find(&tokens)
}
// UpdateAccessToken updates information of access token.
@@ -82,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

@@ -10,11 +10,12 @@ import (
"os/exec"
"strings"
git "github.com/gogits/git-module"
"code.gitea.io/git"
"github.com/gogits/gogs/modules/log"
"code.gitea.io/gitea/modules/log"
)
// UpdateTask defines an UpdateTask
type UpdateTask struct {
ID int64 `xorm:"pk autoincr"`
UUID string `xorm:"index"`
@@ -23,6 +24,7 @@ type UpdateTask struct {
NewCommitID string
}
// AddUpdateTask adds an UpdateTask
func AddUpdateTask(task *UpdateTask) error {
_, err := x.Insert(task)
return err
@@ -42,6 +44,7 @@ func GetUpdateTaskByUUID(uuid string) (*UpdateTask, error) {
return task, nil
}
// DeleteUpdateTaskByUUID deletes an UpdateTask from the database
func DeleteUpdateTaskByUUID(uuid string) error {
_, err := x.Delete(&UpdateTask{UUID: uuid})
return err
@@ -60,8 +63,9 @@ func CommitToPushCommit(commit *git.Commit) *PushCommit {
}
}
// ListToPushCommits transforms a list.List to PushCommits type.
func ListToPushCommits(l *list.List) *PushCommits {
commits := make([]*PushCommit, 0)
var commits []*PushCommit
var actEmail string
for e := l.Front(); e != nil; e = e.Next() {
commit := e.Value.(*git.Commit)
@@ -73,6 +77,7 @@ func ListToPushCommits(l *list.List) *PushCommits {
return &PushCommits{l.Len(), commits, "", nil}
}
// PushUpdateOptions defines the push update options
type PushUpdateOptions struct {
PusherID int64
PusherName string
@@ -86,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)
@@ -101,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
}
@@ -122,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,10 +8,12 @@ import (
"bytes"
"container/list"
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
"errors"
"fmt"
"image"
// Needed for jpeg support
_ "image/jpeg"
"image/png"
"os"
@@ -23,31 +25,47 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/nfnt/resize"
"golang.org/x/crypto/pbkdf2"
"github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client"
"code.gitea.io/git"
api "code.gitea.io/sdk/gitea"
"github.com/gogits/gogs/modules/avatar"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting"
"code.gitea.io/gitea/modules/avatar"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markdown"
"code.gitea.io/gitea/modules/setting"
)
// UserType defines the user type
type UserType int
const (
USER_TYPE_INDIVIDUAL UserType = iota // Historic reason to make it starts at 0.
USER_TYPE_ORGANIZATION
// UserTypeIndividual defines an individual user
UserTypeIndividual UserType = iota // Historic reason to make it starts at 0.
// UserTypeOrganization defines an organization
UserTypeOrganization
)
var (
ErrUserNotKeyOwner = errors.New("User does not the owner of public key")
ErrEmailNotExist = errors.New("E-mail does not exist")
ErrEmailNotActivated = errors.New("E-mail address has not been activated")
ErrUserNameIllegal = errors.New("User name contains illegal characters")
// ErrUserNotKeyOwner user does not own this key error
ErrUserNotKeyOwner = errors.New("User does not own this public key")
// ErrEmailNotExist e-mail does not exist error
ErrEmailNotExist = errors.New("E-mail does not exist")
// ErrEmailNotActivated e-mail address has not been activated error
ErrEmailNotActivated = errors.New("E-mail address has not been activated")
// ErrUserNameIllegal user name contains illegal characters error
ErrUserNameIllegal = errors.New("User name contains illegal characters")
// ErrLoginSourceNotActived login source is not actived error
ErrLoginSourceNotActived = errors.New("Login source is not actived")
ErrUnsupportedLoginType = errors.New("Login source is unknown")
// ErrUnsupportedLoginType login source is unknown error
ErrUnsupportedLoginType = errors.New("Login source is unknown")
)
// User represents the object of individual and member of organization.
@@ -71,14 +89,16 @@ type User struct {
Rands string `xorm:"VARCHAR(10)"`
Salt string `xorm:"VARCHAR(10)"`
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"`
UpdatedUnix int64
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"`
UpdatedUnix int64
LastLogin time.Time `xorm:"-"`
LastLoginUnix int64
// Remember visibility choice for convenience, true for private
LastRepoVisibility bool
// Maximum repository creation limit, -1 means use gloabl default
// Maximum repository creation limit, -1 means use global default
MaxRepoCreation int `xorm:"NOT NULL DEFAULT -1"`
// Permissions
@@ -105,13 +125,18 @@ type User struct {
NumMembers int
Teams []*Team `xorm:"-"`
Members []*User `xorm:"-"`
// Preferences
DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"`
}
// BeforeInsert is invoked from XORM before inserting an object of this type.
func (u *User) BeforeInsert() {
u.CreatedUnix = time.Now().Unix()
u.UpdatedUnix = u.CreatedUnix
}
// BeforeUpdate is invoked from XORM before updating this object.
func (u *User) BeforeUpdate() {
if u.MaxRepoCreation < -1 {
u.MaxRepoCreation = -1
@@ -119,6 +144,18 @@ func (u *User) BeforeUpdate() {
u.UpdatedUnix = time.Now().Unix()
}
// SetLastLogin set time to last login
func (u *User) SetLastLogin() {
u.LastLoginUnix = time.Now().Unix()
}
// UpdateDiffViewStyle updates the users diff view style
func (u *User) UpdateDiffViewStyle(style string) error {
u.DiffViewStyle = style
return UpdateUser(u)
}
// AfterSet is invoked from XORM after setting the value of a field of this object.
func (u *User) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "full_name":
@@ -127,22 +164,25 @@ func (u *User) AfterSet(colName string, _ xorm.Cell) {
u.Created = time.Unix(u.CreatedUnix, 0).Local()
case "updated_unix":
u.Updated = time.Unix(u.UpdatedUnix, 0).Local()
case "last_login_unix":
u.LastLogin = time.Unix(u.LastLoginUnix, 0).Local()
}
}
// APIFormat converts a User to api.User
func (u *User) APIFormat() *api.User {
return &api.User{
ID: u.ID,
UserName: u.Name,
FullName: u.FullName,
Email: u.Email,
AvatarUrl: u.AvatarLink(),
AvatarURL: u.AvatarLink(),
}
}
// returns true if user login type is LOGIN_PLAIN.
// IsLocal returns true if user login type is LoginPlain.
func (u *User) IsLocal() bool {
return u.LoginType <= LOGIN_PLAIN
return u.LoginType <= LoginPlain
}
// HasForkedRepo checks if user has already forked a repository with given ID.
@@ -151,6 +191,7 @@ func (u *User) HasForkedRepo(repoID int64) bool {
return has
}
// RepoCreationNum returns the number of repositories created by the user
func (u *User) RepoCreationNum() int {
if u.MaxRepoCreation <= -1 {
return setting.Repository.MaxCreationLimit
@@ -158,6 +199,7 @@ func (u *User) RepoCreationNum() int {
return u.MaxRepoCreation
}
// CanCreateRepo returns if user login can create a repository
func (u *User) CanCreateRepo() bool {
if u.MaxRepoCreation <= -1 {
if setting.Repository.MaxCreationLimit <= -1 {
@@ -181,14 +223,14 @@ func (u *User) CanImportLocal() bool {
// DashboardLink returns the user dashboard page link.
func (u *User) DashboardLink() string {
if u.IsOrganization() {
return setting.AppSubUrl + "/org/" + u.Name + "/dashboard/"
return setting.AppSubURL + "/org/" + u.Name + "/dashboard/"
}
return setting.AppSubUrl + "/"
return setting.AppSubURL + "/"
}
// HomeLink returns the user or organization home page link.
func (u *User) HomeLink() string {
return setting.AppSubUrl + "/" + u.Name
return setting.AppSubURL + "/" + u.Name
}
// GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
@@ -244,17 +286,17 @@ func (u *User) GenerateRandomAvatar() error {
// which includes app sub-url as prefix. However, it is possible
// to return full URL if user enables Gravatar-like service.
func (u *User) RelAvatarLink() string {
defaultImgUrl := setting.AppSubUrl + "/img/avatar_default.png"
defaultImgURL := setting.AppSubURL + "/img/avatar_default.png"
if u.ID == -1 {
return defaultImgUrl
return defaultImgURL
}
switch {
case u.UseCustomAvatar:
if !com.IsExist(u.CustomAvatarPath()) {
return defaultImgUrl
return defaultImgURL
}
return setting.AppSubUrl + "/avatars/" + com.ToStr(u.ID)
return setting.AppSubURL + "/avatars/" + com.ToStr(u.ID)
case setting.DisableGravatar, setting.OfflineMode:
if !com.IsExist(u.CustomAvatarPath()) {
if err := u.GenerateRandomAvatar(); err != nil {
@@ -262,7 +304,7 @@ func (u *User) RelAvatarLink() string {
}
}
return setting.AppSubUrl + "/avatars/" + com.ToStr(u.ID)
return setting.AppSubURL + "/avatars/" + com.ToStr(u.ID)
}
return base.AvatarLink(u.AvatarEmail)
}
@@ -271,15 +313,17 @@ func (u *User) RelAvatarLink() string {
func (u *User) AvatarLink() string {
link := u.RelAvatarLink()
if link[0] == '/' && link[1] != '/' {
return setting.AppUrl + strings.TrimPrefix(link, setting.AppSubUrl)[1:]
return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL)[1:]
}
return link
}
// User.GetFollwoers returns range of user's followers.
// GetFollowers returns range of user's followers.
func (u *User) GetFollowers(page int) ([]*User, error) {
users := make([]*User, 0, ItemsPerPage)
sess := x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).Where("follow.follow_id=?", u.ID)
sess := x.
Limit(ItemsPerPage, (page-1)*ItemsPerPage).
Where("follow.follow_id=?", u.ID)
if setting.UsePostgreSQL {
sess = sess.Join("LEFT", "follow", `"user".id=follow.user_id`)
} else {
@@ -288,6 +332,7 @@ func (u *User) GetFollowers(page int) ([]*User, error) {
return users, sess.Find(&users)
}
// IsFollowing returns true if user is following followID.
func (u *User) IsFollowing(followID int64) bool {
return IsFollowing(u.ID, followID)
}
@@ -295,7 +340,9 @@ func (u *User) IsFollowing(followID int64) bool {
// GetFollowing returns range of user's following.
func (u *User) GetFollowing(page int) ([]*User, error) {
users := make([]*User, 0, ItemsPerPage)
sess := x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).Where("follow.user_id=?", u.ID)
sess := x.
Limit(ItemsPerPage, (page-1)*ItemsPerPage).
Where("follow.user_id=?", u.ID)
if setting.UsePostgreSQL {
sess = sess.Join("LEFT", "follow", `"user".id=follow.follow_id`)
} else {
@@ -315,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)
}
@@ -323,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.
@@ -334,7 +381,7 @@ func (u *User) UploadAvatar(data []byte) error {
return fmt.Errorf("Decode: %v", err)
}
m := resize.Resize(avatar.AVATAR_SIZE, avatar.AVATAR_SIZE, img, resize.NearestNeighbor)
m := resize.Resize(avatar.AvatarSize, avatar.AvatarSize, img, resize.NearestNeighbor)
sess := x.NewSession()
defer sessionRelease(sess)
@@ -347,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)
@@ -364,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 {
@@ -375,7 +428,7 @@ func (u *User) DeleteAvatar() error {
// IsAdminOfRepo returns true if user has admin or higher access of repository.
func (u *User) IsAdminOfRepo(repo *Repository) bool {
has, err := HasAccess(u, repo, ACCESS_MODE_ADMIN)
has, err := HasAccess(u, repo, AccessModeAdmin)
if err != nil {
log.Error(3, "HasAccess: %v", err)
}
@@ -384,7 +437,7 @@ func (u *User) IsAdminOfRepo(repo *Repository) bool {
// IsWriterOfRepo returns true if user has write access to given repository.
func (u *User) IsWriterOfRepo(repo *Repository) bool {
has, err := HasAccess(u, repo, ACCESS_MODE_WRITE)
has, err := HasAccess(u, repo, AccessModeWrite)
if err != nil {
log.Error(3, "HasAccess: %v", err)
}
@@ -393,21 +446,23 @@ func (u *User) IsWriterOfRepo(repo *Repository) bool {
// IsOrganization returns true if user is actually a organization.
func (u *User) IsOrganization() bool {
return u.Type == USER_TYPE_ORGANIZATION
return u.Type == UserTypeOrganization
}
// IsUserOrgOwner returns true if user is in the owner team of given organization.
func (u *User) IsUserOrgOwner(orgId int64) bool {
return IsOrganizationOwner(orgId, u.ID)
func (u *User) IsUserOrgOwner(orgID int64) bool {
return IsOrganizationOwner(orgID, u.ID)
}
// IsPublicMember returns true if user public his/her membership in give organization.
func (u *User) IsPublicMember(orgId int64) bool {
return IsPublicMembership(orgId, u.ID)
func (u *User) IsPublicMember(orgID int64) bool {
return IsPublicMembership(orgID, u.ID)
}
func (u *User) getOrganizationCount(e Engine) (int64, error) {
return e.Where("uid=?", u.ID).Count(new(OrgUser))
return e.
Where("uid=?", u.ID).
Count(new(OrgUser))
}
// GetOrganizationCount returns count of membership of organization of user.
@@ -421,7 +476,7 @@ func (u *User) GetRepositories(page, pageSize int) (err error) {
return err
}
// GetRepositories returns mirror repositories that user owns, including private repositories.
// GetMirrorRepositories returns mirror repositories that user owns, including private repositories.
func (u *User) GetMirrorRepositories() ([]*Repository, error) {
return GetUserMirrorRepositories(u.ID)
}
@@ -458,6 +513,7 @@ func (u *User) DisplayName() string {
return u.Name
}
// ShortName ellipses username to length
func (u *User) ShortName(length int) string {
return base.EllipsisString(u.Name, length)
}
@@ -470,11 +526,13 @@ func IsUserExist(uid int64, name string) (bool, error) {
if len(name) == 0 {
return false, nil
}
return x.Where("id!=?", uid).Get(&User{LowerName: strings.ToLower(name)})
return x.
Where("id!=?", uid).
Get(&User{LowerName: strings.ToLower(name)})
}
// GetUserSalt returns a ramdom user salt token.
func GetUserSalt() string {
func GetUserSalt() (string, error) {
return base.GetRandomString(10)
}
@@ -488,12 +546,12 @@ func NewGhostUser() *User {
}
var (
reversedUsernames = []string{"debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new", ".", ".."}
reversedUserPatterns = []string{"*.keys"}
reservedUsernames = []string{"assets", "css", "img", "js", "less", "plugins", "debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new", ".", ".."}
reservedUserPatterns = []string{"*.keys"}
)
// isUsableName checks if name is reserved or pattern of name is not allowed
// based on given reversed names and patterns.
// based on given reserved names and patterns.
// Names are exact match, patterns can be prefix or suffix match with placeholder '*'.
func isUsableName(names, patterns []string, name string) error {
name = strings.TrimSpace(strings.ToLower(name))
@@ -517,8 +575,9 @@ func isUsableName(names, patterns []string, name string) error {
return nil
}
// IsUsableUsername returns an error when a username is reserved
func IsUsableUsername(name string) error {
return isUsableName(reversedUsernames, reversedUserPatterns, name)
return isUsableName(reservedUsernames, reservedUserPatterns, name)
}
// CreateUser creates record of a new user.
@@ -545,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
@@ -566,7 +629,9 @@ func CreateUser(u *User) (err error) {
}
func countUsers(e Engine) int64 {
count, _ := e.Where("type=0").Count(new(User))
count, _ := e.
Where("type=0").
Count(new(User))
return count
}
@@ -578,7 +643,11 @@ func CountUsers() int64 {
// Users returns number of users in given page.
func Users(page, pageSize int) ([]*User, error) {
users := make([]*User, 0, pageSize)
return users, x.Limit(pageSize, (page-1)*pageSize).Where("type=0").Asc("id").Find(&users)
return users, x.
Limit(pageSize, (page-1)*pageSize).
Where("type=0").
Asc("name").
Find(&users)
}
// get user by erify code
@@ -599,7 +668,7 @@ func getVerifyUser(code string) (user *User) {
return nil
}
// verify active code when active account
// VerifyUserActiveCode verifies active code when active account
func VerifyUserActiveCode(code string) (user *User) {
minutes := setting.Service.ActiveCodeLives
@@ -615,7 +684,7 @@ func VerifyUserActiveCode(code string) (user *User) {
return nil
}
// verify active code when active account
// VerifyActiveEmailCode verifies active email code when active account
func VerifyActiveEmailCode(code, email string) *EmailAddress {
minutes := setting.Service.ActiveCodeLives
@@ -652,11 +721,13 @@ func ChangeUserName(u *User, newUserName string) (err error) {
}
// Delete all local copies of repository wiki that user owns.
if err = x.Where("owner_id=?", u.ID).Iterate(new(Repository), func(idx int, bean interface{}) error {
repo := bean.(*Repository)
RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
return nil
}); err != nil {
if err = x.
Where("owner_id=?", u.ID).
Iterate(new(Repository), func(idx int, bean interface{}) error {
repo := bean.(*Repository)
RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
return nil
}); err != nil {
return fmt.Errorf("Delete repository wiki local copy: %v", err)
}
@@ -667,7 +738,11 @@ func updateUser(e Engine, u *User) error {
// Organization does not need email
if !u.IsOrganization() {
u.Email = strings.ToLower(u.Email)
has, err := e.Where("id!=?", u.ID).And("type=?", u.Type).And("email=?", u.Email).Get(new(User))
has, err := e.
Where("id!=?", u.ID).
And("type=?", u.Type).
And("email=?", u.Email).
Get(new(User))
if err != nil {
return err
} else if has {
@@ -803,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
}
@@ -834,7 +918,9 @@ func DeleteUser(u *User) (err error) {
// DeleteInactivateUsers deletes all inactivate users and email addresses.
func DeleteInactivateUsers() (err error) {
users := make([]*User, 0, 10)
if err = x.Where("is_active = ?", false).Find(&users); err != nil {
if err = x.
Where("is_active = ?", false).
Find(&users); err != nil {
return fmt.Errorf("get all inactive users: %v", err)
}
// FIXME: should only update authorized_keys file once after all deletions.
@@ -848,7 +934,9 @@ func DeleteInactivateUsers() (err error) {
}
}
_, err = x.Where("is_activated = ?", false).Delete(new(EmailAddress))
_, err = x.
Where("is_activated = ?", false).
Delete(new(EmailAddress))
return err
}
@@ -857,15 +945,19 @@ func UserPath(userName string) string {
return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
}
// GetUserByKeyID get user information by user's public key id
func GetUserByKeyID(keyID int64) (*User, error) {
user := new(User)
has, err := x.Sql("SELECT a.* FROM `user` AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?", keyID).Get(user)
var user User
has, err := x.Join("INNER", "public_key", "`public_key`.owner_id = `user`.id").
Where("`public_key`.id=?", keyID).
Get(&user)
if err != nil {
return nil, err
} else if !has {
return nil, ErrUserNotKeyOwner
}
return user, nil
if !has {
return nil, ErrUserNotExist{0, "", keyID}
}
return &user, nil
}
func getUserByID(e Engine, id int64) (*User, error) {
@@ -874,7 +966,7 @@ func getUserByID(e Engine, id int64) (*User, error) {
if err != nil {
return nil, err
} else if !has {
return nil, ErrUserNotExist{id, ""}
return nil, ErrUserNotExist{id, "", 0}
}
return u, nil
}
@@ -886,11 +978,11 @@ func GetUserByID(id int64) (*User, error) {
// GetAssigneeByID returns the user with write access of repository by given ID.
func GetAssigneeByID(repo *Repository, userID int64) (*User, error) {
has, err := HasAccess(&User{ID: userID}, repo, ACCESS_MODE_WRITE)
has, err := HasAccess(&User{ID: userID}, repo, AccessModeWrite)
if err != nil {
return nil, err
} else if !has {
return nil, ErrUserNotExist{userID, ""}
return nil, ErrUserNotExist{userID, "", 0}
}
return GetUserByID(userID)
}
@@ -898,14 +990,14 @@ func GetAssigneeByID(repo *Repository, userID int64) (*User, error) {
// GetUserByName returns user by given name.
func GetUserByName(name string) (*User, error) {
if len(name) == 0 {
return nil, ErrUserNotExist{0, name}
return nil, ErrUserNotExist{0, name, 0}
}
u := &User{LowerName: strings.ToLower(name)}
has, err := x.Get(u)
if err != nil {
return nil, err
} else if !has {
return nil, ErrUserNotExist{0, name}
return nil, ErrUserNotExist{0, name, 0}
}
return u, nil
}
@@ -923,6 +1015,16 @@ func GetUserEmailsByNames(names []string) []string {
return mails
}
// GetUsersByIDs returns all resolved users from a list of Ids.
func GetUsersByIDs(ids []int64) ([]*User, error) {
ous := make([]*User, 0, len(ids))
err := x.
In("id", ids).
Asc("name").
Find(&ous)
return ous, err
}
// GetUserIDsByNames returns a slice of ids corresponds to names.
func GetUserIDsByNames(names []string) []int64 {
ids := make([]int64, 0, len(names))
@@ -981,7 +1083,7 @@ func ValidateCommitsWithEmails(oldCommits *list.List) *list.List {
// GetUserByEmail returns the user object by given e-mail if exists.
func GetUserByEmail(email string) (*User, error) {
if len(email) == 0 {
return nil, ErrUserNotExist{0, "email"}
return nil, ErrUserNotExist{0, email, 0}
}
email = strings.ToLower(email)
@@ -1005,9 +1107,10 @@ func GetUserByEmail(email string) (*User, error) {
return GetUserByID(emailAddress.UID)
}
return nil, ErrUserNotExist{0, email}
return nil, ErrUserNotExist{0, email, 0}
}
// SearchUserOptions contains the options for searching
type SearchUserOptions struct {
Keyword string
Type UserType
@@ -1034,7 +1137,8 @@ func SearchUserByName(opts *SearchUserOptions) (users []*User, _ int64, _ error)
searchQuery := "%" + opts.Keyword + "%"
users = make([]*User, 0, opts.PageSize)
// Append conditions
sess := x.Where("LOWER(lower_name) LIKE ?", searchQuery).
sess := x.
Where("LOWER(lower_name) LIKE ?", searchQuery).
Or("LOWER(full_name) LIKE ?", searchQuery).
And("type = ?", opts.Type)
@@ -1048,7 +1152,9 @@ func SearchUserByName(opts *SearchUserOptions) (users []*User, _ int64, _ error)
if len(opts.OrderBy) > 0 {
sess.OrderBy(opts.OrderBy)
}
return users, count, sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&users)
return users, count, sess.
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
Find(&users)
}
// ___________ .__ .__
@@ -1065,6 +1171,7 @@ type Follow struct {
FollowID int64 `xorm:"UNIQUE(follow)"`
}
// IsFollowing returns true if user is following followID.
func IsFollowing(userID, followID int64) bool {
has, _ := x.Get(&Follow{UserID: userID, FollowID: followID})
return has
@@ -1121,3 +1228,18 @@ func UnfollowUser(userID, followID int64) (err error) {
}
return sess.Commit()
}
// GetStarredRepos returns the repos starred by a particular user
func GetStarredRepos(userID int64, private bool) ([]*Repository, error) {
sess := x.Where("star.uid=?", userID).
Join("LEFT", "star", "`repository`.id=`star`.repo_id")
if !private {
sess = sess.And("is_private=?", false)
}
repos := make([]*Repository, 0, 10)
err := sess.Find(&repos)
if err != nil {
return nil, err
}
return repos, nil
}

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