Compare commits

..

383 Commits

Author SHA1 Message Date
Unknwon
23f2efa8c1 Update locales 2017-02-11 03:59:25 -05:00
Unknwon
5791e1398c install: validate SMTP From
Invalid SMTP From will cause fatal error in post-install and exit
the program.
2017-02-11 03:29:30 -05:00
Unknwon
9b72661767 config: show Git version in admin panel 2017-02-11 03:04:45 -05:00
Unknwon
0958fe5a4e Improve Open Graph Meta tags (#3664) 2017-02-11 00:03:10 -05:00
Simeon Radivoev
4a1dc29e23 Added Open Graph Meta tags to head template (#3664) 2017-02-10 23:37:23 -05:00
Unknwon
2ca668e79e Add more details on error report
[CI SKIP]
2017-02-10 17:11:46 -05:00
Unknwon
ee59016585 wiki: clean up broken data if migration failed (#3792) 2017-02-10 17:07:21 -05:00
Unknwon
7ac09681a2 markdown: fix mailto: doesn't recognize as valid link (#3790) 2017-02-10 17:03:27 -05:00
Unknwon
1863f38286 models/repo: fix SQLite3 database-lock when fail to delete repository (#4048) 2017-02-10 16:56:58 -05:00
Unknwon
6b6f54b79b Some file refactoring 2017-02-10 16:51:09 -05:00
Unknwon
b67ec01d41 Able to disable non-admin to create new organization (#1556)
Add new config option '[admin] DISABLE_REGULAR_ORG_CREATION', by
default it's 'false'.
2017-02-10 16:41:51 -05:00
Unknwon
2c154ccbe7 Minor improve on error handling 2017-02-10 16:05:11 -05:00
Unknwon
3f95824e65 api/repo/milestone: fix change status didn't take effect 2017-02-10 15:54:02 -05:00
spacetourist
29722af1ae Configurable SSH cipher suite (#4109)
* Configurable SSH cipher suite

* Maintain ordering
2017-02-10 14:04:43 -05:00
Unknwon
563fc7c6d7 dump: check existence before include data subdirs (#4100) 2017-02-10 11:58:04 -05:00
Unknwon
9b8fa69c15 models/ssh_key: fix SSH_KEYGEN_PATH not working (#3770) 2017-02-10 02:26:55 -05:00
Unknwon
f5dc436441 Minor improve on error handling 2017-02-10 00:11:51 -05:00
Unknwon
d9d329bec8 modules/setting: add Slack logger
Conn and email loggers are removed for now unless people requested
for them, then try to add back in gopkg.in/clog.v1
2017-02-09 23:53:57 -05:00
Unknwon
76879e977b docker: fix script 2017-02-09 20:48:02 -05:00
Unknwon
9c3c9a8eb9 Update CI settings 2017-02-09 20:11:34 -05:00
Unknwon
2fd69f13d9 vendor: check in vendors
Bye bye glide...
2017-02-09 19:48:13 -05:00
Unknwon
eb66060cd7 log: start using gopkg.in/clog.v1 2017-02-09 19:29:59 -05:00
Unknwon
8a19f8a63c Update locales
This patch also fixes #4073
2017-02-09 16:04:35 -05:00
Unknwon
f7c11a27d0 models/repo: clean up repository local copy after rename (#3641) 2017-02-09 15:56:39 -05:00
Unknwon
418dab9b96 models/pull: load attributes when fetch list of pull requests (#4089)
Code only fetched issues corresponding to the pull requests, and left
out necessary base/head repository objects, which is required later
to generate API format.
2017-02-09 15:45:35 -05:00
Unknwon
09ad42b918 dump: include data-subdirs (#4100) 2017-02-09 15:33:57 -05:00
Unknwon
074c92b0a3 routers/repo/branch: fix can't delete branch with slashes after merge (#4089) 2017-02-09 15:25:48 -05:00
Unknwon
e893e1fc63 models: set XORM log level to WARNING in production 2017-02-09 15:09:37 -05:00
Unknwon
6622b7b49a models: remove TiDB embedded driver support
Users should all start tidb-server process and connect to it as if
it is a MySQL server with MySQL drivers.
2017-02-09 09:31:38 -05:00
Unknwon
afab38b0d7 routers/repo/pull: fix 404 on PR compare (#4074)
Due to recent code refactor, ctx.PullRequest is not initialized for
route repo.CompareAndPullRequest, which leads the UI thinks the
compare is not happening inside the same repository.

The current fix is to allow compare URL to include redundant head
user name so everything works fine again, but code logic isn't
as clean as before.

Made comments about possible future fix.
2017-02-08 18:43:46 -05:00
Unknwon
ede58ade4c models/org_team: fix compile error 2017-02-08 18:18:55 -05:00
Unknwon
a2dd9ec2e1 models/org_team: panic when team num_repos is negative (#3671) 2017-02-08 18:13:46 -05:00
Unknwon
591c333dcd liberjs: pointing licenses to GitHub instead of local 2017-02-07 18:50:16 -05:00
Jorge Maldonado Ventura
6971143dc5 Make Gogs compatible with LibreJS (#4092) 2017-02-07 18:47:08 -05:00
Unknwon
5d6ea4a81b IPythonNotebook: fix a bit more CSS 2017-02-07 17:27:33 -05:00
Unknwon
2374a3ef64 IPythonNotebook: fix Markdown cell CSS 2017-02-07 17:18:18 -05:00
Unknwon
0d9e435bfe IPythonNotebook: CSS adjustment for PR #4070 2017-02-07 17:11:46 -05:00
Herbert
9af0dd23dd Ipython notebook support (#4070)
* added marked and notebookjs javascript libraries

* added ipython notebook render support using javascript libraries

* recompiled gogs.css to include ipynb-related css

* removed superflous javascript library files
2017-02-07 16:18:11 -05:00
Unknwon
39eb6df769 Fix wrong commit SHA in .gopmfile (#4093) 2017-02-07 11:23:16 -05:00
Unknwon
c0f25d24b2 Update locales 2017-02-05 22:42:01 -05:00
Crayon
4f778da35e Change copyright date to 2017 (#4079)
The copyright date in the footer was still set to 2016.
2017-02-02 20:09:24 -05:00
Unknwon
f0f8205b8b models/ssh_key: little key methods receiver rename 2017-02-01 21:34:14 -05:00
Unknwon
2bb1de1805 cmd/serve: minor code improve for PR #4078 2017-02-01 21:28:43 -05:00
Pablo Saavedra
0081c6911d Check deploy keys when Gogs is run with Service.RequireSignInView=true (#4078)
* Check deploy keys when Gogs is run with require_sign_in_view

Check if the deploy key can access to a repository. A deploy key
doesn't represent an gogs user, so in a site with Service.RequireSignInView
activated we should give read access only in the repositories where
this deploy key is in use. In other case, a deploy service or system
using an active deploy key can get read access to all the repositories
in a Gogs service.

* Refactoring: Comments starts in a new line

* Minor change in a comment

* Code cleaning. Replace spaces with tabs
2017-02-01 21:08:59 -05:00
Unknwon
2527037973 routers/repo: minor code fix for PR #3758 2017-02-01 07:24:20 -05:00
Andrey Nering
1d951cfc49 Fix 500 when repo has invalid .editorconfig (#3758)
Creating a notice instead

Fixes #3643
2017-02-01 07:21:03 -05:00
Unknwon
32a0255ce3 bindata: generate for PR #3646 2017-01-31 21:01:13 -05:00
Rémy Boulanouar
be3a13a0d6 Allow use to set an external tracker url and to redirect user when clicking in Issues same behavior as Wiki. (#3646) 2017-01-31 20:53:48 -05:00
Unknwon
d293aa9ced Do a fast-fail testing on repository URL before mirroring
To ensure the URL is accessible under good condition to prevent
long blocking on URL resolution without syncing anything.
2017-01-31 18:40:38 -05:00
Unknwon
0cfcaca351 conf: minor comments fix 2017-01-31 18:08:34 -05:00
Unknwon
412ba5b2a9 Prepare for release 2017-01-31 07:36:59 -05:00
Unknwon
c17f93e6c0 Makefile: remove -buildmode=pie 2017-01-30 15:28:42 -05:00
Unknwon
a5afa37203 Makefile: fix string concatenation 2017-01-30 15:24:31 -05:00
Unknwon
6bfbed0616 Use commit time instead of author time for push commits (#4037) 2017-01-30 13:38:16 -05:00
Unknwon
185c90df12 Skip deletion for temporary data when not exist on Windows (#4069) 2017-01-30 13:30:04 -05:00
Unknwon
7463d9c51d Fix can not save release draft as draft again (#3669)
But release was not saved as draft in the first time, is not
possible to be draft afterwards because the Git tag was created.
2017-01-30 13:21:24 -05:00
Renato P. de Aquino
ec5a967937 Issue #3814 (#3903) 2017-01-30 08:35:12 -05:00
Unknwon
4bc98f7aa2 Move models/mail.go to modules/mail.go
To use interface to replace *models.User in avoiding cycle import.
2017-01-30 07:20:48 -05:00
Unknwon
207960b459 Fix create user can use user email which is used (#4016) 2017-01-29 18:29:53 -05:00
Unknwon
7b3b46c675 Fix showing total number of PRs when user does not have any repositories (#4007) 2017-01-28 20:17:01 -05:00
Unknwon
5e01ecbc05 Able to set custom Access-Control-Allow-Origin header (#3987)
Added new config option '[http] ACCESS_CONTROL_ALLOW_ORIGIN'.
2017-01-28 19:59:17 -05:00
Dennis Chen
c98aa0e895 api: display repository forks (#3252)
Lists the forks of a repository at the /:user/:repo/forks endpoint.

Signed-off-by: Dennis Chen <barracks510@gmail.com>
2017-01-28 17:59:21 -05:00
Aaron Wood
263203ec28 Produce a position independent executable (#4011)
* Produce a position independent executable

* Add OS detection to the main Makefile so we don't apply -pie on OS X
2017-01-28 17:16:34 -05:00
Denis Denisov
84f28fc5d6 Safe compare password (timing attack) (#4064) 2017-01-28 13:28:52 -05:00
Unknwon
9144ea2b1d Fix inappropriate CSS rule for Markdown on wiki page (#3766) 2017-01-28 09:47:16 -05:00
Unknwon
0d73dcaf0f Fix cross-repository reference link error (#4025) 2017-01-28 09:40:32 -05:00
Unknwon
a6a3afd130 Update locales 2017-01-28 05:54:05 -05:00
Unknwon
7aa53635fe Add 'Organizations' page to user settings (#3587)
User is now able to view full list of organizations belongs to.
2017-01-27 22:36:45 -05:00
Rémy Boulanouar
2ee0c61e62 Setting orgs (#3587)
* Implement organizations listing in setting and allow user to create new organization.

* Implement organizations listing in setting and allow user to create new organization.

* Add space remove by mistake

* Remove unused part of the template

* Update display and behavior according to @Unknown remarks
2017-01-27 22:02:27 -05:00
Unknwon
3d23c13160 Add AppVeyor badge to README 2017-01-27 19:42:41 -05:00
Unknwon
e2afd886fd Update appveyor.yml 2017-01-27 19:33:40 -05:00
Unknwon
aa682b3b7e Add appveyor.yml 2017-01-27 19:25:00 -05:00
Unknwon
e43479d948 Fix changed branch is not reflected when creating PR (#3604) 2017-01-27 18:56:32 -05:00
Unknwon
a2f2f7717a Fix template error when rendering non-README markdown (#4063) 2017-01-27 16:52:19 -05:00
cybe
740192564b Verify repository is not bare before retrieving blob. (#3996) 2017-01-27 07:09:25 -05:00
Unknwon
8bcc0e392e Update XORM required version and 'go fmt' 2017-01-26 17:49:29 -05:00
Unknwon
ae319da5fd Disable local path migration by default (#4033)
Site admin now has to enable manually by config option
[repository] ENABLE_LOCAL_PATH_MIGRATION = true.
Site admin always grants this permission, but regulars users have
to be allowed by site admins in admin user panel.
2017-01-26 17:43:37 -05:00
Unknwon
6d6848af5c Fix log depth of AvatarLink 2017-01-26 17:22:25 -05:00
Unknwon
0d60b58434 templates/repo: rename 'Code' to 'Files' 2017-01-25 18:15:37 -05:00
Unknwon
ad57f18894 modules/sync: minor field refactor 2017-01-25 18:10:27 -05:00
Óscar García Amor
80cd8f6a29 Fix #3714 (#4060) 2017-01-25 17:48:31 -05:00
Unknwon
8cb903fbbb Fix unexpected rendering of README when it is not in Markdown
This patch also handles case when a file name looks like README
but is not a text file (e.g. image, PDF).
2017-01-25 07:10:52 -05:00
Unknwon
d1c327d508 repo/home.tmpl: only ellipsis on repository name
File name could contain non-ASCII characters.
See details on https://discuss.gogs.io/t/topic/758.
2017-01-24 21:15:44 -05:00
Óscar García Amor
eaf57229d3 Fix notification email issues (#4055) 2017-01-24 08:18:14 -05:00
atzoum
4e967bc765 Dockerfile for aarch64 (odroid c2 & pine64) (#4018) 2017-01-23 18:31:24 -05:00
Aaron Wood
64788ffff6 Remove call to set GOMAXPROCS (#4010)
* Remove call to set GOMAXPROCS

* Remove runtime import
2017-01-23 18:30:40 -05:00
Joakim Fremstad
3143e35d83 Reword README.md (#4047) 2017-01-23 18:30:29 -05:00
Unknwon
8d5a693382 locale: remove unused locale string 2017-01-23 14:33:25 -05:00
Sandro Santilli
1e185787a9 Enable federated avatars by default (#3997) 2017-01-22 06:03:38 -05:00
Unknwon
1b2ecde1c9 Update locales 2017-01-21 20:12:19 -05:00
Unknwon
e8c3e9bcf8 Improve code for fix of #4006 2017-01-03 11:02:14 +08:00
Unknwon
cdfcef04a1 Fix incorrect logic check for fork repo action 2017-01-03 10:39:05 +08:00
Unknwon
8aa35577b3 Fix vulnerability reported in #4006 2017-01-03 10:36:27 +08:00
Unknwon
c4086d43db Update locales 2017-01-01 13:33:24 +08:00
Unknwon
8059175a5c Fix dashboard issues/pull request counting 2016-12-27 22:01:18 +08:00
Unknwon
f8fd084bd2 Fix dashboard issue/pull request scoping 2016-12-27 20:32:27 +08:00
Unknwon
d528704503 Minor code fix for PR #3560 2016-12-27 20:26:35 +08:00
Unknwon
98076ee72d Upgrade Sematic UI to 2.2.7 2016-12-27 18:56:21 +08:00
hgaiser
e6ef75204b Fix assigned/created issues in dashboard. (#3560)
* Fix assigned/created issues in dashboard.

* Use GetUserIssueStats for getting all Dashboard stats.

* Use gofmt to format the file properly.

* Replace &Issue{} with new(Issue).

* Check if user has access to given repository.

* Remove unnecessary filtering of issues.

* Return 404 error if invalid repository is given.

* Use correct number of issues in paginater.
2016-12-27 18:54:24 +08:00
Joel-Liang
d674cb7f20 Fix wrong anchors for non-latin headings (#3981)
Change Javascript regular expression to match non-latin characters
The regex comes from here: http://stackoverflow.com/questions/150033/regular-expression-to-match-non-english-characters#comment22322603_150078

And this patch should fixed these two issues: #3919 #3843
2016-12-26 22:37:20 -05:00
Unknwon
114c179e5a Update .gopmfile and glide.lock 2016-12-23 21:53:30 -05:00
Unknwon
598e062241 Add Galician support
- Update locales
2016-12-23 21:06:15 -05:00
David A. Lareo
bf70082c22 New locale "galician" (#3917) 2016-12-23 20:53:24 -05:00
Unknwon
2994272e91 Code fix for PR #3748 2016-12-23 20:44:27 -05:00
typeless
cdedc2d188 Use temporary file to avoid out-of-memory when receiving big chunks. (#3748)
* Use temporary file to avoid out-of-memory when receiving big chunk.

Not perfect but I think it's a reasonable solution.
For small request bodies, I suppose performance wouldn't be an issue.
For large ones, this seems to be a necessary evil.

* Must close the open file to avoid fd leaks
2016-12-23 19:50:12 -05:00
Unknwon
42a3bbb0f4 Fetch before Checkout when create pull request (#3699) 2016-12-23 19:36:16 -05:00
Unknwon
eb79532812 Minor fix for PR #3436 2016-12-23 19:00:24 -05:00
lstahlman
5feb68a589 Improve issue references in markdown. (#3436) 2016-12-23 18:49:53 -05:00
Unknwon
03f7f3ee67 Some code renaming 2016-12-22 19:58:30 -05:00
Unknwon
6383bf7480 Fix reported vulnerability
Ability to use labels from arbitrary repositories.

Reported by Miguel Ángel Jimeno.
2016-12-22 19:44:59 -05:00
Unknwon
f471ef1bc7 Fix vulnerability reported in #3962 2016-12-22 19:35:06 -05:00
Unknwon
7ebe0a9916 Fix vulnerabilities reported in #3959 2016-12-22 19:19:56 -05:00
Unknwon
89e93fe01e Minor code fix for PR #3602
Closes #1122
2016-12-22 03:49:50 -05:00
raphael10241024
0f8a5fdf49 fix bug #1122 log.smtp receiver configure error (#3602) 2016-12-22 03:45:51 -05:00
Gian Perrone
3c91c9063b Enable Ubuntu 16.04 build at packager.io (#3617) 2016-12-22 03:41:54 -05:00
Unknwon
e629c7583b Fix #3675
Closes #3676
2016-12-22 03:35:53 -05:00
ipavl
539b07e205 Pluralize "Statistic" (#3665)
Other locales appear to use the plural version, and the text is being associated with more than one statistic.
2016-12-22 03:26:33 -05:00
Unknwon
16d3e7085e Minor fix for PR #3667 2016-12-22 01:51:49 -05:00
Thibault Meyer
c47fbc629b Feature #2583: Disable HTTP cloning (#3667)
* Can disable GIT interactions by HTTP protocol

* rename variable + fix wiki link

* missing space
2016-12-22 01:42:04 -05:00
Unknwon
d04b19545d Code fix for PR #3547 2016-12-22 01:28:06 -05:00
Kurt Madel
3b0e2c1c3f PR Webhook - Add base/head info (#3547)
* messing with getting local go-gogs-client

* coding style fix

* added comments for required fields
2016-12-22 01:01:15 -05:00
Unknwon
79a2745b4a Set ProdMode in the correct place
Closes #3696, #3611

Previously, ProdMode can only be true for web server,
which always prints dev mode log message to incoming SSH
connections and leaks unexpected information.
2016-12-22 00:27:45 -05:00
Unknwon
6cc992ea54 Minor fix for PR #3687 2016-12-21 23:52:11 -05:00
Stefan Grönke
3376354ed8 Check if file is a symlink with web editor (#3687)
* editor checks for symlinks

* translate file_is_a_symlink message

* credit translation author
2016-12-21 23:49:56 -05:00
Unknwon
c2e1370588 Update README
[CI SKIP]
2016-12-21 22:47:55 -05:00
Thibault Meyer
93616fe776 Fix regex on route file (#3851) 2016-12-21 19:46:43 -05:00
Najeeb R
e5972bbcde #3480 Fix new ssh key adding issues (#3565)
* #3480 Fix new ssh key adding issues

Added regular exp match (108) and remove training new line (111) that cause system to think its an ssh2 key.

* #3480 Fix new ssh key adding issues

-Sanitizate new lines (windows format) in posted key
-Edit sanitization implementation to use string replace for code readability and maintenability.
2016-12-21 19:35:48 -05:00
Flare
952e510dfa Added public entries to reserved keywords list
Closes #3728
2016-12-21 19:24:23 -05:00
Unknwon
8f442dde03 Dirty hack for #3905
I beileve this is a bug in XORM which wrongly identifies a struct
to inappropriate table name. Also seems to be random.
2016-12-21 05:11:52 -05:00
Unknwon
c1e53cdc72 Minor fix for PR #3822 2016-12-21 04:18:23 -05:00
stroucki
e9f6a43073 Fix database write context interleaving bug (#3822)
* UpdateIssueUsersByMentions was calling database write operations while
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

* issue: forgot debug statement
2016-12-21 04:11:07 -05:00
Unknwon
67380cf47b Minor code fix 2016-12-21 04:08:23 -05:00
LefsFlare
39fdb0f9c4 Fixed 404 caused by unexpected question mark (#3668)
This fixes 404 caused when creating new files or wiki pages with question marks.
2016-12-21 04:05:49 -05:00
imilo
85fbd6e9c6 New settings option for a custom SSH host (#3763) 2016-12-21 03:46:54 -05:00
Mateusz Hromada
2cfdce88e0 Check for zero length passwords in LDAP module. (#3827) 2016-12-21 03:43:37 -05:00
Саша Иванов
ca6cbb95cc #3791 update LDAP username check (#3906) 2016-12-21 03:43:22 -05:00
leonklingele
7cb440273c Don't use custom PBKDF2 function (#3952)
Instead, use golang.org/x/crypto/pbkdf2
2016-12-21 03:42:44 -05:00
leonklingele
d96f2a7184 Fix random string generator (#3953)
* Remove unused custom-alphabet feature of random string generator

* Fix modulo-biased random string generator

* Random string generator should return error if it fails to read random data via crypto/rand
2016-12-21 03:41:37 -05:00
Nico Mandery
adcb1d7c65 serve video files using the HTML5 video tag (#3967) 2016-12-21 03:40:23 -05:00
afilippov1985
04fbfad2d4 init script for gentoo (#3761) 2016-12-21 03:38:07 -05:00
SeongAhJo
bab051a8c1 Fix Typo Errors (#3885)
* Fix typos

* Fix typos
2016-12-21 03:33:30 -05:00
leonklingele
ad6de46ce4 Fix typo: 'passowrd' -> 'password' (#3951) 2016-12-21 03:31:40 -05:00
Bo Zhang
282f7fb8fa Fix typos (#3852) 2016-12-21 03:13:11 -05:00
M5oul
5034ef787c [mod] readme: update YunoHost package link. (#3881) 2016-12-21 03:12:53 -05:00
Sandro Santilli
3925166d31 Add support for using "libravatar" as the GravatarSource (#3969)
Just to make it easier for administrator to configure libre avatar,
as it is done for "duoshuo" and "gravatar"
2016-12-21 03:10:15 -05:00
Alexander Lunegov
7358e46815 Fix string format verbs (#3637) 2016-12-21 02:09:43 -05:00
Unknwon
8f09fc64bd Minor fix for PR #3624 2016-12-21 01:48:11 -05:00
Kim "BKC" Carlbäcker
b2de3d71c5 More Issue-Comments API-endpoints (#3624)
* ListAllInRepo & Delete Issue-Comments

* Moar data in issue-comments
2016-12-21 01:21:15 -05:00
Unknwon
44ed991726 Merge branch 'develop' of https://github.com/tanapoln/gogs into develop 2016-12-21 00:49:44 -05:00
Unknwon
34b92cdb44 Fix #3905 2016-12-20 23:23:57 -05:00
Unknwon
d3b2ff17d6 Update locales 2016-12-20 22:35:55 -05:00
Unknwon
cc45a8ab06 cmd: new command 'import locale'
Quickly import locale files downloaded from Crowdin.
2016-12-20 22:34:58 -05:00
Unknwon
105c528369 Add Korean support 2016-12-20 21:59:59 -05:00
Unknwon
5d0b334d56 Update git-module required version 2016-12-20 21:28:32 -05:00
Unknwon
b092733c2e Update git-module version to support back Git 1.7.1 2016-12-08 11:44:45 -05:00
Unknwon
baeccdb161 Add github.com/go-xorm/builder to dependency 2016-11-23 21:04:16 -05:00
Unknwon
394fc61129 Update glide.lock and .gopmfile for XORM 2016-11-23 20:58:45 -05:00
Unknwon
55dc9d898f Drop Go 1.4 support
Due to golang.org/x/crypto/ssh requires a method from STD in Go 1.5.

And Go 1.4 is fairly old version for now.
2016-11-23 20:23:18 -05:00
Unknwon
552d5c7ceb Update glide.lock and .gopmfile
Closes #3690 #3727
2016-11-23 20:06:41 -05:00
Unknwon
95065de39a Fork go-libravatar to remove import path check
To use GitHub import path as much as possible.
2016-11-19 21:55:21 -05:00
Unknwon
a3ea4b8802 Update locales and add Swedish 2016-11-19 21:40:13 -05:00
Rémy Boulanouar
6bcff7828f Fix mention in comments like (@dblk) (#3655)
* Fix mention in comments like (@dblk)

* Better fix to avoid making link for "Hello@DblK"
2016-10-16 22:17:59 -04:00
LefsFlare
2cb5ec5983 Prevented user enumeration of valid users through HTTP status codes of login (#3639) (#3654) 2016-10-16 22:08:40 -04:00
LefsFlare
2bec8a4f1e Changed interface (#3685) 2016-09-22 19:38:12 -04:00
Unknwon
7e15ff9486 Update locales
Add new locale Serbian (Cyrillic)
2016-09-15 20:03:36 -04:00
Unknwon
12445fe2ed Add build system link to README [CI SKIP] 2016-09-08 20:56:05 -04:00
Unknwon
491407ddf8 #3590 fix 404 for release draft edition
Closes #3591
2016-09-03 06:00:59 -04:00
Unknwon
6da55159a2 #3589 LoadRepoConfig after ORM is initialized 2016-09-02 23:18:37 -04:00
Tanapol Nearunchorn
73fedc7275 provide button to delete merged pull request 2016-09-02 10:12:21 +07:00
Unknwon
c50d59874d #3577 incorrect URL produced by AvatarLink 2016-09-01 12:36:26 -04:00
Daniel Oaks
b3d9ca4ccd Add the ability to explore organizations (#3573)
* Add ability to explore organizations

* Use right icon for org explore links
2016-09-01 09:08:05 -04:00
Daniel Oaks
4efaf8e882 Fix repo list display on Safari (#3569) 2016-09-01 08:04:25 -04:00
raphael10241024
178556142a fix link error under preview (#3566) 2016-09-01 06:01:27 -04:00
Unknwon
7c1fbed057 Fix panic when attempt login with non-exist user 2016-09-01 05:12:34 -04:00
Thibault Meyer
bc902b8f74 Feature #3492: Add option to hide footer load times (#3562)
* Add option to hide footer load times

* Rename option variable + minor changes
2016-09-01 01:01:32 -04:00
Unknwon
8ee14db51e Update locales 2016-09-01 00:35:04 -04:00
Rémy Boulanouar
5d35578811 Update size of SHA to fix #3538 (#3563) 2016-08-31 14:22:17 -07:00
Corben Dallas
d09fca3ca9 Add a (Open)SuSE init script (#3558) 2016-08-31 14:04:21 -07:00
Unknwon
dadd35b636 #3559 fix template error 2016-08-31 13:59:23 -07:00
Unknwon
c2afdf2192 Minor code fix [CI SKIP] 2016-08-31 04:31:53 -07:00
Unknwon
152e715999 models/login_source: code improvement 2016-08-31 01:22:41 -07:00
Unknwon
99c2ae7b35 #3515 use alert instead 500 for duplicated login source name 2016-08-31 00:56:10 -07:00
无闻
cd9b926af7 Support Editorconfig on web editor (#3512) 2016-08-30 16:47:22 -07:00
Andrey Nering
9ac46fb983 Support Editorconfig on web editor 2016-08-30 20:30:47 -03:00
Unknwon
8516dfcb6c #2018 able to sync now for mirrors
- Refactor code to use sync.UniqueQueue
- Closes #3509
2016-08-30 16:18:33 -07:00
Unknwon
c1ecb6c60a modules/sync: add UniqueQueue 2016-08-30 15:50:30 -07:00
Unknwon
43297148b2 modules/sync: rename SingleInstancePool to ExclusivePool 2016-08-30 15:19:53 -07:00
Unknwon
c0c1a4b01b js: fix comment issue status button title change 2016-08-30 14:37:46 -07:00
Sandro Santilli
47a3243ff1 Add all, check and dist Makefile rules (#3549)
These are to follow the GNU Coding Standards Makefile Targets:
https://www.gnu.org/prep/standards/html_node/Standard-Targets.html
2016-08-30 14:06:05 -07:00
Unknwon
22e14a0a67 templates/repo/view: fix bad link 2016-08-30 13:59:41 -07:00
Unknwon
48a0b5b026 UI: fix block selection on code for empty line are not highlighted 2016-08-30 06:03:38 -07:00
Unknwon
16eb2eb6a3 Fix import path 2016-08-30 05:49:54 -07:00
Unknwon
e6ec1ca1f8 #3548 disable issue cannot edit label and milestonefor pull requests 2016-08-30 05:30:47 -07:00
Unknwon
6f90835f95 Make bindata 2016-08-30 05:24:34 -07:00
Unknwon
643142acab Web editor: support upload files 2016-08-30 05:23:59 -07:00
Unknwon
7c31f235da Web editor: support upload files 2016-08-30 05:12:37 -07:00
Kim "BKC" Carlbäcker
4f40019130 codegangsta/cli => urfave/cli (#3546) 2016-08-30 04:57:58 -07:00
Unknwon
780cc2d110 router/repo: code refactoring 2016-08-30 02:08:38 -07:00
Unknwon
2a13f682e0 Bump git-module required version 2016-08-29 23:57:22 -07:00
Unknwon
28cf0e6aaa #3459 code quality improvement 2016-08-29 20:00:06 -07:00
Thibault Meyer
92fb30c526 Load a set of predefined labels (#3459)
* Can use a predefined set of labels

* Change UI

* Fix HTML file indentation

* Avoid reading file from other directory (security issue)

* Apply a better fix

* Remove not used variable

* Merge upstream/develop

* Do modifications

* Raname

* remove binding + rename variable
2016-08-29 19:02:49 -07:00
Andrey Nering
9f44c26789 Update .editorconfig (#3534)
[CI SKIP]
2016-08-29 18:05:44 -07:00
LFlare
3738b6399e Fixed typo (#3533)
Git convention has it capitalised.
2016-08-29 11:31:12 -07:00
Unknwon
62b0dc4853 Web editor: fix cannot create new file in subdirectory 2016-08-29 00:10:21 -07:00
Unknwon
429c92c0ce #3516 enforce line ending to be \n from web editor 2016-08-28 05:32:10 -07:00
Unknwon
579e5e4fee Web editor: disallow edit mirror repository 2016-08-28 04:56:41 -07:00
Unknwon
ba27d71abe Web editor: improve edit file 2016-08-28 04:31:42 -07:00
Unknwon
7115e3a4d5 css: remove profile avatar height 2016-08-28 03:19:27 -07:00
Unknwon
0114fdcba4 Web editor: improve delete file process 2016-08-28 01:41:44 -07:00
Unknwon
dad5c15520 #2901 allow setting preferred licenses
- Closes #3488
2016-08-28 00:06:22 -07:00
Unknwon
6e171c5225 Web editor: improve edit file tooltip 2016-08-27 15:25:01 -07:00
Unknwon
f0b5c3b90a #3448 redirect if any after sign in 2016-08-27 15:07:02 -07:00
Unknwon
c30b856d14 #3505 use user’s info for committer and author 2016-08-27 13:37:55 -07:00
Unknwon
13c106af77 label: adjust forecolor boundary 2016-08-27 12:44:39 -07:00
Unknwon
ce1e4348da #3521 fix wiki HTTP/S clone URL does not have .wiki suffix 2016-08-27 12:29:52 -07:00
Unknwon
13a8823bd3 #3495 only start builtin SSH server after user finish installation 2016-08-27 12:25:22 -07:00
Unknwon
bbca2916f7 Update highlightjs 2016-08-27 11:56:20 -07:00
Unknwon
37305a59ca migrations: sync table first 2016-08-26 17:32:41 -07:00
Unknwon
bb359a74f1 migrations: set comment updated as created 2016-08-26 14:07:21 -07:00
Unknwon
6b98d58906 #2966 code cleanup 2016-08-26 13:40:53 -07:00
Iwan Budi Kusnanto
8dca9f95fa issues comment API : list, create, edit (#2966)
add `since` query string support to list issue comment
2016-08-26 11:23:21 -07:00
Thibault Meyer
f50e568fd1 Fix #3189: Sort labels by name (#3446)
* Fix #3189 #3445: Order labels by name

* Order labels by name on Issues view
2016-08-25 17:43:53 -07:00
Unknwon
f8a48ffaad Web editor: improve code quality 2016-08-24 21:35:03 -07:00
Kurt Madel
67fb0fe6a5 added support to set pull_request event from api (#3513) 2016-08-24 20:44:58 -07:00
Unknwon
0b273ac4d5 #3383 code cleanup 2016-08-24 16:05:56 -07:00
lstahlman
84b56c3c53 Additional API support for milestones (#3383) 2016-08-24 15:18:56 -07:00
Kim "BKC" Carlbäcker
06602a84ff Fix PR-webhook issue where Label-data is stale (#3486) (#3510)
* Fix PR-webhook issue where Label-data is stale

* Conventions \o/

* logs are nice if they're consistent...
2016-08-24 12:01:30 -07:00
Kim Carlbäcker
b710f6bd65 Update gopmfile and glide.lock (#3508) 2016-08-23 14:53:16 -07:00
rugk
95bd19c509 libravatar.org supports HTTPS (#3498) 2016-08-23 09:50:33 -07:00
Kim Carlbäcker
7c5710d31f Issues can be closed via API (#3170) (#3479)
* Issues can be closed via API

* Error-checking is nice xD

* EditIssueOption.Status => State

* Use const instead of string-literal
2016-08-23 09:09:32 -07:00
Unknwon
7f7216be6e Code quality improvement on JS 2016-08-17 22:44:07 -07:00
Unknwon
ec332cf903 Minor naming improvement 2016-08-17 16:10:07 -07:00
Thibault Meyer
2c5411b00c Fix #3361: Dumps are created world readable (#3473)
* Set dump file permission to 0600

* Typo
2016-08-17 11:38:42 -07:00
Unknwon
a00c932bbc General code quality improvement 2016-08-16 23:06:38 -07:00
Unknwon
6f9a95f830 #2246 add HTMLURL to webhook type
- Fill Milestone and Assignee field when available in webhook payload
2016-08-16 10:19:09 -07:00
Unknwon
8bf57be9ba Fix git diff tests 2016-08-16 07:45:06 -07:00
Unknwon
b1504ed99a #3464 add diff signs which does not have inline diff 2016-08-16 07:37:28 -07:00
Unknwon
9349def72e #3464 reproduce diff signs
Commited wrong file.
2016-08-16 07:33:53 -07:00
Unknwon
6cda35a75f #3464 reproduce diff signs 2016-08-16 07:31:54 -07:00
Unknwon
2625193a48 models/repo_editor: improve code quality 2016-08-15 22:20:55 -07:00
Unknwon
f3c3258921 Fix repository owner can assign self 2016-08-15 18:48:20 -07:00
Unknwon
4042d1f0c3 models/issue: improve quality and performance of NewIssue function 2016-08-15 18:40:32 -07:00
Unknwon
4a46613916 markdown: fix treating pure number as SHA1
- Detect non-exist commit and return 404 not 500
2016-08-15 15:27:19 -07:00
Unknwon
6c8fcb3af2 #3467 fix clone fail when wiki is empty 2016-08-15 15:09:34 -07:00
Unknwon
61e27dedf7 #3466 fix response of pull request form validation error 2016-08-15 14:04:44 -07:00
Unknwon
94392a7af3 Fix empty repository panic on send test webhook 2016-08-15 05:53:47 -07:00
Unknwon
cc647ba9d5 #3461 fix security issue of REAMDE path in create repository 2016-08-15 02:35:54 -07:00
Unknwon
5e89485cec Update README [CI SKIP] 2016-08-15 02:12:18 -07:00
Unknwon
8637e67e6f Fix outdated edit can’t overwrite changes 2016-08-15 02:06:35 -07:00
Unknwon
4a19fd6441 Web editor: temporarily disable upload and quick fix for edit and new
Try to merge into develop branch ASAP, then continue minor fixes afterwards.
2016-08-15 01:42:20 -07:00
Unknwon
54e0ada9d5 Web editor: improve delete file 2016-08-14 23:52:24 -07:00
Unknwon
cd89f6c502 Web editor: improve edit file and diff preview 2016-08-14 23:52:24 -07:00
Unknwon
660e7a178a modules/sync: move sync objects to independent module 2016-08-14 23:52:24 -07:00
Unknwon
15845cb287 Code clean up for new config options 2016-08-14 23:52:24 -07:00
Richard Mahn
d0a0239bac Squashed commit of the following:
commit 0afcb843d7
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Sun Jul 31 17:13:29 2016 -0600

    Removed Upload stats as the upload table is just a temporary table

commit 7ecd73ff55
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Sun Jul 31 08:42:41 2016 -0600

    Fix for CodeMirror mode

commit c29b9ab531
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Sun Jul 31 08:03:33 2016 -0600

    Made tabbing in editor use spaces

commit 23af384c53
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Sun Jul 31 07:56:46 2016 -0600

    Fix for data-url

commit cfb8a97591
Merge: 7fc8a89 991ce42
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Sun Jul 31 07:42:53 2016 -0600

    Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file

    Conflicts:
    	modules/bindata/bindata.go
    	public/js/gogs.js

commit 7fc8a89cb4
Merge: fd3d86c c03d040
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Sun Jul 31 07:40:00 2016 -0600

    Merge branch 'feature-create-and-edit-repo-file' of github.com:richmahn/gogs into feature-create-and-edit-repo-file

commit fd3d86ca6b
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Sun Jul 31 07:39:44 2016 -0600

    Code cleanup

commit c03d0401c1
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Fri Jul 29 15:38:23 2016 -0600

    Code cleanup

commit 98e1206ccf
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Thu Jul 28 18:36:01 2016 -0600

    Code cleanup and fixes

commit c2895dc742
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Thu Jul 28 18:24:04 2016 -0600

    Fixes per Unknwon's requests

commit 6aa7e46b21
Merge: 889e9fa ad7ea88
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Thu Jul 28 17:13:43 2016 -0600

    Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file

    Conflicts:
    	modules/bindata/bindata.go
    	modules/setting/setting.go

commit 889e9faf1b
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Fri Jul 22 14:09:18 2016 -0600

    Fix in gogs.js

commit 47603edf22
Merge: bb57912 cf85e9e
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Fri Jul 22 14:07:36 2016 -0600

    Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file

    Conflicts:
    	modules/bindata/bindata.go
    	public/js/gogs.js

commit bb57912558
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Fri Jul 22 14:02:18 2016 -0600

    Update for using CodeMirror mode addon

commit d10d128c51
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Tue Jul 19 16:12:57 2016 -0600

    Update for Edit

commit 34a3498202
Merge: fa1b752 1c7dcdd
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Tue Jul 19 11:52:02 2016 -0600

    Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file

    Conflicts:
    	modules/bindata/bindata.go

commit fa1b752be2
Author: Richard Mahn <richard_mahn@wycliffeassociates.org>
Date:   Fri Jul 15 18:35:42 2016 -0600

    Feature for editing, creating, uploading and deleting files
2016-08-14 23:52:24 -07:00
Unknwon
7e7613cdec Fix template nil error 2016-08-14 23:43:13 -07:00
Unknwon
a5b88c4d0c Fix template error [CI SKIP] 2016-08-14 16:45:15 -07:00
Unknwon
dccb0c15b9 Replace convert.To with APIFormat calls 2016-08-14 04:17:26 -07:00
Unknwon
3f7f4852ef #2246 fully support of webhooks for pull request 2016-08-14 03:32:24 -07:00
Unknwon
0f33b04c87 Add subcommand to create new user in CLI 2016-08-13 16:11:52 -07:00
Unknwon
fd3b9ca3aa CSS: remove font “Meiryo Ui” 2016-08-12 22:05:20 -07:00
Justin Ray Vrooman
f1a5a4277d fix grammar + typo. (#3453) 2016-08-12 17:06:07 -07:00
Unknwon
f59d2dd034 Code clean up 2016-08-12 03:04:50 -07:00
Unknwon
5be881756b #3442 add test suites 2016-08-12 02:56:50 -07:00
Thibault Meyer
4296427214 Fix #3437: Cannot connect to PostgreSQL via IPv6 address (#3442)
* Change PostgreSQL connstring parsing to handle IPv6

* Fix used variable

* Remove redundant code + use variable
2016-08-12 02:42:06 -07:00
Unknwon
7551141dbe Minor fix on top menu dropdown icon position 2016-08-11 23:12:06 -07:00
Unknwon
5544a7037b Add new dependency 2016-08-11 17:12:55 -07:00
Andrey Nering
dbed39ba05 On showing diff/file, use the tab_width specified on .editorconfig, if any (#3241)
Closes #3182
2016-08-11 17:07:09 -07:00
Unknwon
aa1fc30b89 Add .mailmap 2016-08-11 16:57:48 -07:00
Andrey Nering
fa12c282f6 Add Content-Disposition header for downloads (#3439) 2016-08-11 16:53:40 -07:00
Andrey Nering
25b23c4bc9 Do not show non-image attachment in a <img> tag. Fixes #3215 (#3311) 2016-08-11 16:16:36 -07:00
Thibault Meyer
7eafe3213f Fix #3321: commit tag shortener (#3418)
* Fix #3321: commit tag shortener

* Check short commit

* remove debug

* Edit unit tests

* Show 10-char short SHA
2016-08-11 15:34:00 -07:00
Unknwon
2cb04db526 Fix #3391 2016-08-11 15:29:39 -07:00
Unknwon
96f92e6105 Fix email FROM 2016-08-11 15:16:01 -07:00
Unknwon
a47aef5460 #2852 code cleanup 2016-08-11 14:55:10 -07:00
Odin Ugedal
1dd003bd4c Add initial support for unix sockets (#2852) 2016-08-11 14:46:33 -07:00
Unknwon
70fbcd2f27 models: rename EnableTidb to EnableTiDB 2016-08-11 14:38:45 -07:00
Unknwon
5850308a37 #3013 support connect PostgreSQL via unix socket 2016-08-11 14:38:26 -07:00
Thibault Meyer
53c573ed02 Fix #3314: Cannot edit release with tag name contains slash (#3434) 2016-08-11 13:45:42 -07:00
Unknwon
10b47eddd2 Update glide.lock and .gopmfile [CI SKIP] 2016-08-11 11:51:12 -07:00
Robin Lambertz
5a9709fa9d Add MaxRepoCreation to EditUser API (#2781) 2016-08-11 11:49:31 -07:00
Unknwon
7e9b42c87d #2780 code clean up 2016-08-11 11:35:46 -07:00
Robin Lambertz
b6c14f8b21 Add AddCollaborator API Endpoint (#2780)
* Add AddCollaborator API Endpoint

* Add optional Permission to AddCollaborator endpoint

* Use APIContext
2016-08-11 11:23:25 -07:00
Unknwon
5077408d78 #3233 code cleanup and minor issue fix 2016-08-11 10:53:51 -07:00
Andrew
0885784f13 Wiki mirroring implementation (#3233)
* Implement wiki mirroring, add Update mirrors operation to admin dashboard

* bindata.go update after merge

* Implement checking Git repo endpoint existence, support for BB included

* Remove admin dashboard operation
Fix bindata.go

* Apply gofmt to repo model file

* Try to remove bindata from PR

* Revert accepted wiki names change in favor of better system

* Remove unused imports
2016-08-11 10:18:51 -07:00
Sandro Santilli
3380c946e1 Always set redirect_to on header-provided sign-in (#3435)
This is an attempt to fix #3089 following the strategy introduced
in d625e41c6c, although that strategy
by itself does not seem to be sufficient.

What needs be done is honouring the redirect_url query parameter
from the auth router.
2016-08-11 10:14:39 -07:00
Unknwon
d625e41c6c #3408 minor code fix 2016-08-11 07:41:01 -07:00
Sandro Santilli
eb1bfe0e59 Do not show the "Sign up for free" button in issue tracker (#3408)
* Do not show the "Sign up for free" button in issue tracker

The "Sign in to comment" link is good enough and will correctly
show or not show the "Sign Up" button link for those not having
an account already.

Fixes #3407 (link to nowhere when registration is disabled)

* Move html from translation to template

* Remove extra space in `{{ .SignInLink }}`.
2016-08-11 07:36:23 -07:00
Unknwon
042d350762 Fix only user has repo write access can comment 2016-08-11 06:22:56 -07:00
Unknwon
0f26f3678a #3279 use doer email for FROM field of issues 2016-08-11 06:17:45 -07:00
Thibault Meyer
6a81632e36 Fix typo CacheInternal -> CacheInterval (#3432) 2016-08-11 05:59:11 -07:00
Kim Carlbäcker
b756806ee9 Add "support" for git-daemon-export-ok (#2940) (#3046)
* add git-daemon-export-ok "support"

* Slight fix to git-daemon-export-ok

* Add error-checking for git-demon-export-ok

* Remove old comments and fixed logging-issues

* Check if git-daemon-export-ok exists or not
2016-08-10 20:08:09 -07:00
Unknwon
81e6f82caf Update glide.lock and .gopmfile [CI SKIP] 2016-08-10 11:57:53 -07:00
Unknwon
29f76f3936 Update locales [CI SKIP] 2016-08-10 11:54:52 -07:00
lstahlman
ea192147ea Add test pull request task on merging a PR. Fixes #3396 (#3425) 2016-08-10 11:38:44 -07:00
Thibault Meyer
99812a80fd Fix #3420: Bad commit URL generation (#3424) 2016-08-10 11:35:06 -07:00
Thibault Meyer
8ad92bb8a4 Verify list len before use it with IN (#3423) 2016-08-10 11:06:51 -07:00
Unknwon
b85927e488 #3091 show Git configs on admin panel 2016-08-10 11:01:42 -07:00
Unknwon
87b408a2e5 Update bindata.go [CI SKIP] 2016-08-09 23:58:15 -07:00
Thibault Meyer
fc68fb951c Feature #3398: Redefine global mirror interval (#3409)
* add mirror::GLOBAL_INTERVAL on app.ini

* rename key to DEFAULT_INTERVAL

* add key on default app.ini + move code
2016-08-09 23:47:16 -07:00
Unknwon
5448d29b2e #3417 wrong dashboard issue count for create by you 2016-08-09 23:19:52 -07:00
Unknwon
bb51eb5188 Update cron revision [CI SKIP] 2016-08-09 22:02:51 -07:00
lstahlman
89f71b44f7 Add committer information to API and Webhooks. Also fixes #3271 (#3414) 2016-08-09 22:01:57 -07:00
Unknwon
c5d4a9e046 #2907 Add commit timestamp to webhook 2016-08-09 18:28:06 -07:00
Unknwon
edd786446c #3158 skip RUN_USER check on Windows 2016-08-09 17:41:18 -07:00
Unknwon
b0b88d9bc5 #3091 add config option for Git GC 2016-08-09 17:24:32 -07:00
Unknwon
15b0cbe318 #3007 update git-module require version 2016-08-09 17:15:48 -07:00
Unknwon
9f0c571238 Change LICENSE copyright holder name [CI SKIP] 2016-08-09 13:05:15 -07:00
Unknwon
f70343660d Little code refactoring 2016-08-09 12:56:00 -07:00
Rory McNamara
c8b45ecc27 Render the Code view on the server (minus syntax highlighting) (#2942)
* render code view server side

* remove debug print

* fix multiline selection bug

* change string concatenation to bytes.Buffer for efficiency

* Fix newlines added by previous for hljs

* fix selection highlighting

* make css changes in .less
2016-08-09 12:35:20 -07:00
Unknwon
9e8a8867ea #3325 use correct word for .gitignore 2016-08-09 12:16:21 -07:00
lstahlman
2c82fc3edb Fix for #3410 overall issues for organisations is limited to num_repos from the user (#3412) 2016-08-09 10:00:42 -07:00
Unknwon
bbe866122d #3406 fix regression of MustEnableIssues check 2016-08-09 09:39:55 -07:00
Unknwon
87954dbfeb Adjust .codebeatsettings 2016-08-08 23:26:10 -07:00
lstahlman
699c71d319 Fix for #3401 Links of pull request comment email should use pulls URL (#3403) 2016-08-08 22:40:05 -07:00
Unknwon
21f25799b4 Add codebeat files 2016-08-08 20:03:46 -07:00
Unknwon
90af997fec #3399 500 for upstream pulls page if user has forked repository 2016-08-08 13:02:55 -07:00
Unknwon
b73318bc62 Fix 404 when comment on pulls and not using interal issue tracker 2016-08-08 11:29:50 -07:00
Unknwon
e5bf4281b5 #2825 early response 200 when ?go-get=1 2016-08-07 14:29:16 -07:00
Unknwon
0c2b9bbb2b Update glide.lock and .gopmfile 2016-08-07 11:05:19 -07:00
Unknwon
99385db0c4 #3320 code cleanup 2016-08-07 11:01:47 -07:00
Sandro Santilli
90dd0657b5 Add support for federated avatars (#3320)
* Add support for federated avatars

Fixes #3105

Removes avatar fetching duplication code
Adds an "Enable Federated Avatar" checkbox in user settings
(defaults to unchecked)

Moves avatar settings all in the same form, making
local and remote avatars mutually exclusive

Renames UploadAvatarForm to AvatarForm
as it's not anymore only for uploading

* Run gofmt on all modified files

* Move Avatar form in its own page

* Add go-libravatar dependency to vendor/ dir

Hopefully helps with accepting the contribution.
See also #3214

* Revert "Add go-libravatar dependency to vendor/ dir"

This reverts commit a8cb93ae640bbb90f7d25012fc257bda9fae9b82.

* Make federated avatar setting a global configuration

Removes the per-user setting

* Move avatar handling back to base tool, disable federated avatar in offline mode

* Format, handle error

* Properly set fallback host

* Use unsupported github.com mirror for importing go-libravatar

* Remove comment showing life exists outside of github.com

... pity, but contribution would not be accepted otherwise

* Use Combo for Get and Post methods over /avatar

* FEDERATED_AVATAR -> ENABLE_FEDERATED_AVATAR

* Fix persistance of federated avatar lookup checkbox at install time

* Federated Avatars -> Enable Federated Avatars

* Use len(string) == 0 instead of string == ""

* Move import line where it belong

See
https://github.com/Unknwon/go-code-convention/blob/master/en-US/import_packages.md

Pity the import url is still the unofficial one, but oh well...

* Save a line (and waste much more expensive time)

* Remove redundant parens

* Remove an empty line

* Remove empty lines

* Reorder lines to make diff smaller

* Remove another newline

Unknwon review got me start a fight against newlines

* Move DISABLE_GRAVATAR and ENABLE_FEDERATED_AVATAR after OFFLINE_MODE

On re-reading the diff I figured what Unknwon meant here:
https://github.com/gogits/gogs/pull/3320/files#r73741106

* Remove newlines that weren't there before my intervention
2016-08-07 10:27:38 -07:00
Unknwon
ec92565f23 #3393 fix missing sub-url prefix in relative avatar link 2016-08-07 10:13:05 -07:00
Andrey Nering
2772791fda Improve diff highlight (#3390)
- Try to reduce memory allocations
- Add possibility to disable diff highlight (can improve performance for large diffs)
- Tweaking with cost for prettier (cleaner) diffs
- Do not calculate diff when the number of removed lines in a block is not equal to the number of added lines (this usually resulted in ugly diffs)
2016-08-07 09:49:47 -07:00
Unknwon
08c976f811 Only do go vet on this codebase 2016-08-06 11:20:10 -07:00
Unknwon
72dd299ca0 Update .gitattributes 2016-08-06 10:36:40 -07:00
Thibault Meyer
30fda0f1ae Fix #3315: Release dont use tag creation date (#3374)
* Fix #3315: Release dont use tag creation date

* Simplify code and apply gofmt

* remove useless block (ctx.Repo.GitRepo.GetTag) on EditReleasePost

* apply gofmt on modified files
2016-08-06 10:02:15 -07:00
Unknwon
ab9c5fb5e7 #2593 allow render raw content
Use URL query parameter render=1 to render content in raw mode.
2016-08-05 18:34:13 -07:00
rugk
28dc5bb566 Replace gogs.io http links with https version (#3386) 2016-08-05 17:35:40 -07:00
Unknwon
cf6d321991 Ignore repository with issue disabled or use external tracker in dashboard issues 2016-08-05 12:46:26 -07:00
Unknwon
50422f1fc2 #3348 always use relative avatar link in the template 2016-08-05 12:12:54 -07:00
Unknwon
db3d393576 routers/api: rename handlers to be unexported 2016-08-04 17:08:01 -07:00
Unknwon
2f105f3979 #2162 completely disable builtin issue tracker when enable external tracker 2016-08-04 16:32:02 -07:00
Unknwon
ee28fd9255 Update locales [CI SKIP] 2016-08-03 12:24:53 -07:00
Unknwon
13d492e92a Update .gopmfile and glide.lock 2016-08-03 12:12:33 -07:00
Unknwon
e7fd65f0cf #3290 better code structure and batch minor improvements 2016-08-03 11:51:22 -07:00
lstahlman
2eeb0ec9b0 Additional API support for labels (#3290)
* Add API support for labels.

* Error handling for adding/replacing multiple issue labels

* Revisions to function names and error handling. Use issue.ClearLabels in replace/clear functions

* Additional code cleanup
2016-08-03 09:24:16 -07:00
silverwind
b1133c9934 Lighter icon colors for repo files (#3351)
* Lighter icon colors for repo files

* also color submodule icon
2016-08-03 08:53:28 -07:00
Unknwon
991ce42c48 #2162 improve repository advance options UI display
Enable/disable input based on user chosen options for wiki and issue tracker.
2016-07-31 01:26:43 +08:00
Unknwon
10dc330640 #3345 dump content directly to HTTP ResponseWriter 2016-07-30 23:39:58 +08:00
Dennis Chen
dfab54d5a2 Diff patch (#3345)
* Add support for .diff and .patch

Add the ability to get text-diff and format-patch by adding .diff or
.patch in the end of a commit url. Issue #2641

* models: git_diff: various fixes

* Renames commitId to commitID.
* Writes stderr to a bytes.Buffer and displays proper error message on
command failure.
* Various style changes.

Signed-off-by: Dennis Chen <barracks510@gmail.com>
2016-07-30 23:02:22 +08:00
Unknwon
3e22ae3412 Update locales 2016-07-30 22:28:23 +08:00
Okunev Yu Dmitry
55b4e77a5e Fix of template error in "/:owner/:repo/pulls" (#3343)
If anonymous (not signed in user) requests page
"/:owner/:repo/pulls" he gets an error:

  template: repo/issue/list:11:105: executing "repo/issue/list" at <.PullRequestCtx.Base...>: nil pointer evaluating *models.Repository.Link

This commit fixes that.

Signed-off-by: Dmitry Yu Okunev <dyokunev@ut.mephi.ru>
2016-07-29 22:59:38 +08:00
Unknwon
ad7ea88923 Update glide.lock 2016-07-28 11:00:14 +08:00
Unknwon
f2884d8e31 Minor fix for pull request template [CI SKIP] 2016-07-28 10:54:52 +08:00
마누엘
36a63dd059 models/release: Update Sha1 if tag already exists (#3331)
Since the release struct is initialized with the current `HEAD` of the
current `release.Target` the commit id has to be updated if the tag
commit already exists. Otherwise the linked commit on the release page
will target the current `HEAD` at release time.
2016-07-28 10:45:35 +08:00
Unknwon
03ba257ad2 Update GitHub templates 2016-07-28 10:36:26 +08:00
마누엘
fe60ca408b routers/repo/release: Use correct branch reference (#3330)
When calculating the current behind commit count the calculation should
use the current release target to get the total commit count. Should the
release target not exist anymore the calculation will return zero for
the newest release on that target. Older releases on that target will then
use that calculated commit count as reference.

The only use case that is now somehow invalid is when the release target
was merged / deleted after a tag on that release target:

    master 1 - - - - - - - 6
            \             /
    branch   2 - 3 - 4 - 5

When `4` is the last tag on branch `branch` and the branch `branch` is not
yet deleted the calculated numbers would be:

    1 commits to branch since this release

Now if the branch `branch` gets deleted the calculation function will not
find the branch and use the commit count of the newest release (`4`) as
reference resulting in:

    0 commit to branch since this release

This fixes #3326
2016-07-27 16:57:32 +08:00
Richard Mahn
0402c803c6 Added Full Name to CreateUser api call (#3333) 2016-07-27 02:43:06 +08:00
Unknwon
29ccf047d8 routers/repo/issue: remove redundant format string 2016-07-26 18:42:18 +08:00
Unknwon
8aa0a76702 #3327 fix wrong table name in Join 2016-07-26 18:40:20 +08:00
Unknwon
2d76de2574 #3281 fix x.Iterate returns nothing inside session scope with SQLite3 2016-07-26 17:26:48 +08:00
Unknwon
4d8b905541 models/ssh_key: code cleaning 2016-07-26 10:47:25 +08:00
Unknwon
452aefd025 Fix issue event octicon CSS 2016-07-26 02:56:07 +08:00
Unknwon
899e799459 #1601 support delete issue comment 2016-07-26 02:48:17 +08:00
Unknwon
2295fafb34 repo/settings/options: take naming style examples out of locale string 2016-07-25 16:55:51 +08:00
Unknwon
a562228c5e Add org.getUserTeams to reduce redundant code 2016-07-24 18:09:45 +08:00
Unknwon
e74630ae3b #1384 add pagination for repositories 2016-07-24 14:32:46 +08:00
Unknwon
1f2e173a74 Refactor User.Id to User.ID 2016-07-24 01:08:22 +08:00
Unknwon
46e96c008c Use struct for UI settings 2016-07-24 00:23:54 +08:00
Unknwon
256cd6374a #2790 fix not detect diff style in pull request file changes 2016-07-23 23:46:49 +08:00
Unknwon
57a47bbc05 Add some tutorial links [CI SKIP] 2016-07-23 21:23:30 +08:00
Unknwon
024fcc836b Minor HTML fix for delete repository notice 2016-07-23 20:42:46 +08:00
Unknwon
250be011c7 Remove redundant Unix timestamp method call
Unix() already uses UTC as timezone
2016-07-23 20:24:44 +08:00
Unknwon
4e822c1911 conf: change default mirror checking interval to 10m 2016-07-23 20:20:09 +08:00
Unknwon
26d52ceb48 #3186 fix wrong link for new pull request button of non-fork repository 2016-07-23 19:55:53 +08:00
Unknwon
d90acacd86 Update README [CI SKIP] 2016-07-23 19:22:43 +08:00
Unknwon
69f5308761 #2903 use different reversed words and patterns for repository and user 2016-07-23 18:58:18 +08:00
Unknwon
4b5e09e4d6 #3181 detect situation when base branch is deleted in pull request 2016-07-23 18:35:16 +08:00
Unknwon
4f78abe7dc #3066 fix create organization ignores full name property 2016-07-23 17:57:22 +08:00
Unknwon
e63b2881b1 api: fix panic if anonymous user request admin API
Add sign in check before check user account level
2016-07-23 17:56:37 +08:00
Unknwon
745167d57a #3157 create user path before rename repository while transfer
os.Rename does not create parent directory automatically when not exist
2016-07-23 17:36:15 +08:00
Unknwon
d7bdc1de8d #3107 fix mention regex does not include dash 2016-07-23 17:29:34 +08:00
Unknwon
c912494609 #3076 detect invalid tag name git error 2016-07-23 15:59:19 +08:00
Richard Mahn
69dae1ec1c Added coding style modes to SimpleMDE (#3286)
* Added coding style modes to SimpleMDE

* Moved the CodeMirror addon from simplemd to codemirror directory
2016-07-23 13:29:20 +08:00
Siarhei Navatski
cf85e9eb7b add IsSubmodule field to DiffFile and hide view file button on diff page for submodules (#3097) 2016-07-23 02:18:56 +08:00
Unknwon
599716bb1b Update locales [CI SKIP] 2016-07-22 22:21:26 +08:00
Unknwon
ae88d76032 Bump version 2016-07-22 21:52:39 +08:00
Unknwon
9266f28822 Fix GitHub wrong repo language detection 2016-07-21 18:20:03 +08:00
Dennis Chen
6488ee12be avatar: make custom and generated avatars equal (#3301)
Sets all avatars to use PNG image format.
Keeps avatars consistent at 290x290px resolution.

Signed-off-by: Dennis Chen <barracks510@gmail.com>
2016-07-21 15:31:14 +08:00
Unknwon
c2fb01a257 #3299 don’t pop up confirm box when leave on signin page 2016-07-21 14:36:26 +08:00
Unknwon
5761342f32 #3291 fix SQLite3 session read/update conflict on create new issue 2016-07-21 14:26:30 +08:00
Unknwon
57af7432fc #3295 fix wrong logic judgement 2016-07-21 14:15:04 +08:00
1484 changed files with 703740 additions and 7549 deletions

View File

@@ -1,6 +1,6 @@
[run]
init_cmds = [
["make", "build-dev", "TAGS=sqlite"],
["make", "build-dev"],
["./gogs", "web"]
]
watch_all = true
@@ -14,6 +14,6 @@ watch_exts = [".go"]
ignore_files = [".+_test.go"]
build_delay = 1500
cmds = [
["make", "build-dev", "TAGS=sqlite"], # cert pam tidb
["make", "build-dev"], # TAGS=sqlite cert pam tidb
["./gogs", "web"]
]

7
.codebeatignore Normal file
View File

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

7
.codebeatsettings Normal file
View File

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

View File

@@ -5,8 +5,21 @@ root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
[*.yml]
[*.go]
indent_style = tab
indent_size = 4
[*.tmpl]
indent_style = tab
indent_size = 2
[*.{less,yml}]
indent_style = space
indent_size = 2
[*.js]
indent_style = space
indent_size = 4

11
.gitattributes vendored Normal file
View File

@@ -0,0 +1,11 @@
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.7.min.css linguist-vendored
public/js/libs/* linguist-vendored
public/js/jquery-1.11.3.min.js linguist-vendored
public/js/semantic-2.2.7.min.js linguist-vendored

View File

@@ -46,7 +46,7 @@ Please read detailed information on [Wiki](https://github.com/gogits/gogs/wiki/C
### Ask For Help
Before opening an issue, please make sure your problem isn't already addressed on the [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.html) and [FAQs](http://gogs.io/docs/intro/faqs.html) pages.
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

View File

@@ -1,17 +1,20 @@
We DO NOT take questions or config/deploy problems on GitHub, please use our forum: https://discuss.gogs.io
The issue will be closed without any reasons if it does not satisfy any of following requirements:
Please take a moment to search that an issue doesn't already exist.
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.
For bug reports, please give the relevant info:
**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:
- Gogs version (or commit ref):
- Git version:
- Operating system:
- Database (use `[x]`):
- [ ] PostgreSQL
- [ ] MySQL
- [ ] SQLite
- Can you reproduce the bug at http://try.gogs.io:
- Can you reproduce the bug at https://try.gogs.io:
- [ ] Yes (provide example URL)
- [ ] No
- [ ] Not relevant

View File

@@ -1,4 +1,9 @@
Please, make sure you are targeting the `develop` branch!
The pull request will be closed without any reasons if it does not satisfy any of following requirements:
More instructions about contributing with Gogs code can be found here:
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.**

1
.gitignore vendored
View File

@@ -17,4 +17,3 @@ output*
gogs.sublime-project
gogs.sublime-workspace
/release
vendor

View File

@@ -2,57 +2,63 @@
path = github.com/gogits/gogs
[deps]
github.com/bradfitz/gomemcache = commit:fb1f79c
github.com/codegangsta/cli = commit:1efa31f
github.com/go-macaron/binding = commit:9440f33
github.com/bradfitz/gomemcache = commit:2fafb84
github.com/urfave/cli = commit:347a988
github.com/go-macaron/binding = commit:4892016
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/inject = commit:d8a0b86
github.com/go-macaron/session = commit:66031fc
github.com/go-macaron/toolbox = commit:82b5115
github.com/go-sql-driver/mysql = commit:3654d25
github.com/go-xorm/core = commit:bc1b7f8
github.com/go-xorm/xorm = commit:b8b1711
github.com/go-sql-driver/mysql = commit:2e00b5c
github.com/go-xorm/builder = commit:867edcc
github.com/go-xorm/core = commit:2fbe2c7
github.com/go-xorm/xorm = commit:445a934
github.com/gogits/chardet = commit:2404f77
github.com/gogits/cron = commit:96040e4
github.com/gogits/git-module = commit:db93fa5
github.com/gogits/go-gogs-client = commit:ee68cd9
github.com/gogits/cron = commit:2fc07a4
github.com/gogits/git-module = commit:172cbc2
github.com/gogits/go-gogs-client = commit:98046bb
github.com/gogits/go-libravatar = commit:cd1abbd
github.com/issue9/identicon = commit:d36b545
github.com/jaytaylor/html2text = commit:52d9b78
github.com/jaytaylor/html2text = commit:d16d412
github.com/kardianos/minwinsvc = commit:cad6b2b
github.com/klauspost/compress = commit:14eb9c4
github.com/klauspost/compress = commit:461e8fd
github.com/klauspost/cpuid = commit:09cded8
github.com/klauspost/crc32 = commit:19b0b33
github.com/lib/pq = commit:ee1442b
github.com/mattn/go-sqlite3 = commit:38ee283
github.com/mcuadros/go-version = commit:d52711f
github.com/microcosm-cc/bluemonday = commit:4ac6f27
github.com/klauspost/crc32 = commit:cb6bfca
github.com/lib/pq = commit:67c3f2a
github.com/mattn/go-colorable = commit:d228849
github.com/mattn/go-isatty = commit:30a891c
github.com/mattn/go-sqlite3 = commit:ce9149a
github.com/mcuadros/go-version = commit:257f7b9
github.com/microcosm-cc/bluemonday = commit:e797637
github.com/msteinert/pam = commit:02ccfbf
github.com/nfnt/resize = commit:4d93a29
github.com/russross/blackfriday = commit:4e6f303
github.com/satori/go.uuid = commit:879c588
github.com/sergi/go-diff = commit:ec7fdbb
github.com/shurcooL/sanitized_anchor_name = commit:10ef21a
github.com/Unknwon/cae = commit:7f5e046
github.com/nfnt/resize = commit:891127d
github.com/russross/blackfriday = commit:5f33e7b
github.com/satori/go.uuid = commit:b061729
github.com/sergi/go-diff = commit:24e2351
github.com/shurcooL/sanitized_anchor_name = commit:1dba4b3
github.com/Unknwon/cae = commit:c6aac99
github.com/Unknwon/com = commit:28b053d
github.com/Unknwon/i18n = commit:39d6f27
github.com/Unknwon/paginater = commit:7748a72
golang.org/x/crypto = commit:77f4136
golang.org/x/net = commit:3f122ce
golang.org/x/sys = commit:7f918dd
golang.org/x/text = commit:e477511
github.com/Unknwon/paginater = commit:701c23f
github.com/fatih/color = commit:42c364b
golang.org/x/crypto = commit:dc137be
golang.org/x/net = commit:f249948
golang.org/x/sys = commit:d75a526
golang.org/x/text = commit:ece019d
gopkg.in/alexcesaro/quotedprintable.v3 = commit:2caba25
gopkg.in/asn1-ber.v1 = commit:4e86f43
gopkg.in/bufio.v1 = commit:567b2bf
gopkg.in/clog.v1 = commit:d359c28
gopkg.in/editorconfig/editorconfig-core-go.v1 = commit:a872f05
gopkg.in/gomail.v2 = commit:81ebce5
gopkg.in/ini.v1 = commit:72ba3e6
gopkg.in/ldap.v2 = commit:0e7db8e
gopkg.in/macaron.v1 = commit:2133042
gopkg.in/ini.v1 = commit:e3c2d47
gopkg.in/ldap.v2 = commit:8168ee0
gopkg.in/macaron.v1 = commit:78521e4
gopkg.in/redis.v2 = commit:e617904
[res]
include = public|scripts|templates

2
.mailmap Normal file
View File

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

View File

@@ -7,10 +7,15 @@ targets:
- git
debian-8:
<<: *debian
ubuntu-14.04:
<<: *debian
ubuntu-12.04:
<<: *debian
ubuntu-14.04:
<<: *debian
ubuntu-16.04:
<<: *debian
build_dependencies:
- bzr
- mercurial
centos-6: &el
build_dependencies:
- pam-devel

View File

@@ -1,29 +1,17 @@
language: go
go:
- 1.4
- 1.5
- 1.6
- 1.5.x
- 1.6.x
- 1.7.x
- master
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 ./...
env:
- GO15VENDOREXPERIMENT=1
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

22
Dockerfile.aarch64 Normal file
View File

@@ -0,0 +1,22 @@
FROM aarch64/alpine:3.5
MAINTAINER atzoum@gmail.com
# Install system utils & Gogs runtime dependencies
ADD https://github.com/tianon/gosu/releases/download/1.9/gosu-arm64 /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/"]

View File

@@ -1,4 +1,4 @@
Copyright (c) 2014 All Gogs Contributors
Copyright (c) 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

View File

@@ -5,25 +5,39 @@ 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
OS := $(shell uname)
TAGS = ""
BUILD_FLAGS = "-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
.PHONY: build pack release bindata clean
.IGNORE: public/css/gogs.css
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' .
govet:
go tool vet -composites=false -methods=false -structtags=false .
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' .
@@ -60,3 +74,7 @@ fixme:
todo:
grep -rnw "TODO" routers models modules
# Legacy code should be remove by the time of release
legacy:
grep -rnw "LEGACY" routers models modules

View File

@@ -1,9 +1,9 @@
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)
Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs) [![Build status](https://ci.appveyor.com/api/projects/status/b9uu5ejl933e2wlt/branch/master?svg=true)](https://ci.appveyor.com/project/Unknwon/gogs/branch/master) [![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/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true)
##### Current tip version: 0.9.46 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
##### Current tip version: [`.VERSION`](templates/.VERSION) (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/)~~)
| Web | UI | Preview |
|:-------------:|:-------:|:-------:|
@@ -18,7 +18,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
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](http://gogs.io), contact us by any means.
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)
@@ -28,11 +28,10 @@ The goal of this project is to make the easiest, fastest, and most painless way
## Overview
- Please see the [Documentation](http://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.
- Please see the [Documentation](https://gogs.io/docs/intro) for common usages and change log.
- Want to try it before doing anything else? Do it [online](https://try.gogs.io/gogs/gogs)!
- Having trouble? Get help with [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.html) or [User Forum](https://discuss.gogs.io/).
- Want to help with localization? Check out the [guide](http://gogs.io/docs/features/i18n.html)!
- 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)!
## Features
@@ -41,15 +40,17 @@ The goal of this project is to make the easiest, fastest, and most painless way
- 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
- Add/Remove repository collaborators
- Gravatar and custom source
- 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 ([18 languages](https://crowdin.com/project/gogs))
- Multi-language support ([22 languages](https://crowdin.com/project/gogs))
## System Requirements
@@ -59,17 +60,17 @@ The goal of this project is to make the easiest, fastest, and most painless way
## Browser Support
- Please see [Semantic UI](https://github.com/Semantic-Org/Semantic-UI#browser-support) for specific versions of supported browsers.
- The official support minimal size is **1024*768**, UI may still looks right in smaller size but no promises and fixes.
- The smallest resolution officially supported is **1024*768**, however the UI may still look right in smaller resolutions, but no promises or fixes.
## Installation
Make sure you install the [prerequisites](http://gogs.io/docs/installation) first.
Make sure you install the [prerequisites](https://gogs.io/docs/installation) first.
There are 5 ways to install Gogs:
- [Install from binary](http://gogs.io/docs/installation/install_from_binary.html)
- [Install from source](http://gogs.io/docs/installation/install_from_source.html)
- [Install from packages](http://gogs.io/docs/installation/install_from_packages.html)
- [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)
@@ -77,6 +78,8 @@ There are 5 ways to install Gogs:
- [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)
@@ -85,6 +88,7 @@ There are 5 ways to install Gogs:
### 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
@@ -95,7 +99,7 @@ There are 5 ways to install 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)
- [YunoHost](https://github.com/YunoHost-Apps/gogs_ynh)
- [DPlatform](https://github.com/j8r/DPlatform)
## Software and Service Support
@@ -117,10 +121,10 @@ There are 5 ways to install Gogs:
- 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 [lavachen](http://www.lavachen.cn/) and [Rocker](http://weibo.com/rocker1989) for designing Logo.
- 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/) for providing CDN service.
- Thanks [KeyCDN](https://www.keycdn.com/) and [QiNiu](http://www.qiniu.com/) for providing CDN service.
## Contributors

View File

@@ -9,11 +9,10 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
## 项目概览
- 有关基本用法和变更日志,请通过 [使用手册](http://gogs.io/docs/intro/) 查看。
- 您可以到 [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) 跟随开发团队的脚步。
- 有关基本用法和变更日志,请通过 [使用手册](https://gogs.io/docs/intro/) 查看。
- 想要先睹为快?直接去 [在线体验](https://try.gogs.io/gogs/gogs) 。
- 使用过程中遇到问题?尝试从 [故障排查](http://gogs.io/docs/intro/troubleshooting.html) 页面或 [用户论坛](https://discuss.gogs.io/) 获取帮助。
- 希望帮助多国语言界面的翻译吗?请立即访问 [详情页面](http://gogs.io/docs/features/i18n.html)
- 使用过程中遇到问题?尝试从 [故障排查](https://gogs.io/docs/intro/troubleshooting.html) 页面或 [用户论坛](https://discuss.gogs.io/) 获取帮助。
- 希望帮助多国语言界面的翻译吗?请立即访问 [详情页面](https://gogs.io/docs/features/i18n.html)
## 功能特性
@@ -22,15 +21,17 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- 支持 SMTP、LDAP 和反向代理的用户认证
- 支持反向代理子路径
- 支持用户、组织和仓库管理系统
- 支持添加和删除仓库协作者
- 支持仓库和组织级别 Web 钩子(包括 Slack 集成)
- 支持仓库 Git 钩子和部署密钥
- 支持仓库工单Issue、合并请求Pull Request以及 Wiki
- 支持添加和删除仓库协作者
- 支持 Gravatar 以及自定义源
- 支持迁移和镜像仓库以及它的 Wiki
- 支持在线编辑仓库文件和 Wiki
- 支持自定义源的 Gravatar 和 Federated Avatar
- 支持邮件服务
- 支持后台管理面板
- 支持 MySQL、PostgreSQL、SQLite3 和 [TiDB](https://github.com/pingcap/tidb)(实验性支持) 数据库
- 支持多语言本地化([18 种语言]([more](https://crowdin.com/project/gogs))
- 支持多语言本地化([22 种语言]([more](https://crowdin.com/project/gogs))
## 系统要求
@@ -44,13 +45,13 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
## 安装部署
在安装 Gogs 之前,您需要先安装 [基本环境](http://gogs.io/docs/installation)。
在安装 Gogs 之前,您需要先安装 [基本环境](https://gogs.io/docs/installation)。
然后,您可以通过以下 5 种方式来安装 Gogs
- [二进制安装](http://gogs.io/docs/installation/install_from_binary.html)
- [源码安装](http://gogs.io/docs/installation/install_from_source.html)
- [包管理安装](http://gogs.io/docs/installation/install_from_packages.html)
- [二进制安装](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)
@@ -89,10 +90,10 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- 基于 [Macaron](https://github.com/go-macaron/macaron) 的路由与中间件机制。
- 基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改的系统监视状态。
- 感谢 [lavachen](http://www.lavachen.cn/) 和 [Rocker](http://weibo.com/rocker1989) 设计的 Logo。
- 感谢 [Rocker](http://weibo.com/rocker1989) 设计的 Logo。
- 感谢 [Crowdin](https://crowdin.com/project/gogs) 提供免费的开源项目本地化支持。
- 感谢 [DigitalOcean](https://www.digitalocean.com) 提供主站和体验站点的服务器赞助。
- 感谢 [KeyCDN](https://www.keycdn.com/) 提供 CDN 服务赞助。
- 感谢 [KeyCDN](https://www.keycdn.com/) 和 [七牛云存储](http://www.qiniu.com/) 提供 CDN 服务赞助。
## 贡献成员

20
appveyor.yml Normal file
View File

@@ -0,0 +1,20 @@
version: "{build}"
skip_tags: true
clone_folder: c:\gopath\src\github.com\gogits\gogs
clone_depth: 1
environment:
GOPATH: c:\gopath
GOVERSION: 1.7
build: false
deploy: false
install:
- go build -v
notifications:
- provider: Email
to:
- u@gogs.io
on_build_success: false

70
cmd/admin.go Normal file
View File

@@ -0,0 +1,70 @@
// Copyright 2016 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"
"github.com/urfave/cli"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/setting"
)
var (
CmdAdmin = cli.Command{
Name: "admin",
Usage: "Preform admin operations on command line",
Description: `Allow using internal logic of Gogs without hacking into the source code
to make automatic initialization process more smoothly`,
Subcommands: []cli.Command{
subcmdCreateUser,
},
}
subcmdCreateUser = cli.Command{
Name: "create-user",
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"),
},
}
)
func runCreateUser(c *cli.Context) error {
if !c.IsSet("name") {
return fmt.Errorf("Username is not specified")
} else if !c.IsSet("password") {
return fmt.Errorf("Password is not specified")
} else if !c.IsSet("email") {
return fmt.Errorf("Email is not specified")
}
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
setting.NewContext()
models.LoadConfigs()
models.SetEngine()
if err := models.CreateUser(&models.User{
Name: c.String("name"),
Email: c.String("email"),
Passwd: c.String("password"),
IsActive: true,
IsAdmin: c.Bool("admin"),
}); err != nil {
return fmt.Errorf("CreateUser: %v", err)
}
fmt.Printf("New user '%s' has been successfully created!\n", c.String("name"))
return nil
}

View File

@@ -22,7 +22,7 @@ import (
"strings"
"time"
"github.com/codegangsta/cli"
"github.com/urfave/cli"
)
var CmdCert = cli.Command{

View File

@@ -10,7 +10,7 @@ import (
"fmt"
"os"
"github.com/codegangsta/cli"
"github.com/urfave/cli"
)
var CmdCert = cli.Command{

View File

@@ -7,7 +7,7 @@ package cmd
import (
"time"
"github.com/codegangsta/cli"
"github.com/urfave/cli"
)
func stringFlag(name, value, usage string) cli.StringFlag {

View File

@@ -14,7 +14,8 @@ import (
"io/ioutil"
"github.com/Unknwon/cae/zip"
"github.com/codegangsta/cli"
"github.com/Unknwon/com"
"github.com/urfave/cli"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/setting"
@@ -87,15 +88,32 @@ func runDump(ctx *cli.Context) error {
} else {
log.Printf("Custom dir %s doesn't exist, skipped", setting.CustomPath)
}
if err := z.AddDir("log", setting.LogRootPath); err != nil {
log.Fatalf("Fail to include log: %v", err)
}
for _, dir := range []string{"attachments", "avatars"} {
dirPath := path.Join(setting.AppDataPath, dir)
if !com.IsDir(dirPath) {
continue
}
if err := z.AddDir(path.Join("data", dir), dirPath); err != nil {
log.Fatalf("Fail to include '%s': %v", dirPath, err)
}
}
// FIXME: SSH key file.
if err = z.Close(); err != nil {
os.Remove(fileName)
log.Fatalf("Fail to save %s: %v", fileName, err)
}
if err := os.Chmod(fileName, 0600); err != nil {
log.Printf("Can't change file access permissions mask to 0600: %v", err)
}
log.Printf("Removing tmp work dir: %s", TmpWorkDir)
os.RemoveAll(TmpWorkDir)
log.Printf("Finish dumping in file %s", fileName)

82
cmd/import.go Normal file
View File

@@ -0,0 +1,82 @@
// Copyright 2016 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"
"path/filepath"
"time"
"github.com/Unknwon/com"
"github.com/urfave/cli"
"github.com/gogits/gogs/modules/setting"
)
var (
CmdImport = cli.Command{
Name: "import",
Usage: "Import portable data as local Gogs data",
Description: `Allow user import data from other Gogs installations to local instance
without manually hacking the data files`,
Subcommands: []cli.Command{
subcmdImportLocale,
},
}
subcmdImportLocale = cli.Command{
Name: "locale",
Usage: "Import locale files to local repository",
Action: runImportLocale,
Flags: []cli.Flag{
stringFlag("source", "", "Source directory that stores new locale files"),
stringFlag("target", "", "Target directory that stores old locale files"),
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
},
}
)
func runImportLocale(c *cli.Context) error {
if !c.IsSet("source") {
return fmt.Errorf("Source directory is not specified")
} else if !c.IsSet("target") {
return fmt.Errorf("Target directory is not specified")
}
if !com.IsDir(c.String("source")) {
return fmt.Errorf("Source directory does not exist or is not a directory")
} else if !com.IsDir(c.String("target")) {
return fmt.Errorf("Target directory does not exist or is not a directory")
}
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
setting.NewContext()
now := time.Now()
// Cut out en-US.
for _, lang := range setting.Langs[1:] {
name := fmt.Sprintf("locale_%s.ini", lang)
source := filepath.Join(c.String("source"), name)
target := filepath.Join(c.String("target"), name)
if !com.IsFile(source) {
continue
}
if err := com.Copy(source, target); err != nil {
return fmt.Errorf("Copy file: %v", err)
}
// Modification time of files from Crowdin often ahead of current,
// so we need to set back to current.
os.Chtimes(target, now, now)
}
fmt.Println("Locale files has been successfully imported!")
return nil
}

View File

@@ -14,13 +14,14 @@ import (
"time"
"github.com/Unknwon/com"
"github.com/codegangsta/cli"
git "github.com/gogits/git-module"
gouuid "github.com/satori/go.uuid"
"github.com/urfave/cli"
log "gopkg.in/clog.v1"
"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"
)
@@ -40,7 +41,16 @@ var CmdServ = cli.Command{
func setup(logPath string) {
setting.NewContext()
log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
setting.NewService()
log.New(log.FILE, log.FileConfig{
Filename: filepath.Join(setting.LogRootPath, logPath),
FileRotationConfig: log.FileRotationConfig{
Rotate: true,
Daily: true,
MaxDays: 3,
},
})
log.Delete(log.CONSOLE) // Remove primary logger
models.LoadConfigs()
@@ -60,6 +70,24 @@ func parseCmd(cmd string) (string, string) {
return ss[0], strings.Replace(ss[1], "'/", "'", 1)
}
func checkDeployKey(key *models.PublicKey, repo *models.Repository) {
// Check if this deploy key belongs to current repository.
if !models.HasDeployKey(key.ID, repo.ID) {
fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
}
// Update deploy key activity.
deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID)
if err != nil {
fail("Internal error", "GetDeployKey: %v", err)
}
deployKey.Updated = time.Now()
if err = models.UpdateDeployKey(deployKey); err != nil {
fail("Internal error", "UpdateDeployKey: %v", err)
}
}
var (
allowedCommands = map[string]models.AccessMode{
"git-upload-pack": models.ACCESS_MODE_READ,
@@ -75,11 +103,10 @@ func fail(userMessage, logMessage string, args ...interface{}) {
if !setting.ProdMode {
fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
}
log.GitLogger.Fatal(3, logMessage, args...)
return
log.Fatal(3, logMessage, args...)
}
log.GitLogger.Close()
log.Shutdown()
os.Exit(1)
}
@@ -87,12 +114,12 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
task, err := models.GetUpdateTaskByUUID(uuid)
if err != nil {
if models.IsErrUpdateTaskNotExist(err) {
log.GitLogger.Trace("No update task is presented: %s", uuid)
log.Trace("No update task is presented: %s", uuid)
return
}
log.GitLogger.Fatal(2, "GetUpdateTaskByUUID: %v", err)
log.Fatal(2, "GetUpdateTaskByUUID: %v", err)
} else if err = models.DeleteUpdateTaskByUUID(uuid); err != nil {
log.GitLogger.Fatal(2, "DeleteUpdateTaskByUUID: %v", err)
log.Fatal(2, "DeleteUpdateTaskByUUID: %v", err)
}
if isWiki {
@@ -100,21 +127,21 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
}
if err = models.PushUpdate(models.PushUpdateOptions{
RefName: task.RefName,
RefFullName: task.RefName,
OldCommitID: task.OldCommitID,
NewCommitID: task.NewCommitID,
PusherID: user.Id,
PusherID: user.ID,
PusherName: user.Name,
RepoUserName: repoUser.Name,
RepoName: reponame,
}); err != nil {
log.GitLogger.Error(2, "Update: %v", err)
log.Error(2, "Update: %v", err)
}
// Ask for running deliver hook and test pull request tasks.
reqURL := setting.LocalURL + repoUser.Name + "/" + reponame + "/tasks/trigger?branch=" +
strings.TrimPrefix(task.RefName, "refs/heads/") + "&secret=" + base.EncodeMD5(repoUser.Salt)
log.GitLogger.Trace("Trigger task: %s", reqURL)
strings.TrimPrefix(task.RefName, git.BRANCH_PREFIX) + "&secret=" + base.EncodeMD5(repoUser.Salt) + "&pusher=" + com.ToStr(user.ID)
log.Trace("Trigger task: %s", reqURL)
resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
InsecureSkipVerify: true,
@@ -122,10 +149,10 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
if err == nil {
resp.Body.Close()
if resp.StatusCode/100 != 2 {
log.GitLogger.Error(2, "Fail to trigger task: not 2xx response code")
log.Error(2, "Fail to trigger task: not 2xx response code")
}
} else {
log.GitLogger.Error(2, "Fail to trigger task: %v", err)
log.Error(2, "Fail to trigger task: %v", err)
}
}
@@ -175,7 +202,7 @@ func runServ(c *cli.Context) error {
fail("Internal error", "Failed to get repository owner (%s): %v", username, err)
}
repo, err := models.GetRepositoryByName(repoUser.Id, reponame)
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)
@@ -193,47 +220,25 @@ func runServ(c *cli.Context) error {
fail("mirror repository is read-only", "")
}
// Allow anonymous clone for public repositories.
var (
keyID int64
user *models.User
)
// Allow anonymous (user is nil) clone for public repositories.
var user *models.User
key, err := models.GetPublicKeyByID(com.StrTo(strings.TrimPrefix(c.Args()[0], "key-")).MustInt64())
if err != nil {
fail("Invalid key ID", "Invalid key ID [%s]: %v", c.Args()[0], err)
}
if requestedMode == models.ACCESS_MODE_WRITE || repo.IsPrivate {
keys := strings.Split(c.Args()[0], "-")
if len(keys) != 2 {
fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
}
key, err := models.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64())
if err != nil {
fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err)
}
keyID = key.ID
// Check deploy key or user key.
if key.Type == models.KEY_TYPE_DEPLOY {
if key.IsDeployKey() {
if key.Mode < requestedMode {
fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
}
// Check if this deploy key belongs to current repository.
if !models.HasDeployKey(key.ID, repo.ID) {
fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
}
// Update deploy key activity.
deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID)
if err != nil {
fail("Internal error", "GetDeployKey: %v", err)
}
deployKey.Updated = time.Now()
if err = models.UpdateDeployKey(deployKey); err != nil {
fail("Internal error", "UpdateDeployKey: %v", err)
}
checkDeployKey(key, repo)
} else {
user, err = models.GetUserByKeyID(key.ID)
if err != nil {
fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err)
fail("internal error", "Failed to get user by key ID(%d): %v", key.ID, err)
}
mode, err := models.AccessLevel(user, repo)
@@ -249,6 +254,14 @@ func runServ(c *cli.Context) error {
user.Name, requestedMode, repoPath)
}
}
} else {
// Check if the key can access to the repository in case of it is a deploy key (a deploy keys != user key).
// A deploy key doesn't represent a signed in user, so in a site with Service.RequireSignInView activated
// we should give read access only in repositories where this deploy key is in use. In other case, a server
// or system using an active deploy key can get read access to all the repositories in a Gogs service.
if key.IsDeployKey() && setting.Service.RequireSignInView {
checkDeployKey(key, repo)
}
}
uuid := gouuid.NewV4().String()
@@ -279,10 +292,10 @@ func runServ(c *cli.Context) error {
}
// Update user key activity.
if keyID > 0 {
key, err := models.GetPublicKeyByID(keyID)
if key.ID > 0 {
key, err := models.GetPublicKeyByID(key.ID)
if err != nil {
fail("Internal error", "GetPublicKeyById: %v", err)
fail("Internal error", "GetPublicKeyByID: %v", err)
}
key.Updated = time.Now()

View File

@@ -7,10 +7,10 @@ package cmd
import (
"os"
"github.com/codegangsta/cli"
"github.com/urfave/cli"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
@@ -32,15 +32,15 @@ func runUpdate(c *cli.Context) error {
setup("update.log")
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
log.GitLogger.Trace("SSH_ORIGINAL_COMMAND is empty")
log.Trace("SSH_ORIGINAL_COMMAND is empty")
return nil
}
args := c.Args()
if len(args) != 3 {
log.GitLogger.Fatal(2, "Arguments received are not equal to three")
log.Fatal(2, "Arguments received are not equal to three")
} else if len(args[0]) == 0 {
log.GitLogger.Fatal(2, "First argument 'refName' is empty, shouldn't use")
log.Fatal(2, "First argument 'refName' is empty, shouldn't use")
}
task := models.UpdateTask{
@@ -51,7 +51,7 @@ func runUpdate(c *cli.Context) error {
}
if err := models.AddUpdateTask(&task); err != nil {
log.GitLogger.Fatal(2, "AddUpdateTask: %v", err)
log.Fatal(2, "AddUpdateTask: %v", err)
}
return nil

View File

@@ -8,13 +8,13 @@ import (
"crypto/tls"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/http/fcgi"
"os"
"path"
"strings"
"github.com/codegangsta/cli"
"github.com/go-macaron/binding"
"github.com/go-macaron/cache"
"github.com/go-macaron/captcha"
@@ -25,6 +25,8 @@ import (
"github.com/go-macaron/toolbox"
"github.com/go-xorm/xorm"
"github.com/mcuadros/go-version"
"github.com/urfave/cli"
log "gopkg.in/clog.v1"
"gopkg.in/ini.v1"
"gopkg.in/macaron.v1"
@@ -35,7 +37,7 @@ import (
"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/mailer"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/template"
"github.com/gogits/gogs/routers"
@@ -72,13 +74,18 @@ func checkVersion() {
if err != nil {
log.Fatal(4, "Fail to read 'templates/.VERSION': %v", err)
}
if string(data) != setting.AppVer {
log.Fatal(4, "Binary and template file version does not match, did you forget to recompile?")
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-xorm/xorm", func() string { return xorm.Version }, "0.6.0"},
{"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"},
@@ -86,14 +93,14 @@ func checkVersion() {
{"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.4"},
{"github.com/gogits/git-module", git.Version, "0.3.2"},
{"github.com/gogits/go-gogs-client", gogs.Version, "0.7.4"},
{"gopkg.in/macaron.v1", macaron.Version, "1.1.7"},
{"github.com/gogits/git-module", git.Version, "0.4.6"},
{"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),
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)
}
@@ -110,7 +117,7 @@ func newMacaron() *macaron.Macaron {
if setting.EnableGzip {
m.Use(gzip.Gziper())
}
if setting.Protocol == setting.FCGI {
if setting.Protocol == setting.SCHEME_FCGI {
m.SetURLPrefix(setting.AppSubUrl)
}
m.Use(macaron.Static(
@@ -134,7 +141,7 @@ func newMacaron() *macaron.Macaron {
Funcs: funcMap,
IndentJSON: macaron.Env != macaron.PROD,
}))
models.InitMailRender(path.Join(setting.StaticRootPath, "templates/mail"),
mailer.InitMailRender(path.Join(setting.StaticRootPath, "templates/mail"),
path.Join(setting.CustomPath, "templates/mail"), funcMap)
localeNames, err := bindata.AssetDir("conf/locale")
@@ -157,7 +164,7 @@ func newMacaron() *macaron.Macaron {
m.Use(cache.Cacher(cache.Options{
Adapter: setting.CacheAdapter,
AdapterConfig: setting.CacheConn,
Interval: setting.CacheInternal,
Interval: setting.CacheInterval,
}))
m.Use(captcha.Captchaer(captcha.Options{
SubURL: setting.AppSubUrl,
@@ -208,6 +215,7 @@ func runWeb(ctx *cli.Context) error {
})
m.Get("/repos", routers.ExploreRepos)
m.Get("/users", routers.ExploreUsers)
m.Get("/organizations", routers.ExploreOrganizations)
}, ignSignIn)
m.Combo("/install", routers.InstallInit).Get(routers.Install).
Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost)
@@ -226,7 +234,8 @@ func runWeb(ctx *cli.Context) error {
m.Group("/user/settings", func() {
m.Get("", user.Settings)
m.Post("", bindIgnErr(auth.UpdateProfileForm{}), user.SettingsPost)
m.Post("/avatar", binding.MultipartForm(auth.UploadAvatarForm{}), user.SettingsAvatar)
m.Combo("/avatar").Get(user.SettingsAvatar).
Post(binding.MultipartForm(auth.AvatarForm{}), user.SettingsAvatarPost)
m.Post("/avatar/delete", user.SettingsDeleteAvatar)
m.Combo("/email").Get(user.SettingsEmails).
Post(bindIgnErr(auth.AddEmailForm{}), user.SettingsEmailPost)
@@ -239,6 +248,12 @@ func runWeb(ctx *cli.Context) error {
m.Combo("/applications").Get(user.SettingsApplications).
Post(bindIgnErr(auth.NewAccessTokenForm{}), user.SettingsApplicationsPost)
m.Post("/applications/delete", user.SettingsDeleteApplication)
m.Group("/organizations", func() {
m.Get("", user.SettingsOrganizations)
m.Post("/leave", user.SettingsLeaveOrganization)
})
m.Route("/delete", "GET,POST", user.SettingsDelete)
}, reqSignIn, func(ctx *context.Context) {
ctx.Data["PageIsUserSettings"] = true
@@ -323,6 +338,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 {
@@ -346,8 +362,14 @@ func runWeb(ctx *cli.Context) error {
// ***** START: Organization *****
m.Group("/org", func() {
m.Get("/create", org.Create)
m.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost)
m.Group("", func() {
m.Get("/create", org.Create)
m.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost)
}, func(ctx *context.Context) {
if !ctx.User.CanCreateOrganization() {
ctx.NotFound()
}
})
m.Group("/:org", func() {
m.Get("/dashboard", user.Dashboard)
@@ -375,7 +397,7 @@ func runWeb(ctx *cli.Context) error {
m.Group("/settings", func() {
m.Combo("").Get(org.Settings).
Post(bindIgnErr(auth.UpdateOrgSettingForm{}), org.SettingsPost)
m.Post("/avatar", binding.MultipartForm(auth.UploadAvatarForm{}), org.SettingsAvatar)
m.Post("/avatar", binding.MultipartForm(auth.AvatarForm{}), org.SettingsAvatar)
m.Post("/avatar/delete", org.SettingsDeleteAvatar)
m.Group("/hooks", func() {
@@ -448,11 +470,12 @@ func runWeb(ctx *cli.Context) error {
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
m.Group("/:username/:reponame", func() {
// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
// So they can apply their own enable/disable logic on routers.
m.Group("/issues", func() {
m.Combo("/new", repo.MustEnableIssues).Get(context.RepoRef(), repo.NewIssue).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
m.Combo("/:index/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
m.Group("/:index", func() {
m.Post("/label", repo.UpdateIssueLabel)
m.Post("/milestone", repo.UpdateIssueMilestone)
@@ -462,13 +485,18 @@ func runWeb(ctx *cli.Context) error {
m.Group("/:index", func() {
m.Post("/title", repo.UpdateIssueTitle)
m.Post("/content", repo.UpdateIssueContent)
m.Combo("/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
})
})
m.Post("/comments/:id", repo.UpdateCommentContent)
m.Group("/comments/:id", func() {
m.Post("", repo.UpdateCommentContent)
m.Post("/delete", repo.DeleteComment)
})
m.Group("/labels", func() {
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
m.Post("/delete", repo.DeleteLabel)
m.Post("/initialize", bindIgnErr(auth.InitializeLabelsForm{}), repo.InitializeLabels)
}, reqRepoWriter, context.RepoRef())
m.Group("/milestones", func() {
m.Combo("/new").Get(repo.NewMilestone).
@@ -482,13 +510,60 @@ func runWeb(ctx *cli.Context) error {
m.Group("/releases", func() {
m.Get("/new", repo.NewRelease)
m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
m.Get("/edit/:tagname", repo.EditRelease)
m.Post("/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
m.Post("/delete", repo.DeleteRelease)
}, reqRepoWriter, context.RepoRef())
m.Group("/releases", func() {
m.Get("/edit/*", repo.EditRelease)
m.Post("/edit/*", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
}, reqRepoWriter, func(ctx *context.Context) {
var err error
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
if err != nil {
ctx.Handle(500, "GetBranchCommit", err)
return
}
ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
if err != nil {
ctx.Handle(500, "CommitsCount", err)
return
}
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
})
// FIXME: Should use ctx.Repo.PullRequest to unify template, currently we have inconsistent URL
// for PR in same repository. After select branch on the page, the URL contains redundant head user name.
// e.g. /org1/test-repo/compare/master...org1:develop
// which should be /org1/test-repo/compare/master...develop
m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
m.Group("", func() {
m.Combo("/_edit/*").Get(repo.EditFile).
Post(bindIgnErr(auth.EditRepoFileForm{}), repo.EditFilePost)
m.Combo("/_new/*").Get(repo.NewFile).
Post(bindIgnErr(auth.EditRepoFileForm{}), repo.NewFilePost)
m.Post("/_preview/*", bindIgnErr(auth.EditPreviewDiffForm{}), repo.DiffPreviewPost)
m.Combo("/_delete/*").Get(repo.DeleteFile).
Post(bindIgnErr(auth.DeleteRepoFileForm{}), repo.DeleteFilePost)
m.Group("", func() {
m.Combo("/_upload/*").Get(repo.UploadFile).
Post(bindIgnErr(auth.UploadRepoFileForm{}), repo.UploadFilePost)
m.Post("/upload-file", repo.UploadFileToServer)
m.Post("/upload-remove", bindIgnErr(auth.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
}, func(ctx *context.Context) {
if !setting.Repository.Upload.Enabled {
ctx.Handle(404, "", nil)
return
}
})
}, reqRepoWriter, context.RepoRef(), func(ctx *context.Context) {
if !ctx.Repo.Repository.CanEnableEditor() || ctx.Repo.IsViewCommit {
ctx.Handle(404, "", nil)
return
}
})
}, reqSignIn, context.RepoAssignment(), repo.MustBeNotBare)
m.Group("/:username/:reponame", func() {
@@ -501,6 +576,7 @@ func runWeb(ctx *cli.Context) error {
}, context.RepoRef())
// m.Get("/branches", repo.Branches)
m.Post("/branches/delete/*", reqSignIn, reqRepoWriter, repo.DeleteBranchPost)
m.Group("/wiki", func() {
m.Get("/?:page", repo.Wiki)
@@ -527,10 +603,10 @@ func runWeb(ctx *cli.Context) error {
m.Get("/src/*", repo.Home)
m.Get("/raw/*", repo.SingleDownload)
m.Get("/commits/*", repo.RefCommits)
m.Get("/commit/:sha([a-z0-9]{40})$", repo.Diff)
m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.Diff)
m.Get("/forks", repo.Forks)
}, context.RepoRef())
m.Get("/commit/:sha([a-z0-9]{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]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.CompareDiff)
}, ignSignIn, context.RepoAssignment(), repo.MustBeNotBare)
@@ -570,21 +646,42 @@ 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.HttpPort = ctx.String("port")
setting.AppUrl = strings.Replace(setting.AppUrl, setting.HTTPPort, ctx.String("port"), 1)
setting.HTTPPort = ctx.String("port")
}
var err error
listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
var listenAddr string
if setting.Protocol == setting.SCHEME_UNIX_SOCKET {
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)
var err error
switch setting.Protocol {
case setting.HTTP:
case setting.SCHEME_HTTP:
err = http.ListenAndServe(listenAddr, m)
case setting.HTTPS:
case setting.SCHEME_HTTPS:
server := &http.Server{Addr: listenAddr, TLSConfig: &tls.Config{MinVersion: tls.VersionTLS10}, Handler: m}
err = server.ListenAndServeTLS(setting.CertFile, setting.KeyFile)
case setting.FCGI:
case setting.SCHEME_FCGI:
err = fcgi.Serve(nil, m)
case setting.SCHEME_UNIX_SOCKET:
os.Remove(listenAddr)
var listener *net.UnixListener
listener, err = net.ListenUnix("unix", &net.UnixAddr{listenAddr, "unix"})
if err != nil {
break // Handle error after switch
}
// FIXME: add proper implementation of signal capture on all protocols
// execute this on SIGTERM or SIGINT: listener.Close()
if err = os.Chmod(listenAddr, os.FileMode(setting.UnixSocketPermission)); err != nil {
log.Fatal(4, "Failed to set permission of unix socket: %v", err)
}
err = http.Serve(listener, m)
default:
log.Fatal(4, "Invalid protocol: %s", setting.Protocol)
}

View File

@@ -1,48 +1,56 @@
# NEVER EVER MODIFY THIS FILE
# PLEASE MAKE CHANGES ON CORRESPONDING CUSTOM CONFIG FILE
# !!! NEVER EVER MODIFY THIS FILE !!!
# !!! PLEASE MAKE CHANGES ON CORRESPONDING CUSTOM CONFIG FILE !!!
# !!! IF YOU ARE PACKAGING PROVIDER, PLEASE MAKE OWN COPY OF IT !!!
; App name that shows on every page title
APP_NAME = Gogs: Go Git Service
; Change it if you run locally
; The name of the system user that runs Gogs
RUN_USER = git
; Either "dev", "prod" or "test", default is "dev"
; Either "dev", "prod" or "test"
RUN_MODE = dev
[repository]
; Root path for storing repositories's data, default is "~/<username>/gogs-repositories"
ROOT =
; The script type server supports, sometimes could be "sh"
SCRIPT_TYPE = bash
; Default ANSI charset
; Default ANSI charset for an unrecognized charset
ANSI_CHARSET =
; Force every new repository to be private
FORCE_PRIVATE = false
; Global maximum creation limit of repository per user, -1 means no limit
MAX_CREATION_LIMIT = -1
; Patch test queue length, make it as large as possible
PULL_REQUEST_QUEUE_LENGTH = 10000
; Mirror sync queue length, increase if mirror syncing starts hanging
MIRROR_QUEUE_LENGTH = 1000
; Patch test queue length, increase if pull request patch testing starts hanging
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
; Enable ability to migrate repository by local path
ENABLE_LOCAL_PATH_MIGRATION = false
[ui]
; Number of repositories that are showed in one explore page
EXPLORE_PAGING_NUM = 20
; Number of issues that are showed in one page
ISSUE_PAGING_NUM = 10
; Number of maximum commits showed in one activity feed
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`
; Max size of files to be displayed (defaults is 8MiB)
MAX_DISPLAY_FILE_SIZE = 8388608
[repository.editor]
; List of file extensions that should have line wraps in the CodeMirror editor.
; Separate extensions with a comma. To line wrap files without extension, just put a comma
LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,
; Valid file modes that have a preview API associated with them, such as api/v1/markdown.
; Separate values by commas. Preview tab in edit mode won't show if the file extension doesn't match
PREVIEWABLE_FILE_MODES = markdown
[ui.admin]
; Number of users that are showed in one page
USER_PAGING_NUM = 50
; Number of repos that are showed in one page
REPO_PAGING_NUM = 50
; Number of notices that are showed in one page
NOTICE_PAGING_NUM = 25
; Number of organization that are showed in one page
ORG_PAGING_NUM = 50
[repository.upload]
; Enable repository file uploads.
ENABLED = true
; Path to temporarily store uploads (default path gets cleaned by Gogs in every start)
TEMP_PATH = data/tmp/uploads
; File types that are allowed to be uploaded, e.g. image/jpeg|image/png. Leave empty means allow any file type
ALLOWED_TYPES =
; Maximum size of each file in MB
FILE_MAX_SIZE = 3
; Maximum number of files per upload
MAX_FILES = 5
[markdown]
; Enable hard line break extension
@@ -50,6 +58,9 @@ ENABLE_HARD_LINE_BREAK = false
; List of custom URL-Schemes that are allowed as links when rendering Markdown
; for example git,magnet
CUSTOM_URL_SCHEMES =
; List of file extensions that should be rendered/edited as Markdown
; Separate extensions with a comma. To render files w/o extension as markdown, just put a comma
FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd
[server]
PROTOCOL = http
@@ -57,6 +68,8 @@ DOMAIN = localhost
ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
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.
; 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.
@@ -65,14 +78,18 @@ LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/
DISABLE_SSH = false
; Whether use builtin SSH server or not.
START_SSH_SERVER = false
; Domain name to be exposed in clone URL
; Domain name to be exposed in SSH clone URL
SSH_DOMAIN = %(DOMAIN)s
; Port number to be exposed in clone URL
; Port number to be exposed in SSH clone URL
SSH_PORT = 22
; Network interface builtin SSH server listens on
SSH_LISTEN_HOST = 0.0.0.0
; Port number builtin SSH server listens on
SSH_LISTEN_PORT = %(SSH_PORT)s
; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'.
SSH_ROOT_PATH =
; Choose the ciphers to support for SSH connections
SSH_SERVER_CIPHERS = aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128
; Directory to create temporary files when test publick key using ssh-keygen,
; default is system temporary directory.
SSH_KEY_TEST_PATH =
@@ -102,6 +119,10 @@ ENABLE_GZIP = false
; Landing page for non-logged users, can be "home" or "explore"
LANDING_PAGE = home
[http]
; Value for Access-Control-Allow-Origin header, default is not to present
ACCESS_CONTROL_ALLOW_ORIGIN =
; Define allowed algorithms and their minimum key length (use -1 to disable a type)
[ssh.minimum_key_sizes]
ED25519 = 256
@@ -110,7 +131,7 @@ RSA = 2048
DSA = 1024
[database]
; Either "mysql", "postgres" or "sqlite3", it's your choice
; Either "mysql", "postgres" or "sqlite3", you can connect to TiDB with MySQL protocol
DB_TYPE = mysql
HOST = 127.0.0.1:3306
NAME = gogs
@@ -122,6 +143,8 @@ SSL_MODE = disable
PATH = data/gogs.db
[admin]
; Disable regular (non-admin) users to create organizations
DISABLE_REGULAR_ORG_CREATION = false
[security]
INSTALL_LOCK = false
@@ -152,7 +175,7 @@ ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
ENABLE_CAPTCHA = true
[webhook]
; Hook task queue length
; Hook task queue length, increase if webhook shooting starts hanging
QUEUE_LENGTH = 1000
; Deliver timeout in seconds
DELIVER_TIMEOUT = 5
@@ -221,11 +244,17 @@ GC_INTERVAL_TIME = 86400
SESSION_LIFE_TIME = 86400
[picture]
; Path to store user uploaded avatars
AVATAR_UPLOAD_PATH = data/avatars
; Chinese users can choose "duoshuo"
; or a custom avatar source, like: http://cn.gravatar.com/avatar/
GRAVATAR_SOURCE = gravatar
; This value will be forced to be true in offline mode.
DISABLE_GRAVATAR = false
; Federated avatar lookup uses DNS to discover avatar associated
; with emails, see https://www.libravatar.org
; This value will be forced to be false in offline mode or Gravatar is disbaled.
ENABLE_FEDERATED_AVATAR = true
[attachment]
; Whether attachments are enabled. Defaults to `true`
@@ -245,66 +274,43 @@ MAX_FILES = 5
; For more information about the format see http://golang.org/pkg/time/#pkg-constants
FORMAT =
; General settings of loggers
[log]
ROOT_PATH =
; Either "console", "file", "conn", "smtp" or "database", default is "console"
; Can be "console" and "file", default is "console"
; Use comma to separate multiple modes, e.g. "console, file"
MODE = console
; Buffer length of channel, keep it as it is if you don't know what it is.
BUFFER_LEN = 10000
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
BUFFER_LEN = 100
; Either "Trace", "Info", "Warn", "Error", "Fatal", default is "Trace"
LEVEL = Trace
; For "console" mode only
[log.console]
; leave empty to inherit
LEVEL =
; For "file" mode only
[log.file]
; leave empty to inherit
LEVEL =
; This enables automated log rotate(switch of following options), default is true
; This enables automated log rotate (switch of following options)
LOG_ROTATE = true
; Max line number of single file, default is 1000000
MAX_LINES = 1000000
; Segment log daily
DAILY_ROTATE = true
; Max size shift of single file, default is 28 means 1 << 28, 256MB
MAX_SIZE_SHIFT = 28
; Segment log daily, default is true
DAILY_ROTATE = true
; Expired days of log file(delete after max days), default is 7
; Max line number of single file
MAX_LINES = 1000000
; Expired days of log file (delete after max days)
MAX_DAYS = 7
; For "conn" mode only
[log.conn]
; For "slack" mode only
[log.slack]
; leave empty to inherit
LEVEL =
; Reconnect host for every single message, default is false
RECONNECT_ON_MSG = false
; Try to reconnect when connection is lost, default is false
RECONNECT = false
; Either "tcp", "unix" or "udp", default is "tcp"
PROTOCOL = tcp
; Host address
ADDR =
; For "smtp" mode only
[log.smtp]
LEVEL =
; Name displayed in mail title, default is "Diagnostic message from server"
SUBJECT = Diagnostic message from server
; Mail server
HOST =
; Mailer user name and password
USER =
PASSWD =
; Receivers, can be one or more, e.g. ["1@example.com","2@example.com"]
RECEIVERS =
; For "database" mode only
[log.database]
LEVEL =
; Either "mysql" or "postgres"
DRIVER =
; Based on xorm, e.g.: root:root@localhost/gogs?charset=utf8
CONN =
; Webhook URL
URL =
[cron]
; Enable running cron tasks periodically.
@@ -314,7 +320,7 @@ RUN_AT_START = false
; Update mirrors
[cron.update_mirrors]
SCHEDULE = @every 1h
SCHEDULE = @every 10m
; Repository health check
[cron.repo_health_check]
@@ -330,11 +336,13 @@ RUN_AT_START = true
SCHEDULE = @every 24h
[git]
; Max number of lines allowed of a single file in diff view.
; Disables highlight of added and removed changes
DISABLE_DIFF_HIGHLIGHT = false
; Max number of lines allowed of a single file in diff view
MAX_GIT_DIFF_LINES = 1000
; Max number of characters of a line allowed in diff view.
; Max number of characters of a line allowed in diff view
MAX_GIT_DIFF_LINE_CHARACTERS = 500
; Max number of files shown in diff view.
; Max number of files shown in diff view
MAX_GIT_DIFF_FILES = 100
; Arguments for command 'git gc', e.g. "--aggressive --auto"
; see more on http://git-scm.com/docs/git-gc/1.7.5
@@ -346,14 +354,47 @@ MIGRATE = 600
MIRROR = 300
CLONE = 300
PULL = 300
GC = 60
[mirror]
; Default interval in hours between each check
DEFAULT_INTERVAL = 8
[api]
; Max number of items will response in a page
MAX_RESPONSE_ITEMS = 50
[ui]
; Number of repositories that are showed in one explore page
EXPLORE_PAGING_NUM = 20
; Number of issues that are showed in one page
ISSUE_PAGING_NUM = 10
; Number of maximum commits showed in one activity feed
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`
; Max size in bytes of files to be displayed (default is 8MB)
MAX_DISPLAY_FILE_SIZE = 8388608
[ui.admin]
; Number of users that are showed in one page
USER_PAGING_NUM = 50
; Number of repos that are showed in one page
REPO_PAGING_NUM = 50
; Number of notices that are showed in one page
NOTICE_PAGING_NUM = 25
; Number of organization that are showed in one page
ORG_PAGING_NUM = 50
[ui.user]
; Number of repos that are showed in one page
REPO_PAGING_NUM = 15
[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
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,gl-ES
NAMES = English,简体中文,繁體中文(香港),繁體中文(台湾),Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen,Türkçe,čeština,Српски,Svenska,한국어,Galego
; Used for datetimepicker
[i18n.datelang]
@@ -375,6 +416,10 @@ it-IT = it
fi-FI = fi
tr-TR = tr
cs-CZ = cs-CZ
sr-SP = sr
sv-SE = sv
ko-KR = ko
gl-ES = gl
; Extension mapping to highlight class
; e.g. .toml=ini
@@ -382,5 +427,7 @@ cs-CZ = cs-CZ
[other]
SHOW_FOOTER_BRANDING = false
; Show version information about gogs and go in the footer
; Show version information about Gogs and Go in the footer
SHOW_FOOTER_VERSION = true
; Show time of template execution in the footer
SHOW_FOOTER_TEMPLATE_LOAD_TIME = true

7
conf/label/Default Normal file
View File

@@ -0,0 +1,7 @@
#ee0701 bug
#cccccc duplicate
#84b6eb enhancement
#128a0c help wanted
#e6e6e6 invalid
#cc317c question
#ffffff wontfix

View File

@@ -17,6 +17,7 @@ Barış Arda Yılmaz <ardayilmazgamer AT gmail DOT com>
Camille Baronnet <gogs AT camillebaronnet DOT fr>
Christoph Kisfeld <christoph DOT kisfeld AT gmail DOT com>
Cysioland
Damaris Padieu <damizx AT hotmail DOT fr>
Daniel Speichert <daniel AT speichert DOT pl>
David Yzaguirre <dvdyzag AT gmail DOT com>
Dmitriy Nogay <me AT catwhocode DOT ga>
@@ -31,6 +32,7 @@ ilko <kontact-mr.k AT outlook DOT com">
Ilya Makarov
Jamie Mansfield <dev AT jamierocks DOT uk>
Jean THOMAS <contact AT tibounise DOT com>
Joubert RedRat <me+github AT redrat DOT com DOT br>
Juraj Bubniak <contact AT jbub DOT eu>
Lafriks <lafriks AT gmail DOT com>
Lauri Ojansivu <x AT xet7 DOT org>

View File

@@ -96,6 +96,8 @@ offline_mode=Включи офлайн режима
offline_mode_popup=Изключи CDN дори в продукционен режим, всички ресурсни файлове ще бъдат доставяни локално.
disable_gravatar=Изключи връзка с Gravatar
disable_gravatar_popup=Изключва Gravatar и външни източници, така че всички аватари трябва да са или качени от потребителите или да се ползват аватари по подразбиране.
federated_avatar_lookup=Използване на външни аватари
federated_avatar_lookup_popup=Позволява използване на външни аватари от услуги съвместими с libravatar.
disable_registration=Изключи саморегистрацията
disable_registration_popup=Изключи потребителската саморегистрация, само администратор може да създава профили.
enable_captcha=Включи Captcha
@@ -114,6 +116,7 @@ sqlite3_not_available=Вашата версия не поддържа SQLite3,
invalid_db_setting=Настройките на базата данни са некоректни: %v
invalid_repo_path=Основният път към хранилищата е невалиден: %v
run_user_not_match=Потребителският контекст на приложението не е на текущия потребител: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Неуспешно запазване на конфигурация: %v
invalid_admin_setting=Настройките на профил на администратора са невалидни: %v
install_success=Добре дошли! Радваме се, че избрахте Gogs, и Ви пожелаваме приятна работа и сърдечни поздрави!
@@ -124,6 +127,7 @@ uname_holder=Име или ел. поща
password_holder=Парола
switch_dashboard_context=Превключи контекст на таблото
my_repos=Моите хранилища
show_more_repos=Покажи още хранилища...
collaborative_repos=Съвместни хранилища
my_orgs=Моите организации
my_mirrors=Моите огледала
@@ -134,6 +138,7 @@ issues.in_your_repos=Във Вашите хранилища
[explore]
repos=Хранилища
users=Потребители
organizations=Организации
search=Търсене
[auth]
@@ -148,16 +153,17 @@ forget_password=Забравена парола?
sign_up_now=Нуждаете се от профил? Регистрирайте се сега.
confirmation_mail_sent_prompt=Ново писмо за потвърждение е изпратено до <b>%s</b>. Моля проверете пощенската си кутия в рамките на следващите %d часа, за да завършите процеса на регистрация.
active_your_account=Активиране на профил
prohibit_login=Влизане забранено
prohibit_login_desc=Вашият профил е със забрана за влизане, моля свържете се с администратора.
resent_limit_prompt=За съжаление Вие съвсем наскоро изпратихте писмо за активация. Моля изчакайте 3 минути, след което опитайте отново.
has_unconfirmed_mail=Здравейте %s, имате непотвърден адрес на ел. поща (<b>%s</b>). Ако не сте получили писмо за потвърждение или имате нужда да се изпрати ново писмо, моля щракнете бутона по-долу.
resend_mail=Щракнете тук, за да се изпрати ново писмо за потвърждение
email_not_associate=Този адрес на ел. поща не е свързан с никой профил.
send_reset_mail=Щракнете тук, за да получите (отново) писмо за нулиране на паролата
reset_password=Нулиране на паролата
invalid_code=За съжаление Вашия код за потвърждение е изтекъл или е невалиден.
reset_password_helper=Щракнете тук, за да нулирате паролата си
password_too_short=Размерът на паролата не може да бъде по-малък от 6 знака.
non_local_account=Non-local accounts cannot change passwords through Gogs.
non_local_account=Нелокални потребители не могат да сменят паролата си през Gogs.
[mail]
activate_account=Моля активирайте Вашия профил
@@ -184,6 +190,13 @@ TeamName=Име на екипа
AuthName=Име на удостоверението
AdminEmail=Ел. поща на администратора
NewBranchName=Име на нов клон
CommitSummary=Резюме на ревизия
CommitMessage=Текст на ревизия
CommitChoice=Избор на ревизия
TreeName=Път до файл
Content=Съдържание
require_error=` не може да бъде празен.`
alpha_dash_error=` трябва да e валидна буква, число или тире(-_).`
alpha_dash_dot_error=` трябва да e валидна буква, число, тире(-_) или точка.`
@@ -220,7 +233,7 @@ org_still_own_repo=Тази организация все още притежа
target_branch_not_exist=Целевият клон не съществува.
[user]
change_avatar=Change your avatar
change_avatar=Проми своя аватар
join_on=Регистриран
repositories=Хранилища
activity=Публична дейност
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=Потребителското име '%s' не е
[settings]
profile=Профил
password=Парола
avatar=Аватар
ssh_keys=SSH ключове
social=Социални профили
applications=Приложения
@@ -256,6 +270,8 @@ change_username_prompt=Този промяна ще засегне всички
continue=Продължи
cancel=Отказ
lookup_avatar_by_mail=Търсене на аватари по адрес на ел. поща
federated_avatar_lookup=Външно търсене на аватари
enable_custom_avatar=Разреши потребителски аватар
choose_new_avatar=Избор на нов аватар
update_avatar=Запази настройките на аватара
@@ -322,6 +338,10 @@ access_token_deletion=Изтрий индивидуален API ключ за д
access_token_deletion_desc=При изтриване на този индивидуален API ключ за достъп ще се премахнат всички свързани права на приложението. Желаете ли да продължите?
delete_token_success=Индивидуалният API ключ за достъп е изтрит успешно! Не забравяйте да преконфигурирате приложението също.
orgs.none=You are not a member of any organizations.
orgs.leave_title=Leave an organization
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account=Изтриване на собствения профил
delete_prompt=Тази операция ще изтрие Вашия профил завинаги и тя <strong>НЕ МОЖЕ</strong> да бъде отменена в последствие!
confirm_delete_account=Потвърди изтриването
@@ -342,7 +362,7 @@ fork_from=Разклонение от
fork_visiblity_helper=Не може да променяте видимостта на разклонено хранилище.
repo_desc=Описание
repo_lang=Програмен език
repo_lang_helper=Изберете .gitignore файлове
repo_gitignore_helper=Избор на .gitignore шаблони
license=Лиценз
license_helper=Изберете лицензионен файл
readme=Readme
@@ -350,11 +370,12 @@ readme_helper=Изберете шаблон на readme
auto_init=Инициализиране на това хранилище с избраните файлове и шаблон
create_repo=Създай хранилище
default_branch=Клон по подразбиране
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_prune=Окастряне
mirror_prune_desc=Премахва всички препратки за отдалечено проследяване, които не съществуват отдалечено
mirror_interval=Интервал на отразяване (часове)
mirror_address=Адрес на огледало
mirror_address_desc=Моля включете потребител и парола в адреса ако са нужни.
mirror_last_synced=Последна синхр.
watchers=Наблюдаващи
stargazers=Харесващи
forks=Разклонения
@@ -368,7 +389,8 @@ migrate_type=Тип мигриране
migrate_type_helper=Това хранилище ще бъде <span class="text blue">огледало</span>
migrate_repo=Мигрирай хранилище
migrate.clone_address=Адрес за клониране
migrate.clone_address_desc=Това може да е HTTP/HTTPS/GIT адрес или локален път на сървъра.
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=Недостатъчни права за импорт на локални хранилища.
migrate.invalid_local_path=Невалиден път - не съществува или не е директория.
migrate.failed=Грешка при миграция: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Създай ново хранилище чрез ком
push_exist_repo=Предай съществуващо хранилище през командния ред
repo_is_empty=Това хранилище е празно. Моля проверете по-късно пак!
code=Код
files=Files
branch=Клон
tree=ИН на ревизия
filter_branch_and_tag=Филтър по маркер или клон
@@ -409,6 +431,47 @@ file_raw=Директен файл
file_history=История
file_view_raw=Виж директен файл
file_permalink=Постоянна връзка
file_too_large=Този файл е твърде голям за да се визуализира
video_not_supported_in_browser=Вашият браузър не поддържа HTML5 видео тагове.
editor.new_file=Нов файл
editor.upload_file=Качи файл
editor.edit_file=Редактирай файл
editor.preview_changes=Преглед на промени
editor.cannot_edit_non_text_files=Невъзможна редакция на нетекстови файлове
editor.edit_this_file=Редактирай този файл
editor.must_be_on_a_branch=Трябва да сте избрали клон за да предложите промени в този файл
editor.fork_before_edit=Първо трябва да разклоните хранилището преди да редактирате файл
editor.delete_this_file=Изтрий този файл
editor.must_have_write_access=Трябва да имате права за писане за да предложите промени в този файл
editor.file_delete_success=Файл '%s' е изтрит успешно!
editor.name_your_file=Име на файл...
editor.filename_help=За да добавите директория, въведете името ѝ и натиснете /. За да я премахнете, позиционирайте се в началото на полето и натиснете BackSpace.
editor.or=или
editor.cancel_lower=отказ
editor.commit_changes=Промени в ревизия
editor.add_tmpl=Добави '%s/<filename>'
editor.add=Добави '%s'
editor.update=Модифицирай '%s'
editor.delete=Изтрий '%s'
editor.commit_message_desc=Добавяне на опционално разширено описание...
editor.commit_directly_to_this_branch=Запази ревизия директно в клон <strong class="branch-name">%s</strong>.
editor.create_new_branch=Създай <strong>нов клон</strong> от тази ревизия и изпрати заявки за сливане.
editor.new_branch_name_desc=Име на нов клон...
editor.cancel=Отказ
editor.filename_cannot_be_empty=Името не може да бъде празно.
editor.branch_already_exists=Клон '%s' вече съществува в това хранилище.
editor.directory_is_a_file=Частта '%s' в пътя е файл, не директория в това хранилище.
editor.file_is_a_symlink=Файл "%s" е символна връзка, която не може да се модифицира от редактора.
editor.filename_is_a_directory=Име '%s' вече съществува като директория в това хранилище.
editor.file_editing_no_longer_exists=Файл '%s' който редактирате вече не съществува в това хранилище.
editor.file_changed_while_editing=Съдържанието на файла е било променено докато правихте редакциите. <a target="_blank" href="%s">Щракнете тук</a> за да прегледате какво е променено или <strong>натиснете Запис на ревизия</strong> отново за да презапишете чуждите промени.
editor.file_already_exists=Файл с име '%s' вече съществува в това хранилище.
editor.no_changes_to_show=Няма промени.
editor.fail_to_update_file=Невъзможно модифициране/създаване на файл '%s' заради грешка: %v
editor.add_subdir=Добави поддиректория...
editor.unable_to_upload_files=Невъзможно качване на файлове в '%s' заради грешка: %v
editor.upload_files_to_dir=Качи файлове в '%s'
commits.commits=Ревизии
commits.search=Търсене в ревизии
@@ -435,6 +498,11 @@ issues.create=Създай задача
issues.new_label=Нов етикет
issues.new_label_placeholder=Име на етикета...
issues.create_label=Създай етикет
issues.label_templates.title=Зареждане на предварително зададен набор от етикети
issues.label_templates.info=Липсват етикети все още. Можете да щракнете върху "Нов етикет" по-горе, за да създадете нов или да изберете предварително зададени набори от по-долу.
issues.label_templates.helper=Изберете набор етикети
issues.label_templates.use=Използвай този набор етикети
issues.label_templates.fail_to_load_file=Неуспешно зареждане на шаблон с етикети '%s': %v
issues.open_tab=%d отворени
issues.close_tab=%d затворени
issues.filter_label=Етикет
@@ -462,7 +530,8 @@ issues.next=Следваща
issues.open_title=Отворени
issues.closed_title=Затворени
issues.num_comments=%d коментара
issues.commented_at=`коментира <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`коментира <a href="#%s">%s</a>`
issues.delete_comment_confirm=Желаете ли да изтриете този коментар?
issues.no_content=Все още няма съдържание.
issues.close_issue=Затвори
issues.close_comment_issue=Kоментирай и затвори
@@ -475,8 +544,7 @@ issues.commit_ref_at=`посочи тази задача от ревизия <a
issues.poster=Участник
issues.collaborator=Сътрудник
issues.owner=Притежател
issues.sign_up_for_free=Регистрирай се безплатно
issues.sign_in_require_desc=за да се включите в този разговор. Вече имате профил? <a href="%s">Влезте, за да коментирате</a>
issues.sign_in_require_desc=<a href="%s">Впишете се</a> за да се присъедините към разговора.
issues.edit=Редакция
issues.cancel=Отказ
issues.save=Запис
@@ -491,6 +559,8 @@ issues.label_deletion=Изтрий етикет
issues.label_deletion_desc=При изтриване на този етикет ще се премахне информацията за него във всички свързани задачи. Желаете ли да продължите?
issues.label_deletion_success=Етикетът е изтрит успешно!
issues.num_participants=%d участника
issues.attachment.open_tab=`Щракнете за да прегледате "%s" в нов раздел`
issues.attachment.download=`Щракнете за да изтеглите "%s"`
pulls.new=Нова заявка за сливане
pulls.compare_changes=Сравни промените
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Не може да се извърши обедин
pulls.cannot_auto_merge_helper=Моля, използвайте инструменти на командния ред за да разрешите конфликтите.
pulls.merge_pull_request=Обедини заявка за сливане
pulls.open_unmerged_pull_exists=`Невъзможно повторно отваряне, защото вече съществува заявка за сливане (#%d) от същото хранилище със същата информация за обединяване, която чака да бъде извършена`
pulls.delete_branch=Изтрий клон
pulls.delete_branch_has_new_commits=Клонът не може да бъде изтрит, защото има ревизии след последното обединяване.
milestones.new=Нов етап
milestones.open_tab=%d отворени
@@ -563,27 +635,34 @@ wiki.last_updated=Последна модификация на %s
settings=Настройки
settings.options=Опции
settings.collaboration=Сътрудничество
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.collaboration.admin=За администрация
settings.collaboration.write=За писане
settings.collaboration.read=За четене
settings.collaboration.undefined=Недефинирано
settings.hooks=Уеб-куки
settings.githooks=Git куки
settings.basic_settings=Основни настройки
settings.mirror_settings=Настройки на огледало
settings.sync_mirror=Синхр. сега
settings.mirror_sync_in_progress=Синхронизация на огледалото е в ход, моля обновете страницата след минута.
settings.site=Официален сайт
settings.update_settings=Запази настройките
settings.change_reponame_prompt=Тази промяна ще засегне връзките, които се отнасят до това хранилището.
settings.advanced_settings=Разширени настройки
settings.wiki_desc=Включва уики за да може потребителите да създават документи
settings.wiki_desc=Включи система за уики
settings.use_internal_wiki=Използвай вградено уики
settings.use_external_wiki=Използвай външно уики
settings.external_wiki_url=URL адрес на външно уики
settings.external_wiki_url_desc=Посетителите ще бъдат пренасочени към този URL адрес от връзката за раздел уики.
settings.issues_desc=Включва вградена система за проследяване на задачи
settings.issues_desc=Включи система за проследяване на задачи
settings.use_internal_issue_tracker=Изполвай вградена система за проследяване на задачи
settings.use_external_issue_tracker=Използвай външна система за проследяване на задачи
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Формат на URL адрес на външна система за проследяване на задачи
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style=Стил на именуване на външна система за проследяване на задачи:
settings.tracker_issue_style.numeric=Цифров
settings.tracker_issue_style.alphanumeric=Символен
settings.tracker_url_format_desc=Можете да използвате текстови маркери <code>{user} {repo} {index}</code> за потребителско име, име на хранилище и индекс на задача съответно.
settings.pulls_desc=Включва заявки за сливане за да може да се приемат външни доработки
settings.danger_zone=Опасна зона
@@ -606,7 +685,7 @@ settings.delete=Изтрий това хранилище
settings.delete_desc=След като изтриете хранилището, няма връщане назад. Моля, бъдете сигурни.
settings.delete_notices_1=- Тази операция <strong>НЕ МОЖЕ</strong> да бъде отменена в последствие.
settings.delete_notices_2=- Тази операция ще изтрие всичко от това хранилище, включително Git данни, задачи, коментари и достъпа на сътрудници.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.delete_notices_fork_1=- Всички разклонения ще станат независими след изтриването.
settings.deletion_success=Хранилището е изтрито успешно!
settings.update_settings_success=Настройките на хранилището са запазени успешно.
settings.transfer_owner=Нов притежател
@@ -653,6 +732,8 @@ settings.event_send_everything=При <strong>всички</strong> събити
settings.event_choose=Нека избера от какво имам нужда.
settings.event_create=Създаване
settings.event_create_desc=Създаване на клон или маркер
settings.event_pull_request=Заявка за сливане
settings.event_pull_request_desc=Заявка за сливане е отворена, затворена, отворена повторно, редактирана, възложена, отменена, при модифициран етикет, при премахнат етикет или е синхронизирана.
settings.event_push=Предаване
settings.event_push_desc=Git предаване към хранилището
settings.active=Активна
@@ -690,8 +771,8 @@ diff.show_unified_view=Обединен изглед
diff.stats_desc=променени са <strong>%d файла</strong>, в които са <strong>добавени %d</strong> реда и са <strong>изтрити %d</strong> реда
diff.bin=BIN
diff.view_file=Целия файл
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
diff.file_suppressed=Файловите разлики са ограничени, защото са твърде много
diff.too_many_files=Някои файлове не бяха показани, защото твърде много файлове са промени
release.releases=Версии
release.new_release=Нова версия
@@ -722,6 +803,7 @@ release.deletion=Изтрий версията
release.deletion_desc=При изтриване на тази версия ще се премахне и съответния Git маркер. Желаете ли да продължите?
release.deletion_success=Версията беше изтрита успешно!
release.tag_name_already_exist=Версия с това име на маркер вече съществува.
release.tag_name_invalid=Името на етикета е невалидно.
release.downloads=Изтегляния
[org]
@@ -889,6 +971,7 @@ users.edit_account=Редактирай профил
users.max_repo_creation=Макс. брой хранилища
users.max_repo_creation_desc=(Задайте -1 за да се използва глобалния лимит)
users.is_activated=Този профил е активиран
users.prohibit_login=Този профил има забрана за влизане
users.is_admin=Този профил има административни права
users.allow_git_hook=Този профил има разрешение да създава Git куки
users.allow_import_local=Този профил има права за импорт на локални хранилища
@@ -919,7 +1002,7 @@ auths.enabled=Активно
auths.updated=Последна модификация
auths.auth_type=Тип на удостоверяване
auths.auth_name=Име на удостоверяване
auths.security_protocol=Security Protocol
auths.security_protocol=Протокол за защита
auths.domain=Домейн
auths.host=Сървър
auths.port=Порт
@@ -957,6 +1040,7 @@ auths.delete_auth_title=Изтрий удостоверяването
auths.delete_auth_desc=Това удостоверяване ще бъде изтрито. Желаете ли да продължите?
auths.still_in_used=Това удостоверяване все още се използва от някои потребители. Моля изтрийте ги или ги конвертирайте до друг тип на влизане първо.
auths.deletion_success=Удостоверяването е изтрито успешно!
auths.login_source_exist=Източник за валидация на потребители "%s" вече съществува.
config.server_config=Сървърни настройки
config.app_name=Име на приложението
@@ -967,6 +1051,7 @@ config.offline_mode=Офлайн режим
config.disable_router_log=Изключи журнал на маршрутизатора
config.run_user=Потребителски контекст
config.run_mode=Режим на изпълнение
config.git_version=Git Version
config.repo_root_path=Основен път към хранилища
config.static_file_root_path=Път към статични файлове
config.log_file_root_path=Път към журнал
@@ -994,6 +1079,7 @@ config.db_ssl_mode=SSL режим
config.db_ssl_mode_helper=(само за postgres)
config.db_path=Път
config.db_path_helper=(за "sqlite3" и "tidb")
config.service_config=Настройка на услугата
config.register_email_confirm=Изисквай потвърждение на адреси на ел. поща
config.disable_register=Изключи нови регистрации
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Изключи проверка минимален
config.enable_captcha=Включи Captcha
config.active_code_lives=Кодове за активиране
config.reset_password_code_lives=Кодове за изчистване на парола
config.webhook_config=Конфигурация на уеб-куки
config.queue_length=Дължина на опашка
config.deliver_timeout=Време за отказ при изпращане
config.skip_tls_verify=Пропусни проверка на TLS
config.mailer_config=Конфигурация на мейлър
config.mailer_enabled=Активен
config.mailer_disable_helo=Изключи HELO
@@ -1017,12 +1105,15 @@ config.mailer_user=Потребител
config.send_test_mail=Изпрати тестово писмо
config.test_mail_failed=Невъзможно изпращане на тестово писмо до '%s': %v
config.test_mail_sent=Тестово писмо беше изпратено до '%s'.
config.oauth_config=OAuth конфигурация
config.oauth_enabled=Активна
config.cache_config=Конфигурация на кеша
config.cache_adapter=Кеш адаптер
config.cache_interval=Кеш интервал
config.cache_conn=Кеш на връзката
config.session_config=Конфигурация на сесии
config.session_provider=Доставчик на сесии
config.provider_config=Конфигурация на доставчик
@@ -1032,9 +1123,24 @@ config.gc_interval_time=GC през интервал
config.session_life_time=Период на валидност на сесиите
config.https_only=HTTPS само
config.cookie_life_time=Период на валидност на бисквитките
config.picture_config=Конфигурация на изображения
config.picture_service=Услуги за снимки
config.disable_gravatar=Изключи Gravatar
config.enable_federated_avatar=Включи външни аватари
config.git_config=Конфигурация на git
config.git_disable_diff_highlight=Забрани оцветяване на синтаксис при преглед на разлики
config.git_max_diff_lines=Максимален брой различни редове (за файл)
config.git_max_diff_line_characters=Максимален брой различни символи (на ред)
config.git_max_diff_files=Максимален брой променени файлове (при показване)
config.git_gc_args=Аргументи на GC
config.git_migrate_timeout=Време за отказ при миграция
config.git_mirror_timeout=Време за отказ при синхр. на огледало
config.git_clone_timeout=Време за отказ при клониране
config.git_pull_timeout=Време за отказ при сливане
config.git_gc_timeout=Време за отказ при GC
config.log_config=Конфигурация на журнал
config.log_mode=Режим на журнал

View File

@@ -13,7 +13,7 @@ version=Verze
page=Strana
template=Šablona
language=Jazyk
create_new=Vytořit...
create_new=Vytvořit...
user_profile_and_more=Uživatelský profil a další
signed_in_as=Přihlášen jako
@@ -96,6 +96,8 @@ offline_mode=Zapnout režim offline
offline_mode_popup=Vypnout síť doručování obsahu (CDN) i v produkčním režimu, vše bude obslouženo místně.
disable_gravatar=Vypnout službu Gravatar
disable_gravatar_popup=Vypnout službu Gravatar a ostatní zdroje. Všechny ikony uživatelů budou nahrány uživateli nebo výchozí.
federated_avatar_lookup=Povolit vyhledání avatarů z veřejných zdrojů
federated_avatar_lookup_popup=Povolte vyhledání avatarů z veřejných zdrojů pro využití služeb založených na libravatar.
disable_registration=Vypnout možnost se zaregistrovat
disable_registration_popup=Vypnout možnost registrace, pouze správce může vytvořit účty.
enable_captcha=Povolit službu CAPTCHA
@@ -114,6 +116,7 @@ sqlite3_not_available=Vaše verze vydání Gogs nepodporuje SQLite3, prosíme st
invalid_db_setting=Nastavení databáze není správné: %v
invalid_repo_path=Kořenový adresář repositáře není správný: %v
run_user_not_match=Uživatel pro spuštění není aktuální uživatel: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Uložení konfigurace se nezdařilo: %v
invalid_admin_setting=Nastavení účtu správce není správné: %v
install_success=Vítejte! Jsme rádi, že jste si vybrali Gogs. Bavte se a opatrujte se.
@@ -124,6 +127,7 @@ uname_holder=Uživatelské jméno nebo e-mailová adresa
password_holder=Heslo
switch_dashboard_context=Přepnout kontext přehledu
my_repos=Mé repositáře
show_more_repos=Zobrazit více repositářů...
collaborative_repos=Společné repositáře
my_orgs=Mé organizace
my_mirrors=Má zrcadla
@@ -134,6 +138,7 @@ issues.in_your_repos=Ve vašich repositářích
[explore]
repos=Repositáře
users=Uživatelé
organizations=Organizace
search=Vyhledat
[auth]
@@ -148,16 +153,17 @@ forget_password=Zapomněli jste heslo?
sign_up_now=Potřebujete účet? Zaregistrujte se.
confirmation_mail_sent_prompt=Nový potvrzovací e-mail byl zaslán na <b>%s</b>, prosíme, zkontrolujte si vaši doručenou poštu během následující %d hodin pro dokončení registračního procesu.
active_your_account=Aktivujte si váš účet
prohibit_login=Přihlášení zakázáno
prohibit_login_desc=Vašemu účtu je zakázáno se přihlásit, kontaktujte prosím správce webu.
resent_limit_prompt=Omlouváme se, ale před chvílí jste požádal o aktivační e-mail. Prosíme, počkejte 3 minuty a pak to zkuste znovu.
has_unconfirmed_mail=Zdravím, %s, máte nepotvrzenou e-mailovou adresu (<b>%s</b>). Pokud jste nedostali e-mail pro potvrzení nebo potřebujete zaslat nový, klikněte prosím na tlačítku níže.
resend_mail=Klikněte zde pro odeslání aktivačního e-mailu
email_not_associate=Tato e-mailová adresa není spojena s žádným účtem.
send_reset_mail=Klikněte zde pro znovuposlání e-mailu pro změnu vašeho hesla
reset_password=Obnova vašeho hesla
invalid_code=Omlouváme se, ale kód potvrzení vašeho účtu vypršel nebo není správný.
reset_password_helper=Klikněte zde pro obnovu vašeho hesla
password_too_short=Délka hesla musí být minimálně 6 znaků.
non_local_account=Non-local accounts cannot change passwords through Gogs.
non_local_account=Externí účty nemohou měnit hesla přes Gogs.
[mail]
activate_account=Prosíme, aktivujte si váš účet
@@ -184,6 +190,13 @@ TeamName=Název týmu
AuthName=Název ověření
AdminEmail=E-mailová adresa správce
NewBranchName=Název nové větve
CommitSummary=Shrnutí revize
CommitMessage=Zpráva revize
CommitChoice=Výběr revize
TreeName=Cesta k souboru
Content=Obsah
require_error=` nemůže být prázdný.`
alpha_dash_error=` musí být pouze písmena, číslice či znaky - a _ .`
alpha_dash_dot_error=` musí být pouze písmena, číslice, tečka či znaky - a _ .`
@@ -220,7 +233,7 @@ org_still_own_repo=Tato organizace stále vlastní repositáře, musíte je nejd
target_branch_not_exist=Cílová větev neexistuje.
[user]
change_avatar=Change your avatar
change_avatar=Změnit vaši uživatelskou ikonu
join_on=Připojil se dne
repositories=Repositáře
activity=Veřejná aktivita
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=Vzor uživatelského jména '%s' není povolen.
[settings]
profile=Profil
password=Heslo
avatar=Uživatelská ikona
ssh_keys=Klíče SSH
social=Sociální účty
applications=Aplikace
@@ -256,6 +270,8 @@ change_username_prompt=Tato změna ovlivní vztah odkazů k vašemu účtu.
continue=Pokračovat
cancel=Zrušit
lookup_avatar_by_mail=Vyhledávat uživatelskou ikonu podle emailu
federated_avatar_lookup=Vyhledání Avatarů ve veřejných zdrojích
enable_custom_avatar=Povolit uživatelskou ikonu uživatele
choose_new_avatar=Vybrat novou ikonu uživatele
update_avatar=Aktualizovat nastavení ikony uživatele
@@ -322,6 +338,10 @@ access_token_deletion=Smazání osobní přístupové poukázky
access_token_deletion_desc=Smazáním této osobní přístupové poukázky odstraní všechen návazný přístup aplikace. Chcete pokračovat?
delete_token_success=Osobní přístupová poukázka byla úspěšně odstraněna! Nezapomeňte také aktualizovat vaši aplikaci.
orgs.none=You are not a member of any organizations.
orgs.leave_title=Leave an organization
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account=Smazat váš účet
delete_prompt=Tato operace permanentně smaže váš účet a tato změna <strong>nemůže</strong> být vrácena!
confirm_delete_account=Potvrdit smazání
@@ -342,7 +362,7 @@ fork_from=Rozštěpit z
fork_visiblity_helper=Nemůžete změnit viditelnost repositáře rozštěpení.
repo_desc=Popis
repo_lang=Jazyk
repo_lang_helper=Nastavit soubory .gitignore
repo_gitignore_helper=Vyberte šablony .gitignore
license=Licence
license_helper=Vyberte licenční soubor
readme=Soubor README
@@ -350,11 +370,12 @@ readme_helper=Vyberte šablonu souboru README
auto_init=Inicializovat tento repositář s vybranými soubory a šablonou
create_repo=Vytvořit repositář
default_branch=Výchozí větev
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_prune=Vyčistit
mirror_prune_desc=Odstranit vzdálené odkazy, které již ve vzdáleném repozitáři neexistují
mirror_interval=Odstup zrcadlení (hodina)
mirror_address=Adresa zrcadla
mirror_address_desc=Prosím, přidejte do adresy potřebné přihlašovací údaje.
mirror_last_synced=Naposledy synchronizováno
watchers=Sledující
stargazers=Sledující
forks=Rozštěpení
@@ -368,7 +389,8 @@ migrate_type=Typ migrace
migrate_type_helper=Tento repositář bude <span class="text blue">zrcadlem</span>
migrate_repo=Přenést repositář
migrate.clone_address=Naklonovat adresu
migrate.clone_address_desc=Tím může být HTTP/HTTPS/GIT URL nebo cesta k lokálnímu serveru.
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=Není dovoleno importovat místní repositáře.
migrate.invalid_local_path=Neplatná místní cesta, buď neexistuje nebo není adresářem.
migrate.failed=Přenesení selhalo: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Vytvořit nový repositář v příkazové řádce
push_exist_repo=Nahrát existující repositář z příkazové řádky
repo_is_empty=Tento repositář je prázdný, prosíme, vraťte se brzo zpátky!
code=Zdrojový kód
files=Files
branch=Větev
tree=Strom
filter_branch_and_tag=Filtr pro větev nebo značku
@@ -409,6 +431,47 @@ file_raw=Surový
file_history=Historie
file_view_raw=Zobrazit v surovém stavu
file_permalink=Trvalý odkaz
file_too_large=Tento soubor je příliš velký pro zobrazení
video_not_supported_in_browser=Váš prohlížeč nepodporuje tag pro HTML5 video.
editor.new_file=Nový soubor
editor.upload_file=Nahrát soubor
editor.edit_file=Upravit soubor
editor.preview_changes=Náhled změn
editor.cannot_edit_non_text_files=Netextové soubory není možné upravovat
editor.edit_this_file=Upravit tento soubor
editor.must_be_on_a_branch=Musíte mít zvolenu větev pro úpravu či návrh změn tohoto souboru
editor.fork_before_edit=Musíte provést rozvětvení repositáře před úpravou souboru
editor.delete_this_file=Odstranit tento soubor
editor.must_have_write_access=Musíte mít přístup pro zápis pro dělání či navrhování změn tohoto souboru
editor.file_delete_success=Soubor '%s' byl úspěšně odstraněn!
editor.name_your_file=Pojmenujte váš soubor...
editor.filename_help=Pro vložení adresáře prostě napište jméno a přidejte /. K odstranění adresáře běžte na začátek pole a stiskněte backspace.
editor.or=nebo
editor.cancel_lower=zrušit
editor.commit_changes=Uložit změny revize
editor.add_tmpl=Přidat '%s/<nazev_souboru>'
editor.add=Přidat '%s'
editor.update=Aktualizovat "%s"
editor.delete=Smazat '%s'
editor.commit_message_desc=Přidat dobrovolný rozšířený popis...
editor.commit_directly_to_this_branch=Uložte změny revize přímo do větve <strong class="branch-name">%s</strong>.
editor.create_new_branch=Vytvořit <strong>novou větev</strong> pro tuto revizi a spustit požadavek na stažení.
editor.new_branch_name_desc=Nový název větve...
editor.cancel=Zrušit
editor.filename_cannot_be_empty=Název souboru nemůže být prázdný.
editor.branch_already_exists=Repositář větev '%s' již obsahuje.
editor.directory_is_a_file=Položka '%s' v nadřazené cestě je v tomto repozitáři soubor, ne adresář.
editor.file_is_a_symlink=Soubor '%s' je symbolický odkaz a nemůže být změněn pomocí webového editoru.
editor.filename_is_a_directory=Jméno souboru '%s' koliduje v tomto repozitáři se jménem adresáře.
editor.file_editing_no_longer_exists=Soubor '%s', který upravujete, již neexistuje v tomto repozitáři.
editor.file_changed_while_editing=Obsah souboru se změnil od začátku úprav. <a target="_blank" href="%s"> Klepnutím sem</a> zobrazíte, co se změnilo, nebo <strong>stiskněte potvrdit znovu</strong> pro přepsání změn.
editor.file_already_exists=Soubor '%s' již existuje v tomto repozitáři.
editor.no_changes_to_show=Žádné změny k zobrazení.
editor.fail_to_update_file=Vytvoření nebo změna souboru '%s' skončilo chybou: %v
editor.add_subdir=Přidat podadresář...
editor.unable_to_upload_files=Nepodařilo se nahrát soubor '%s'. Chyba: %v
editor.upload_files_to_dir=Nahrát soubory do '%s'
commits.commits=Revize
commits.search=Hledání revizí
@@ -435,6 +498,11 @@ issues.create=Vytvořit úkol
issues.new_label=Nový štítek
issues.new_label_placeholder=Název štítku...
issues.create_label=Vytvořit štítek
issues.label_templates.title=Nahrát předdefinovanou sadu značek
issues.label_templates.info=Nejsou zadány žádné značky. Pro vytvoření nové klikněte na tlačítko Nová značka nebo použijte předdefinovanou sadu.
issues.label_templates.helper=Vyberte sadu značek
issues.label_templates.use=Použít tuto sadu značek
issues.label_templates.fail_to_load_file=Nepodařilo se nahrát soubor šablony značek '%s': %v
issues.open_tab=%d otevřených
issues.close_tab=%d zavřených
issues.filter_label=Štítek
@@ -462,7 +530,8 @@ issues.next=Další
issues.open_title=otevřený
issues.closed_title=zavřený
issues.num_comments=%d komentářů
issues.commented_at=`komentoval <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`okomentoval <a href="#%s">%s</a>`
issues.delete_comment_confirm=Jste si jist, že chcete smazat tento komentář?
issues.no_content=Není zde žádný obsah.
issues.close_issue=Zavřít
issues.close_comment_issue=Okomentovat a zavřít
@@ -475,8 +544,7 @@ issues.commit_ref_at=`odkázal na tento úkol z revize <a id="%[1]s" href="#%[1]
issues.poster=Autor
issues.collaborator=Spolupracovník
issues.owner=Vlastník
issues.sign_up_for_free=Zaregistrujte se zdarma
issues.sign_in_require_desc=pro zapojení do konverzace. Již máte účet? <a href="%s">Přihlaste se</a>
issues.sign_in_require_desc=<a href="%s">Přihlašte se</a> pro zapojení do konverzace.
issues.edit=Upravit
issues.cancel=Zrušit
issues.save=Uložit
@@ -491,6 +559,8 @@ issues.label_deletion=Smazání štítku
issues.label_deletion_desc=Smazání tohoto štítku jej smaže také ze všech návazných úkolech. Chcete pokračovat?
issues.label_deletion_success=Štítek byl úspěšně smazán!
issues.num_participants=%d účastníků
issues.attachment.open_tab=`Klikněte pro zobrazení "%s" v nové záložce`
issues.attachment.download=`Klikněte pro stažení "%s"`
pulls.new=Nový požadavek na natažení
pulls.compare_changes=Porovnat změny
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Tento požadavek na natažení nemůže být automa
pulls.cannot_auto_merge_helper=Prosíme proveďte sloučení ručně, aby byly vyřešeny konflitky.
pulls.merge_pull_request=Sloučit požadavek na stažení
pulls.open_unmerged_pull_exists=`Nemůžete znovuotevřít požadavek na stažení, neboť požadavek na stažení ze stejného repositáře se stejnými informacemi pro sloučení již existuje (#%d).`
pulls.delete_branch=Smazat větev
pulls.delete_branch_has_new_commits=Větev nemůže být smazána, neboť po sloučení jsou v ní nové revize.
milestones.new=Nový milník
milestones.open_tab=%d otevřených
@@ -563,27 +635,34 @@ wiki.last_updated=Naposledy aktualizováno: %s
settings=Nastavení
settings.options=Možnosti
settings.collaboration=Spolupráce
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.collaboration.admin=Správce
settings.collaboration.write=Zápis
settings.collaboration.read=Čtení
settings.collaboration.undefined=Neurčeno
settings.hooks=Webové háčky
settings.githooks=Háčky Gitu
settings.basic_settings=Základní nastavení
settings.mirror_settings=Nastavení zrcadla
settings.sync_mirror=Provést synchronizaci
settings.mirror_sync_in_progress=Synchronizace zrcadel probíhá, prosím načtěte znovu stránku přibližně za minutu.
settings.site=Oficiální stránky
settings.update_settings=Změnit nastavení
settings.change_reponame_prompt=Tato změna ovlivní vztah odkazů k repositáři.
settings.advanced_settings=Pokročilá nastavení
settings.wiki_desc=Povolit Wiki, aby lidé mohli psát dokumenty
settings.wiki_desc=Povolit systém Wiki
settings.use_internal_wiki=Použít vestavěný systém Wiki
settings.use_external_wiki=Používat externí Wiki
settings.external_wiki_url=URL externí Wiki
settings.external_wiki_url_desc=Návštěvníci budou při kliknutí na záložku přesměrování na tuto URL.
settings.issues_desc=Povolit vestavěný jednoduchý systém úkolů
settings.issues_desc=Povolit systém úkolů
settings.use_internal_issue_tracker=Povolit věstavěný odlehčený systém úkolů
settings.use_external_issue_tracker=Použít externí systém úkolů
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Formát URL externího systému úkolů
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style=Styl pojmenování externího systému úkolů:
settings.tracker_issue_style.numeric=Číselný
settings.tracker_issue_style.alphanumeric=Alfanumeric
settings.tracker_url_format_desc=Můžete použít zástupné výrazy <code>{user} {repo} {index}</code> pro uživatelské jméno, název repositáře a index úkolu.
settings.pulls_desc=Povolit požadavky na stažení, aby veřejné příspěvky mohly být akceptovány
settings.danger_zone=Nebezpečná zóna
@@ -606,7 +685,7 @@ settings.delete=Smazat tento repositář
settings.delete_desc=Jakmile smažete repositář, není možné se vrátit. Buďte si, prosím, jist.
settings.delete_notices_1=- Tuto operaci <strong>nelze</strong> zvrátit.
settings.delete_notices_2=Tato operace permanentně smaže vše v tomto repositáři, včetně dat Gitu, úkolů, komentářů a přístupu spolupracovníků.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.delete_notices_fork_1=- Po smazání se všechny forky se stanou nezávislé.
settings.deletion_success=Repositář byl úspěšně smazán!
settings.update_settings_success=Možnosti repositáře byly úspěšně změněny.
settings.transfer_owner=Nový vlastník
@@ -653,6 +732,8 @@ settings.event_send_everything=Potřebuji <strong>vše</strong>.
settings.event_choose=Nech mne vybrat, co potřebuji.
settings.event_create=Vytvořit
settings.event_create_desc=Větev nebo značka byla vytvořena
settings.event_pull_request=Požadavek na stažení
settings.event_pull_request_desc=Pull request byl otevřen, uzavřen, znovu-otevřen, upraven, přiřazen, zrušeno přiřazení, popis upraven, smazán nebo synchronizován.
settings.event_push=Nahrát
settings.event_push_desc=Nahrání pomocí Gitu do repositáře
settings.active=Aktivní
@@ -690,8 +771,8 @@ diff.show_unified_view=Jednotný pohled
diff.stats_desc=<strong> %d změnil soubory</strong>, kde provedl <strong>%d přidání</strong> a <strong>%d odebrání</strong>
diff.bin=binární
diff.view_file=Zobrazit soubor
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
diff.file_suppressed=Diff nebyl zobrazen, protože je příliš veliký
diff.too_many_files=Některé soubory nejsou zobrazny, neboť je v této revizi změněno mnoho souborů
release.releases=Vydání
release.new_release=Nové vydání
@@ -722,6 +803,7 @@ release.deletion=Smazání vydání
release.deletion_desc=Smazáním tohoto vydání se také smaže odpovídající značka. Chcete pokračovat?
release.deletion_success=Vydání bylo úspěšně smazáno!
release.tag_name_already_exist=Vydání s touto značkou již existuje.
release.tag_name_invalid=Název štítku není platný.
release.downloads=Soubory ke stažení
[org]
@@ -790,7 +872,7 @@ teams.owners_permission_desc=Vlastníci mají plný přístup do <strong>všech
teams.members=Členové týmu
teams.update_settings=Upravit nastavení
teams.delete_team=Smazat tento tým
teams.add_team_member=Přidát člena týmu
teams.add_team_member=Přidat člena týmu
teams.delete_team_title=Smazání týmu
teams.delete_team_desc=Jelikož bude tento tým smazán, jeho členové mohou ztratit přístup do některých repositářů. Chcete pokračovat?
teams.delete_team_success=Daný tým byl úspěšně smazán.
@@ -889,6 +971,7 @@ users.edit_account=Upravit účet
users.max_repo_creation=Limit počtu vytvořených repositářů
users.max_repo_creation_desc=(Nastavte na -1 pro použití výchozího systémového limitu)
users.is_activated=Tento účet je aktivován
users.prohibit_login=Tento účet má zakázáno přihlášení
users.is_admin=Tento účet je správce
users.allow_git_hook=Tento účet má právo vytváře háčky Gitu
users.allow_import_local=Tento účet má právo importovat místní repositáře
@@ -919,7 +1002,7 @@ auths.enabled=Povolený
auths.updated=Upravený
auths.auth_type=Typ ověření
auths.auth_name=Název ověření
auths.security_protocol=Security Protocol
auths.security_protocol=Protokol zabezpečení
auths.domain=Doména
auths.host=Server
auths.port=Port
@@ -957,6 +1040,7 @@ auths.delete_auth_title=Smazání způsobu ověřování
auths.delete_auth_desc=Tento způsob ověřování bude smazán, chcete pokračovat?
auths.still_in_used=Tento způsob ověřování je stále používán některými uživateli. Prosím, nejdříve změňte u těchto uživatelů typ ověřování na jiný.
auths.deletion_success=Způsob ověřování byl úspěšně smazán!
auths.login_source_exist=Zdroj přihlášení '%s' již existuje.
config.server_config=Nastavení serveru
config.app_name=Název aplikace
@@ -967,6 +1051,7 @@ config.offline_mode=Režim off-line
config.disable_router_log=Vypnout log směrovače
config.run_user=Účet pro spouštění
config.run_mode=Režim spouštění
config.git_version=Git Version
config.repo_root_path=Kořenový adresář repositářů
config.static_file_root_path=Kořenový adresář statického souboru
config.log_file_root_path=Kořenový adresář souboru logu
@@ -994,6 +1079,7 @@ config.db_ssl_mode=Režim SSL
config.db_ssl_mode_helper=(pouze pro 'postgres')
config.db_path=Cesta
config.db_path_helper=(pro "sqlite3" a "tidb")
config.service_config=Nastavení služby
config.register_email_confirm=Vyžadovat potvrzení e-mailem
config.disable_register=Vypnout registraci
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Vypnout kontrolu minimální velikosti klíčů
config.enable_captcha=Povolit službu CAPTCHA
config.active_code_lives=Doba života aktivního kódu
config.reset_password_code_lives=Lhůta kódu pro obnovu hesla
config.webhook_config=Nastavení webových háčků
config.queue_length=Délka fronty
config.deliver_timeout=Časový limit doručení
config.skip_tls_verify=Přeskočit ověření TLS
config.mailer_config=Nastavení odesílání e-mailů
config.mailer_enabled=Zapnutý
config.mailer_disable_helo=Zakázat HELO
@@ -1017,12 +1105,15 @@ config.mailer_user=Uživatel
config.send_test_mail=Odeslat zkušební E-mail
config.test_mail_failed=Odeslání testovacího e-mailu na '%s' selhalo: %v
config.test_mail_sent=Zkušební e-mail byl odeslán na '%s'.
config.oauth_config=Nastavení ověření OAuth
config.oauth_enabled=Zapnutý
config.cache_config=Nastavení mezipaměti
config.cache_adapter=Adaptér mezipaměti
config.cache_interval=Interval mezipaměti
config.cache_conn=Připojení mezipaměti
config.session_config=Nastavení relace
config.session_provider=Poskytovatel relace
config.provider_config=Nastavení poskytovatele
@@ -1032,9 +1123,24 @@ config.gc_interval_time=Čas intervalu GC
config.session_life_time=Doba trvání relace
config.https_only=Pouze protokol HTTPS
config.cookie_life_time=Doba života souboru cookie
config.picture_config=Nastavení ikony uživatele
config.picture_service=Služba ikon uživatelů
config.disable_gravatar=Zakázat službu Gravatar
config.enable_federated_avatar=Povolit jednotné avatary
config.git_config=Konfigurace Gitu
config.git_disable_diff_highlight=Zakázat zvýraznění syntaxe v rozdílovém zobrazení
config.git_max_diff_lines=Maximální počet rozdílových řádků jednoho souboru
config.git_max_diff_line_characters=Maximální počet zobrazených rozdílových znaků
config.git_max_diff_files=Maximální počet zobrazených rozdílových souborů
config.git_gc_args=Parametry GC
config.git_migrate_timeout=Časový limit migrace
config.git_mirror_timeout=Časový limit aktualizace zrcadla
config.git_clone_timeout=Časový limit operace naklonování
config.git_pull_timeout=Časový limit operace stažení
config.git_gc_timeout=Časový limit operace GC
config.log_config=Nastavení logů
config.log_mode=Způsob logování
@@ -1090,13 +1196,13 @@ now=nyní
1w=%s 1 týdnem
1mon=%s 1 měsícem
1y=%s 1 rokem
seconds=%s %d sekundami
minutes=%s %d minutami
hours=%s %d hodinami
days=%s %d dny
weeks=%s %d týdny
months=%s %d měsíci
years=%s %d roky
seconds=%[2]s %[1]d sekundami
minutes=%[2]s %[1]d minutami
hours=%[2]s %[1]d hodinami
days=%[2]s %[1]d dny
weeks=%[2]s %[1]d týdny
months=%[2]s %[1]d měsíci
years=%[2]s %[1]d roky
raw_seconds=sekund
raw_minutes=minut

View File

@@ -47,7 +47,7 @@ cancel=Abbrechen
[install]
install=Installation
title=Installationsschritte für den ersten Start
docker_helper=Wenn Gogs innerhalb Docker läuft, lesen Sie sich bitte den <a target="_blank" href="%s">Leitfaden</a> genau durch, bevor Sie irgendwas auf dieser Seite ändern!
docker_helper=Wenn Gogs innerhalb von Docker läuft, lesen Sie sich bitte den <a target="_blank" href="%s">Leitfaden</a> genau durch, bevor Sie irgendwas auf dieser Seite ändern!
requite_db_desc=Gogs benötigt MySQL, PostgreSQL, SQLite3 oder TiDB.
db_title=Datenbankeinstellungen
db_type=Datenbanktyp
@@ -96,6 +96,8 @@ offline_mode=Offline-Modus aktivieren
offline_mode_popup=CDN auch im Produktivmodus deaktivieren. Alle Dateien werden von diesem Server ausgeliefert.
disable_gravatar=Gravatar-Dienst deaktivieren
disable_gravatar_popup=Gravatar und benutzerdefinierte Quellen deaktivieren. Alle Profilbilder werden vom Nutzer hochgeladen oder sind das Standard-Profilbild.
federated_avatar_lookup=Suche nach föderierten Profilbildern einschalten
federated_avatar_lookup_popup=Der Suche nach föderierten Profilbildern die Verwendung von föderierten open source Services basierend auf libravatar erlauben.
disable_registration=Registrierung deaktivieren
disable_registration_popup=Registrierung neuer Benutzer deaktivieren. Nur Administratoren können Benutzerkonten anlegen.
enable_captcha=Captcha aktivieren
@@ -114,6 +116,7 @@ sqlite3_not_available=Ihre Gogs-Version unterstützt SQLite3 nicht. Bitte laden
invalid_db_setting=Datenbankeinstellungen sind nicht korrekt: %v
invalid_repo_path=Repository Verzeichnis ist ungültig: %v
run_user_not_match=Der ausführende Benutzer ist nicht der aktuelle Benutzer: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Fehler beim Speichern der Konfiguration: %v
invalid_admin_setting=Admin-Konto Einstellungen sind ungültig: %v
install_success=Herzlich Willkommen! Wir sind froh, dass Sie sich für Gogs entschieden haben. Wir wünschen viel Vergnügen damit.
@@ -124,6 +127,7 @@ uname_holder=Benutzername oder E-Mail
password_holder=Passwort
switch_dashboard_context=Kontext der Übersichtsseite wechseln
my_repos=Meine Repositories
show_more_repos=Zeige mehr Repositories...
collaborative_repos=Gemeinschaftliche Repositories
my_orgs=Meine Organisationen
my_mirrors=Meine Mirrors
@@ -134,6 +138,7 @@ issues.in_your_repos=In Ihren Repositories
[explore]
repos=Repositories
users=Benutzer
organizations=Organisationen
search=Suche
[auth]
@@ -148,10 +153,11 @@ forget_password=Passwort vergessen?
sign_up_now=Benötigen Sie ein Konto? Registrieren Sie sich jetzt.
confirmation_mail_sent_prompt=Eine neue Bestätigungs-E-Mail wurde an <b>%s</b> gesendet. Bitte kontrollieren Sie Ihr Postfach innerhalb der nächsten %d Stunden, um die Registrierung abzuschließen.
active_your_account=Aktivieren Sie Ihr Konto
prohibit_login=Anmelden verboten
prohibit_login_desc=Ihrem Konto ist es nicht gestattet sich anzumelden. Bitte kontaktieren Sie den Administrator.
resent_limit_prompt=Es tut uns leid, aber Sie haben bereits eine Aktivierungs-E-Mail angefordert. Bitte warten Sie 3 Minuten und probieren Sie es dann nochmal.
has_unconfirmed_mail=Hallo %s, Sie haben eine unbestätigte E-Mail-Adresse (<b>%s</b>). Wenn Sie keine Bestätigungs-E-Mail erhalten haben oder eine neue benötigen, klicken Sie bitte auf den folgenden Button.
resend_mail=Hier klicken, um die Aktivierungs-E-Mail erneut zu versenden
email_not_associate=Diese E-Mail-Adresse ist mit keinem Konto verknüpft.
send_reset_mail=Hier klicken, um die E-Mail zum Passwort-zurücksetzen erneut zu versenden
reset_password=Passwort zurücksetzen
invalid_code=Es tut uns leid, der Bestätigungscode ist abgelaufen oder ungültig.
@@ -184,6 +190,13 @@ TeamName=Teamname
AuthName=Name der Autorisierung
AdminEmail=Administrator E-Mail
NewBranchName=Neuer Branch Name
CommitSummary=Commit Zusammenfassung
CommitMessage=Commit Nachricht
CommitChoice=Commit Auswahl
TreeName=Dateipfad
Content=Inhalt
require_error=` darf nicht leer sein.`
alpha_dash_error=` kann ausschließlich alphanumerische Zeichen und "-_" enthalten.`
alpha_dash_dot_error=` kann ausschließlich alphanumerische Zeichen und ".-_" enthalten.`
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=Benutzernamen der Form '%s' sind nicht erlaubt.
[settings]
profile=Profil
password=Passwort
avatar=Profilbild
ssh_keys=SSH-Schlüssel
social=Soziale Konten
applications=Anwendungen
@@ -256,6 +270,8 @@ change_username_prompt=Diese Änderung wirkt sich auf die Links zu Ihrem Benutze
continue=Weiter
cancel=Abbrechen
lookup_avatar_by_mail=Suche nach Profilbildern via E-Mail
federated_avatar_lookup=Suche nach föderierten Profilbildern
enable_custom_avatar=Benutzerdefiniertes Profilbild aktivieren
choose_new_avatar=Neues Profilbild auswählen
update_avatar=Profilbildeinstellungen aktualisieren
@@ -322,6 +338,10 @@ access_token_deletion=Persönlichen Token entfernen
access_token_deletion_desc=Das Löschen dieses persönlichen Zugangs-Tokens wird alle zugehörigen Zugriffe der Anwendung entfernen. Möchten Sie fortfahren?
delete_token_success=Persönlicher Zugriffs-Token wurde erfolgreich entfernt! Vergessen Sie nicht Ihre Anwendung zu aktualisieren.
orgs.none=Sie sind kein Mitglied einer Organisation.
orgs.leave_title=Organisation verlassen
orgs.leave_desc=Sie verlieren den Zugriff auf alle Repositories und Teams nach dem Verlassen der Organisation. Möchten Sie fortfahren?
delete_account=Konto löschen
delete_prompt=Diese Aktion wird Ihr Konto dauerhaft löschen und kann <strong>NICHT</strong> rückgängig gemacht werden!
confirm_delete_account=Löschvorgang bestätigen
@@ -342,7 +362,7 @@ fork_from=Fork von
fork_visiblity_helper=Die Sichtbarkeit von geforkten Repositories ist nicht veränderbar.
repo_desc=Beschreibung
repo_lang=Sprache
repo_lang_helper=Wählen Sie eine .gitignore-Datei aus
repo_gitignore_helper=Wählen Sie eine .gitignore Vorlage aus
license=Lizenz
license_helper=Wählen Sie eine Lizenz aus
readme=Readme
@@ -355,6 +375,7 @@ mirror_prune_desc=Entferne alle Verweise auf nicht mehr existierende entfernte R
mirror_interval=Mirror-Intervall (in Stunden)
mirror_address=Mirror-Adresse
mirror_address_desc=Bitte die nötigen Zugangsdaten in die Adresse mit aufnehmen.
mirror_last_synced=Zuletzt synchronisiert
watchers=Beobachter
stargazers=In Favoriten von
forks=Forks
@@ -368,7 +389,8 @@ migrate_type=Migrationstyp
migrate_type_helper=Dieses Repository wird ein <span class="text blue">Mirror</span> sein
migrate_repo=Repository migrieren
migrate.clone_address=Adresse kopieren
migrate.clone_address_desc=Dies kann eine HTTP/HTTPS/GIT URL oder ein lokaler Serverpfad sein.
migrate.clone_address_desc=Dies kann eine HTTP/HTTPS/GIT-URL sein.
migrate.clone_address_desc_import_local=Du darfst ein Repository vom lokalen Serverpfad migrieren.
migrate.permission_denied=Ihnen fehlen die Rechte zum Importieren lokaler Repositories.
migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder ist kein Ordner.
migrate.failed=Fehler bei Migration: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Erstellen Sie ein neues Repository mittels der Kommandoz
push_exist_repo=Bestehendes Repository von der Kommandozeile pushen
repo_is_empty=Dieses Repository ist leer. Bitte kommen Sie später wieder!
code=Code
files=Dateien
branch=Branch
tree=Struktur
filter_branch_and_tag=Nach Branch oder Tag filtern
@@ -409,6 +431,47 @@ file_raw=Originalformat
file_history=Verlauf
file_view_raw=Ansicht im Originalformat
file_permalink=Permalink
file_too_large=Diese Datei ist zu groß zum Anzeigen
video_not_supported_in_browser=Ihr Browser unterstützt HTML5 Video-Tags nicht.
editor.new_file=Neue Datei
editor.upload_file=Datei hochladen
editor.edit_file=Datei bearbeiten
editor.preview_changes=Vorschau der Änderungen
editor.cannot_edit_non_text_files=Nicht-Text Dateien können nicht bearbeitet werden
editor.edit_this_file=Datei bearbeiten
editor.must_be_on_a_branch=Sie müssen sich in einem Branch befinden, um Änderungen an dieser Datei vorzuschlagen oder vorzunehmen
editor.fork_before_edit=Um die Datei zu bearbeiten, müssen Sie das Repository forken
editor.delete_this_file=Datei löschen
editor.must_have_write_access=Du musst Schreibzugriff haben, um Änderungen an dieser Datei vorzuschlagen oder vorzunehmen
editor.file_delete_success=Die Datei '%s' wurde erfolgreich gelöscht!
editor.name_your_file=Dateinamen eingeben...
editor.filename_help=Um einen Ordner hinzuzufügen, gib den Namen ein und drücke /. Um einen Ordner zu entfernen, gehe zum Anfang des Feldes und drücke auf die Rücktaste.
editor.or=oder
editor.cancel_lower=abbrechen
editor.commit_changes=Änderungen einchecken
editor.add_tmpl=Hinzufügen von '%s/<filename>'
editor.add='%s' hinzufügen
editor.update='%s' ändern
editor.delete='%s' löschen
editor.commit_message_desc=Eine ausführlichere Beschreibung kann hinzugefügt werden...
editor.commit_directly_to_this_branch=Direkt in den <strong class="branch-name">%s</strong> Branch einchecken.
editor.create_new_branch=Einen <strong>neuen Branch</strong> für diesen Commit erstellen und einen Pull Request starten.
editor.new_branch_name_desc=Neuer Branch Name...
editor.cancel=Abbrechen
editor.filename_cannot_be_empty=Der Dateiname darf nicht leer sein.
editor.branch_already_exists=Branch '%s' existiert bereits in diesem Repository.
editor.directory_is_a_file='%s' im übergeordneten Verzeichnis ist eine Datei und kein Verzeichnis.
editor.file_is_a_symlink=Die Datei '%s' ist ein Symlink die nicht im Webeditor verändert werden kann.
editor.filename_is_a_directory=Die Datei '%s' existiert bereits als Verzeichnis in diesem Repository.
editor.file_editing_no_longer_exists=Die Datei '%s', welche Sie bearbeiten, existiert in diesem Repository nicht mehr.
editor.file_changed_while_editing=Seit dem Start der Bearbeitung hat sich die Datei geändert. <a target="_blank" href="%s">Hier klicken</a> um die Änderungen zu sehen, oder nochmals <strong>Commit drücken</strong> um die Änderungen zu überschreiben.
editor.file_already_exists=Eine Datei mit dem Namen '%s' existiert bereits in diesem Repository.
editor.no_changes_to_show=Keine Änderungen vorhanden.
editor.fail_to_update_file=Fehler beim Ändern/Erstellen der Datei '%s'. Fehler: %v
editor.add_subdir=Unterverzeichnis erstellen...
editor.unable_to_upload_files=Fehler beim Hochladen der Dateien zu '%s'. Fehler: %v
editor.upload_files_to_dir=Dateien hochladen nach '%s'
commits.commits=Commits
commits.search=Commits durchsuchen
@@ -435,6 +498,11 @@ issues.create=Issue erstellen
issues.new_label=Neues Label
issues.new_label_placeholder=Label-Name...
issues.create_label=Label erstellen
issues.label_templates.title=Lade vordefinierte Label
issues.label_templates.info=Es sind noch keine Label vorhanden. Sie können vordefinierte Label benutzen, oder auf "Neues Label" klicken um eines zu erstellen.
issues.label_templates.helper=Wählen Sie ein Label
issues.label_templates.use=Dieses Label Set benutzen
issues.label_templates.fail_to_load_file=Fehler beim Laden der Label Template Datei '%s': %v
issues.open_tab=%d offen
issues.close_tab=%d geschlossen
issues.filter_label=Label
@@ -462,7 +530,8 @@ issues.next=Nächste
issues.open_title=Offen
issues.closed_title=Geschlossen
issues.num_comments=%d Kommentare
issues.commented_at=`hat <a id="%[1]s" href="#%[1]s">%[2]s</a> kommentiert`
issues.commented_at=`kommentierte <a href="#%s">%s</a>`
issues.delete_comment_confirm=Sind Sie sich sicher, dass Sie diesen Kommentar löschen wollen?
issues.no_content=Hier gibt es bis jetzt noch keinen Inhalt.
issues.close_issue=Schließen
issues.close_comment_issue=Kommentieren und schließen
@@ -475,8 +544,7 @@ issues.commit_ref_at=`hat dieses Issue <a id="%[1]s" href="#%[1]s">%[2]s</a> aus
issues.poster=Ersteller
issues.collaborator=Mitarbeiter
issues.owner=Besitzer
issues.sign_up_for_free=Kostenlos anmelden
issues.sign_in_require_desc=um dieser Diskussion beizutreten. Haben Sie bereits ein Konto? <a href="%s">Anmelden um zu kommentieren</a>
issues.sign_in_require_desc=<a href="%s">Anmelden</a>, um an der Diskussion teilzunehmen.
issues.edit=Bearbeiten
issues.cancel=Abbrechen
issues.save=Speichern
@@ -491,6 +559,8 @@ issues.label_deletion=Label löschen
issues.label_deletion_desc=Das Label wird von allen verknüpften Issues entfernt. Möchten Sie fortfahren?
issues.label_deletion_success=Label wurde erfolgreich gelöscht!
issues.num_participants=%d Beteiligte
issues.attachment.open_tab=`Klicken um "%s" in einem neuen Tab zu öffnen`
issues.attachment.download=`Klicken um "%s" herunterzuladen`
pulls.new=Neuer Pull-Request
pulls.compare_changes=Änderungen vergleichen
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Dieser Pull-Request kann nicht automatisch zusammen
pulls.cannot_auto_merge_helper=Bitte manuell zusammenführen, um die Konflikte zu lösen.
pulls.merge_pull_request=Pull-Request zusammenführen
pulls.open_unmerged_pull_exists=`Sie können diesen Pull-Request nicht wieder öffnen, da bereits ein offener Pull-Request (#%d) aus dem selben Repository mit den gleichen Merge-Informationen existiert und auf das Zusammenführen wartet.`
pulls.delete_branch=Zweig löschen
pulls.delete_branch_has_new_commits=Zweig kann nicht gelöscht werden, da er noch weitere Commits nach dem Zusammenführen enthält.
milestones.new=Neuer Meilenstein
milestones.open_tab=%d offen
@@ -570,20 +642,27 @@ settings.collaboration.undefined=Nicht definiert
settings.hooks=Webhooks
settings.githooks=Git-Hooks
settings.basic_settings=Grundeinstellungen
settings.mirror_settings=Mirror Einstellungen
settings.sync_mirror=Jetzt synchronisieren
settings.mirror_sync_in_progress=Mirror Synchronisierung läuft, bitte die Seite in ca. einer Minute neu laden.
settings.site=Offizielle Webseite
settings.update_settings=Einstellungen speichern
settings.change_reponame_prompt=Diese Änderung wirkt sich darauf aus, wie sich Links auf Repositories beziehen.
settings.advanced_settings=Erweiterte Einstellungen
settings.wiki_desc=Wiki aktivieren, damit Benutzer Seiten anlegen können
settings.wiki_desc=Wiki einschalten
settings.use_internal_wiki=Eingebautes Wiki verwenden
settings.use_external_wiki=Externes Wiki verwenden
settings.external_wiki_url=Externe Wiki URL
settings.external_wiki_url_desc=Besucher werden auf diese URL umgeleitet, wenn sie auf den Tab klicken.
settings.issues_desc=Eingebautes einfaches Issue-System verwenden
settings.issues_desc=Issue-Tracker einschalten
settings.use_internal_issue_tracker=Eingebauten Issue-Tracker verwenden
settings.use_external_issue_tracker=Externes Issue-System verwenden
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=URL-Format des externen Issue-Systems
settings.tracker_issue_style=Namenskonvention des externen Issue-Trackers:
settings.tracker_issue_style.numeric=Numerisch <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumerisch <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style.numeric=Numerisch
settings.tracker_issue_style.alphanumeric=Alphanumerisch
settings.tracker_url_format_desc=Sie können die Platzhalter <code>{user} {repo} {index}</code> für den Benutzernamen, den Namen des Repositories und die Issue-Nummer verwenden.
settings.pulls_desc=Pull-Requests aktivieren, um öffentliche Mitwirkung zu ermöglichen
settings.danger_zone=Gefahrenzone
@@ -653,6 +732,8 @@ settings.event_send_everything=Ich brauche <strong>alles</strong>.
settings.event_choose=Lass mich auswählen, was ich brauche.
settings.event_create=Erstellen
settings.event_create_desc=Branch/Tag erstellt
settings.event_pull_request=Pull-Request
settings.event_pull_request_desc=Pull-Request geöffnet, geschlossen, wieder geöffnet, bearbeitet, zugewiesen, nicht zugewiesen, Label aktualisiert, Label gelöscht oder synchronisiert.
settings.event_push=Push
settings.event_push_desc=Git push auf ein Repository
settings.active=Aktiv
@@ -690,7 +771,7 @@ diff.show_unified_view=Gesamtansicht
diff.stats_desc=<strong> %d geänderte Dateien</strong> mit <strong>%d neuen</strong> und <strong>%d gelöschten</strong> Zeilen
diff.bin=BIN
diff.view_file=Datei anzeigen
diff.file_supressed=Datei-Diff unterdrückt, da es zu groß ist
diff.file_suppressed=Datei-Diff unterdrückt, da er zu groß ist
diff.too_many_files=Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.
release.releases=Releases
@@ -722,6 +803,7 @@ release.deletion=Release löschen
release.deletion_desc=Beim Löschen dieses Releases wird das entsprechende Git-Tag gelöscht. Möchten Sie fortfahren?
release.deletion_success=Release wurde erfolgreich gelöscht!
release.tag_name_already_exist=Ein Release mit diesem Tag existiert bereits.
release.tag_name_invalid=Tag-Name ist nicht gültig.
release.downloads=Downloads
[org]
@@ -889,6 +971,7 @@ users.edit_account=Konto bearbeiten
users.max_repo_creation=Maximale Anzahl erstellbarer Repositories
users.max_repo_creation_desc=(Auf -1 setzen, um das globale Standardlimit zu verwenden)
users.is_activated=Dieses Konto ist aktiviert
users.prohibit_login=Diesem Konto ist es nicht gestattet sich anzumelden
users.is_admin=Dieses Konto hat Administratorrechte
users.allow_git_hook=Dieses Konto ist berechtigt Git-Hooks zu erstellen
users.allow_import_local=Dieses Konto ist berechtigt, lokale Repositories zu importieren
@@ -957,9 +1040,10 @@ auths.delete_auth_title=Authentifizierung löschen
auths.delete_auth_desc=Diese Authentifizierung wird gelöscht. Möchten Sie fortfahren?
auths.still_in_used=Diese Authentifizierung wird noch von einigen Benutzern verwendet. Bitte löschen Sie diese Benutzer oder ändern Sie deren Anmeldetyp.
auths.deletion_success=Authentifizierung wurde erfolgreich gelöscht!
auths.login_source_exist=Login-Quelle '%s' ist bereits vorhanden.
config.server_config=Serverkonfiguration
config.app_name=Anwendungsname
config.app_name=Name der Anwendung
config.app_ver=Anwendungsversion
config.app_url=Anwendungs-URL
config.domain=Domain
@@ -967,6 +1051,7 @@ config.offline_mode=Offline-Modus
config.disable_router_log=Router-Log deaktivieren
config.run_user=Ausführender Benutzer
config.run_mode=Laufzeit-Modus
config.git_version=Git Version
config.repo_root_path=Repository-Verzeichnis
config.static_file_root_path=Verzeichnis für statische Dateien
config.log_file_root_path=Log-Verzeichnis
@@ -994,6 +1079,7 @@ config.db_ssl_mode=SSL-Modus
config.db_ssl_mode_helper=(nur für "postgres")
config.db_path=Verzeichnis
config.db_path_helper=(für "sqlite3" und "tidb")
config.service_config=Service-Konfiguration
config.register_email_confirm=E-Mail-Bestätigung bei Registrierung
config.disable_register=Registrierung deaktivieren
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Prüfung der Mindestschlüssellänge deaktiveren
config.enable_captcha=Captcha aktivieren
config.active_code_lives=Aktivierungscode Lebensdauer
config.reset_password_code_lives=Passwortcode Lebensdauer
config.webhook_config=Webhook-Konfiguration
config.queue_length=Warteschlangenlänge
config.deliver_timeout=Zeitlimit für Zustellung
config.skip_tls_verify=TLS verifikation überspringen
config.mailer_config=Mailer-Konfiguration
config.mailer_enabled=Aktiviert
config.mailer_disable_helo=HELO Deaktivieren
@@ -1017,12 +1105,15 @@ config.mailer_user=Benutzer
config.send_test_mail=Test-E-Mail senden
config.test_mail_failed=Das Senden der Test-E-Mail an '%s': %v ist fehlgeschlagen
config.test_mail_sent=Test-E-Mail wurde an '%s' gesendet.
config.oauth_config=OAuth-Konfiguration
config.oauth_enabled=Aktiviert
config.cache_config=Cache-Konfiguration
config.cache_adapter=Cache-Adapter
config.cache_interval=Cache-Intervall
config.cache_conn=Cache-Anbindung
config.session_config=Session-Konfiguration
config.session_provider=Session-Provider
config.provider_config=Provider-Einstellungen
@@ -1032,9 +1123,24 @@ config.gc_interval_time=GC-Intervall
config.session_life_time=Session-Lebensdauer
config.https_only=Nur HTTPS
config.cookie_life_time=Cookie-Lebensdauer
config.picture_config=Konfiguration der Profilbilder
config.picture_service=Bildservice
config.disable_gravatar=Gravatar deaktivieren
config.enable_federated_avatar=Föderierte Profilbilder einschalten
config.git_config=Git Konfiguration
config.git_disable_diff_highlight=Diff Syntaxhervorhebung ausschalten
config.git_max_diff_lines=Max Diff Zeilen (in einer Datei)
config.git_max_diff_line_characters=Max Diff Zeichen (in einer Zeile)
config.git_max_diff_files=Max Diff Dateien (Anzeige)
config.git_gc_args=GC-Argumente
config.git_migrate_timeout=Zeitlimit für Migration
config.git_mirror_timeout=Zeitlimit für Mirror-Aktualisierung
config.git_clone_timeout=Zeitlimit für Clone
config.git_pull_timeout=Zeitlimit für Pull
config.git_gc_timeout=Zeitlimit für GC
config.log_config=Konfiguration des Loggings
config.log_mode=Log-Modus

View File

@@ -96,6 +96,8 @@ offline_mode = Enable Offline Mode
offline_mode_popup = Disable CDN even in production mode, all resource files will be served locally.
disable_gravatar = Disable Gravatar Service
disable_gravatar_popup = Disable Gravatar and custom sources, all avatars are uploaded by users or default.
federated_avatar_lookup = Enable Federated Avatars Lookup
federated_avatar_lookup_popup = Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration = Disable Self-registration
disable_registration_popup = Disable user self-registration, only admin can create accounts.
enable_captcha = Enable Captcha
@@ -114,6 +116,7 @@ sqlite3_not_available = Your release version does not support SQLite3, please do
invalid_db_setting = Database setting is not correct: %v
invalid_repo_path = Repository root path is invalid: %v
run_user_not_match = Run user isn't the current user: %s -> %s
invalid_smtp_from = SMTP From field is not valid: %v
save_config_failed = Fail to save configuration: %v
invalid_admin_setting = Admin account setting is invalid: %v
install_success = Welcome! We're glad that you chose Gogs, have fun and take care.
@@ -124,6 +127,7 @@ uname_holder = Username or email
password_holder = Password
switch_dashboard_context = Switch Dashboard Context
my_repos = My Repositories
show_more_repos = Show more repositories...
collaborative_repos = Collaborative Repositories
my_orgs = My Organizations
my_mirrors = My Mirrors
@@ -134,6 +138,7 @@ issues.in_your_repos = In your repositories
[explore]
repos = Repositories
users = Users
organizations = Organizations
search = Search
[auth]
@@ -153,7 +158,6 @@ prohibit_login_desc = Your account is prohibited to login, please contact site a
resent_limit_prompt = Sorry, you already requested an activation email recently. Please wait 3 minutes then try again.
has_unconfirmed_mail = Hi %s, you have an unconfirmed email address (<b>%s</b>). If you haven't received a confirmation email or need to resend a new one, please click on the button below.
resend_mail = Click here to resend your activation email
email_not_associate = This email address is not associated with any account.
send_reset_mail = Click here to (re)send your password reset email
reset_password = Reset Your Password
invalid_code = Sorry, your confirmation code has expired or not valid.
@@ -186,6 +190,13 @@ TeamName = Team name
AuthName = Authorization name
AdminEmail = Admin email
NewBranchName = New branch name
CommitSummary = Commit summary
CommitMessage = Commit message
CommitChoice = Commit choice
TreeName = File path
Content = Content
require_error = ` cannot be empty.`
alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.`
alpha_dash_dot_error = ` must be valid alpha or numeric or dash(-_) or dot characters.`
@@ -238,6 +249,7 @@ form.name_pattern_not_allowed = Username pattern '%s' is not allowed.
[settings]
profile = Profile
password = Password
avatar = Avatar
ssh_keys = SSH Keys
social = Social Accounts
applications = Applications
@@ -258,7 +270,9 @@ change_username_prompt = This change will affect the way how links relate to you
continue = Continue
cancel = Cancel
enable_custom_avatar = Enable Custom Avatar
lookup_avatar_by_mail = Lookup Avatar by mail
federated_avatar_lookup = Federated Avatar Lookup
enable_custom_avatar = Use Custom Avatar
choose_new_avatar = Choose new avatar
update_avatar = Update Avatar Setting
delete_current_avatar = Delete Current Avatar
@@ -324,6 +338,10 @@ access_token_deletion = Personal Access Token Deletion
access_token_deletion_desc = Delete this personal access token will remove all related accesses of application. Do you want to continue?
delete_token_success = Personal access token has been removed successfully! Don't forget to update your application as well.
orgs.none = You are not a member of any organizations.
orgs.leave_title = Leave an organization
orgs.leave_desc = You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account = Delete Your Account
delete_prompt = The operation will delete your account permanently, and <strong>CANNOT</strong> be undone!
confirm_delete_account = Confirm Deletion
@@ -344,7 +362,7 @@ fork_from = Fork From
fork_visiblity_helper = You cannot alter the visibility of a forked repository.
repo_desc = Description
repo_lang = Language
repo_lang_helper = Select .gitignore files
repo_gitignore_helper = Select .gitignore templates
license = License
license_helper = Select a license file
readme = Readme
@@ -357,6 +375,7 @@ mirror_prune_desc = Remove any remote-tracking references that no longer exist o
mirror_interval = Mirror Interval (hour)
mirror_address = Mirror Address
mirror_address_desc = Please include necessary user credentials in the address.
mirror_last_synced = Last Synced
watchers = Watchers
stargazers = Stargazers
forks = Forks
@@ -370,7 +389,8 @@ migrate_type = Migration Type
migrate_type_helper = This repository will be a <span class="text blue">mirror</span>
migrate_repo = Migrate Repository
migrate.clone_address = Clone Address
migrate.clone_address_desc = This can be a HTTP/HTTPS/GIT URL or local server path.
migrate.clone_address_desc = This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local = You're also allowed to migrate a repository by local server path.
migrate.permission_denied = You are not allowed to import local repositories.
migrate.invalid_local_path = Invalid local path, it does not exist or not a directory.
migrate.failed = Migration failed: %v
@@ -395,7 +415,7 @@ create_new_repo_command = Create a new repository on the command line
push_exist_repo = Push an existing repository from the command line
repo_is_empty = This repository is empty, please come back later!
code = Code
files = Files
branch = Branch
tree = Tree
filter_branch_and_tag = Filter branch or tag
@@ -412,6 +432,46 @@ file_history = History
file_view_raw = View Raw
file_permalink = Permalink
file_too_large = This file is too large to be shown
video_not_supported_in_browser = Your browser doesn't support HTML5 video tag.
editor.new_file = New file
editor.upload_file = Upload file
editor.edit_file = Edit file
editor.preview_changes = Preview Changes
editor.cannot_edit_non_text_files = Cannot edit non-text files
editor.edit_this_file = Edit this file
editor.must_be_on_a_branch = You must be on a branch to make or propose changes to this file
editor.fork_before_edit = You must fork this repository before editing the file
editor.delete_this_file = Delete this file
editor.must_have_write_access = You must have write access to make or propose changes to this file
editor.file_delete_success = File '%s' has been deleted successfully!
editor.name_your_file = Name your file...
editor.filename_help = To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
editor.or = or
editor.cancel_lower = cancel
editor.commit_changes = Commit Changes
editor.add_tmpl = Add '%s/<filename>'
editor.add = Add '%s'
editor.update = Update '%s'
editor.delete = Delete '%s'
editor.commit_message_desc = Add an optional extended description...
editor.commit_directly_to_this_branch = Commit directly to the <strong class="branch-name">%s</strong> branch.
editor.create_new_branch = Create a <strong>new branch</strong> for this commit and start a pull request.
editor.new_branch_name_desc = New branch name...
editor.cancel = Cancel
editor.filename_cannot_be_empty = Filename cannot be empty.
editor.branch_already_exists = Branch '%s' already exists in this repository.
editor.directory_is_a_file = Entry '%s' in the parent path is a file not a directory in this repository.
editor.file_is_a_symlink = The file '%s' is a symlink that cannot be modified from the web editor.
editor.filename_is_a_directory = The filename '%s' is an existing directory in this repository.
editor.file_editing_no_longer_exists = The file '%s' you are editing no longer exists in the repository.
editor.file_changed_while_editing = File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
editor.file_already_exists = A file with name '%s' already exists in this repository.
editor.no_changes_to_show = There are no changes to show.
editor.fail_to_update_file = Failed to update/create file '%s' with error: %v
editor.add_subdir = Add subdirectory...
editor.unable_to_upload_files = Failed to upload files to '%s' with error: %v
editor.upload_files_to_dir = Upload files to '%s'
commits.commits = Commits
commits.search = Search commits
@@ -438,6 +498,11 @@ issues.create = Create Issue
issues.new_label = New Label
issues.new_label_placeholder = Label name...
issues.create_label = Create Label
issues.label_templates.title = Load a predefined set of labels
issues.label_templates.info = There arent any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
issues.label_templates.helper = Select a label set
issues.label_templates.use = Use this label set
issues.label_templates.fail_to_load_file = Failed to load label template file '%s': %v
issues.open_tab = %d Open
issues.close_tab = %d Closed
issues.filter_label = Label
@@ -465,7 +530,8 @@ issues.next = Next
issues.open_title = Open
issues.closed_title = Closed
issues.num_comments = %d comments
issues.commented_at = `commented <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at = `commented <a href="#%s">%s</a>`
issues.delete_comment_confirm = Are you sure you want to delete this comment?
issues.no_content = There is no content yet.
issues.close_issue = Close
issues.close_comment_issue = Comment and close
@@ -478,8 +544,7 @@ issues.commit_ref_at = `referenced this issue from a commit <a id="%[1]s" href="
issues.poster = Poster
issues.collaborator = Collaborator
issues.owner = Owner
issues.sign_up_for_free = Sign up for free
issues.sign_in_require_desc = to join this conversation. Already have an account? <a href="%s">Sign in to comment</a>
issues.sign_in_require_desc = <a href="%s">Sign in</a> to join this conversation.
issues.edit = Edit
issues.cancel = Cancel
issues.save = Save
@@ -494,6 +559,8 @@ issues.label_deletion = Label Deletion
issues.label_deletion_desc = Deleting this label will remove its information in all related issues. Do you want to continue?
issues.label_deletion_success = Label has been deleted successfully!
issues.num_participants = %d Participants
issues.attachment.open_tab = `Click to see "%s" in a new tab`
issues.attachment.download = `Click to download "%s"`
pulls.new = New Pull Request
pulls.compare_changes = Compare Changes
@@ -520,6 +587,8 @@ pulls.cannot_auto_merge_desc = This pull request can't be merged automatically b
pulls.cannot_auto_merge_helper = Please merge manually in order to resolve the conflicts.
pulls.merge_pull_request = Merge Pull Request
pulls.open_unmerged_pull_exists = `You can't perform reopen operation because there is already an open pull request (#%d) from same repository with same merge information and is waiting for merging.`
pulls.delete_branch = Delete Branch
pulls.delete_branch_has_new_commits = Branch cannot be deleted because it has new commits after mergence.
milestones.new = New Milestone
milestones.open_tab = %d Open
@@ -573,20 +642,27 @@ settings.collaboration.undefined = Undefined
settings.hooks = Webhooks
settings.githooks = Git Hooks
settings.basic_settings = Basic Settings
settings.mirror_settings = Mirror Settings
settings.sync_mirror = Sync Now
settings.mirror_sync_in_progress = Mirror syncing is in progress, please refresh page in about a minute.
settings.site = Official Site
settings.update_settings = Update Settings
settings.change_reponame_prompt = This change will affect how links relate to the repository.
settings.advanced_settings = Advanced Settings
settings.wiki_desc = Enable wiki to allow people write documents
settings.wiki_desc = Enable wiki system
settings.use_internal_wiki = Use builtin wiki
settings.use_external_wiki = Use external wiki
settings.external_wiki_url = External Wiki URL
settings.external_wiki_url_desc = Visitors will be redirected to URL when they click on the tab.
settings.issues_desc = Enable builtin lightweight issue tracker
settings.issues_desc = Enable issue tracker
settings.use_internal_issue_tracker = Use builtin lightweight issue tracker
settings.use_external_issue_tracker = Use external issue tracker
settings.external_tracker_url = External Issue Tracker URL
settings.external_tracker_url_desc = Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format = External Issue Tracker URL Format
settings.tracker_issue_style = External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric = Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric = Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style.numeric = Numeric
settings.tracker_issue_style.alphanumeric = Alphanumeric
settings.tracker_url_format_desc = You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc = Enable pull requests to accept public contributions
settings.danger_zone = Danger Zone
@@ -656,6 +732,8 @@ settings.event_send_everything = I need <strong>everything</strong>.
settings.event_choose = Let me choose what I need.
settings.event_create = Create
settings.event_create_desc = Branch, or tag created
settings.event_pull_request = Pull Request
settings.event_pull_request_desc = Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
settings.event_push = Push
settings.event_push_desc = Git push to a repository
settings.active = Active
@@ -725,6 +803,7 @@ release.deletion = Release Deletion
release.deletion_desc = Deleting this release will delete the corresponding Git tag. Do you want to continue?
release.deletion_success = Release has been deleted successfully!
release.tag_name_already_exist = Release with this tag name already exists.
release.tag_name_invalid = Tag name is not valid.
release.downloads = Downloads
[org]
@@ -819,7 +898,7 @@ first_page = First
last_page = Last
total = Total: %d
dashboard.statistic = Statistic
dashboard.statistic = Statistics
dashboard.operations = Operations
dashboard.system_status = System Monitor Status
dashboard.statistic_info = Gogs database has <b>%d</b> users, <b>%d</b> organizations, <b>%d</b> public keys, <b>%d</b> repositories, <b>%d</b> watches, <b>%d</b> stars, <b>%d</b> actions, <b>%d</b> accesses, <b>%d</b> issues, <b>%d</b> comments, <b>%d</b> social accounts, <b>%d</b> follows, <b>%d</b> mirrors, <b>%d</b> releases, <b>%d</b> login sources, <b>%d</b> webhooks, <b>%d</b> milestones, <b>%d</b> labels, <b>%d</b> hook tasks, <b>%d</b> teams, <b>%d</b> update tasks, <b>%d</b> attachments.
@@ -961,6 +1040,7 @@ auths.delete_auth_title = Authentication Deletion
auths.delete_auth_desc = This authentication is going to be deleted, do you want to continue?
auths.still_in_used = This authentication is still used by some users, please delete or convert these users to another login type first.
auths.deletion_success = Authentication has been deleted successfully!
auths.login_source_exist = Login source '%s' already exists.
config.server_config = Server Configuration
config.app_name = Application Name
@@ -971,6 +1051,7 @@ config.offline_mode = Offline Mode
config.disable_router_log = Disable Router Log
config.run_user = Run User
config.run_mode = Run Mode
config.git_version = Git Version
config.repo_root_path = Repository Root Path
config.static_file_root_path = Static File Root Path
config.log_file_root_path = Log File Root Path
@@ -998,6 +1079,7 @@ config.db_ssl_mode = SSL Mode
config.db_ssl_mode_helper = (for "postgres" only)
config.db_path = Path
config.db_path_helper = (for "sqlite3" and "tidb")
config.service_config = Service Configuration
config.register_email_confirm = Require Email Confirmation
config.disable_register = Disable Registration
@@ -1008,10 +1090,12 @@ config.disable_key_size_check = Disable Minimum Key Size Check
config.enable_captcha = Enable Captcha
config.active_code_lives = Active Code Lives
config.reset_password_code_lives = Reset Password Code Lives
config.webhook_config = Webhook Configuration
config.queue_length = Queue Length
config.deliver_timeout = Deliver Timeout
config.skip_tls_verify = Skip TLS Verify
config.mailer_config = Mailer Configuration
config.mailer_enabled = Enabled
config.mailer_disable_helo = Disable HELO
@@ -1021,12 +1105,15 @@ config.mailer_user = User
config.send_test_mail = Send Test Email
config.test_mail_failed = Fail to send test email to '%s': %v
config.test_mail_sent = Test email has been sent to '%s'.
config.oauth_config = OAuth Configuration
config.oauth_enabled = Enabled
config.cache_config = Cache Configuration
config.cache_adapter = Cache Adapter
config.cache_interval = Cache Interval
config.cache_conn = Cache Connection
config.session_config = Session Configuration
config.session_provider = Session Provider
config.provider_config = Provider Config
@@ -1036,9 +1123,24 @@ config.gc_interval_time = GC Interval Time
config.session_life_time = Session Life Time
config.https_only = HTTPS Only
config.cookie_life_time = Cookie Life Time
config.picture_config = Picture Configuration
config.picture_service = Picture Service
config.disable_gravatar = Disable Gravatar
config.enable_federated_avatar = Enable Federated Avatars
config.git_config = Git Configuration
config.git_disable_diff_highlight = Disable Diff Syntax Highlight
config.git_max_diff_lines = Max Diff Lines (for a single file)
config.git_max_diff_line_characters = Max Diff Characters (for a single line)
config.git_max_diff_files = Max Diff Files (to be shown)
config.git_gc_args = GC Arguments
config.git_migrate_timeout = Migration Timeout
config.git_mirror_timeout = Mirror Update Timeout
config.git_clone_timeout = Clone Operation Timeout
config.git_pull_timeout = Pull Operation Timeout
config.git_gc_timeout = GC Operation Timeout
config.log_config = Log Configuration
config.log_mode = Log Mode

View File

@@ -25,7 +25,7 @@ captcha=Captcha
repository=Repositorio
organization=Organización
mirror=Mirror
mirror=Réplica
new_repo=Nuevo repositorio
new_migrate=Nueva migración
new_mirror=Nueva réplica
@@ -96,6 +96,8 @@ offline_mode=Activar el modo Sin Conexión
offline_mode_popup=Desactivar el CDN incluso en el modo de producción, todos los recursos se servirán localmente.
disable_gravatar=Desactivar el servicio Gravatar
disable_gravatar_popup=Desactivar Gravatar y cualquier otra fuente personalizada. Todos los avatares deben ser cargados por los usuarios o en su defecto se mostrará el avatar predeterminado.
federated_avatar_lookup=Habilitar búsqueda de Avatares Federados
federated_avatar_lookup_popup=Habilitar búsqueda de avatares federador para usar el servicio federado de código abierto basado en libravatar.
disable_registration=Desactivar Auto-Registro
disable_registration_popup=Desactivar auto-registro del usuario, solo el administrador podrá crear cuentas nuevas.
enable_captcha=Activar la Captcha
@@ -114,6 +116,7 @@ sqlite3_not_available=Tu versión no soporta SQLite3, por favor descarga el bina
invalid_db_setting=La configuración de la base de datos no es correcta: %v
invalid_repo_path=La ruta de la raíz del repositorio es inválida: %v
run_user_not_match=El usuario que está ejecutando la aplicación no es el usuario actual: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Error al guardar la configuración: %v
invalid_admin_setting=La configuración de la cuenta de administración es inválida: %v
install_success=Bienvenido! Estamos encantados de que hayas escogido Gogs, diviértete y cuídate.
@@ -124,6 +127,7 @@ uname_holder=Nombre de usuario o correo electrónico
password_holder=Contraseña
switch_dashboard_context=Cambiar el contexto del Dashboard
my_repos=Mis repositorios
show_more_repos=Mostrar más repositorios...
collaborative_repos=Repositorios colaborativos
my_orgs=Mis organizaciones
my_mirrors=Mis réplicas
@@ -134,6 +138,7 @@ issues.in_your_repos=En tus repositorios
[explore]
repos=Repositorios
users=Usuarios
organizations=Organizaciones
search=Buscar
[auth]
@@ -148,10 +153,11 @@ forget_password=¿Has olvidado tu contraseña?
sign_up_now=¿Necesitas una cuenta? Regístrate ahora.
confirmation_mail_sent_prompt=Un nuevo correo de confirmación se ha enviado a <b>%s</b>. Por favor, comprueba tu bandeja de entrada en las siguientes %d horas para completar el proceso de registro.
active_your_account=Activa tu cuenta
prohibit_login=Ingreso prohibido
prohibit_login_desc=Su cuenta tiene prohibido ingresar al sistema, fovor contactar al administrador del sistema.
resent_limit_prompt=Lo sentimos, estás solicitando el reenvío del mail de activación con demasiada frecuencia. Por favor, espera 3 minutos.
has_unconfirmed_mail=Hola %s, tu correo electrónico (<b>%s</b>) no está confirmado. Si no has recibido un correo de confirmación o necesitas que lo enviemos de nuevo, por favor, haz click en el siguiente botón.
resend_mail=Haz click aquí para reenviar tu correo electrónico de activación
email_not_associate=Esta dirección de correo electrónico no esta asociada a ninguna cuenta.
send_reset_mail=Haga clic aquí para (re)enviar el correo para el restablecimiento de la contraseña
reset_password=Restablecer su contraseña
invalid_code=Lo sentimos, su código de confirmación ha expirado o no es valido.
@@ -184,6 +190,13 @@ TeamName=Nombre del equipo
AuthName=Nombre de autorización
AdminEmail=Correo electrónico del administrador
NewBranchName=Nuevo nombre de rama
CommitSummary=Resumen del commit
CommitMessage=Mensaje de commit
CommitChoice=Hacer commit de la elección
TreeName=Ruta del archivo
Content=Contenido
require_error=` no puede estar vacío.`
alpha_dash_error=` los caracteres deben ser Alfanumericos o dash(-_).`
alpha_dash_dot_error=` debe ser un caracter alfanumérivo válido, un guión alto o bajo (-_) o un signo de puntuación.`
@@ -220,7 +233,7 @@ org_still_own_repo=Esta organización es dueña de uno o más repositorios, tien
target_branch_not_exist=La rama de destino no existe
[user]
change_avatar=Change your avatar
change_avatar=Cambiar tu avatar
join_on=Registrado el
repositories=Repositorios
activity=Actividad pública
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=El patrón de nombre de usuario '%s' no está perm
[settings]
profile=Perfil
password=Contraseña
avatar=Avatar
ssh_keys=Claves SSH
social=Redes Sociales
applications=Aplicaciones
@@ -256,6 +270,8 @@ change_username_prompt=Este cambio afectará a los enlaces que hacen referencia
continue=Continuar
cancel=Cancelar
lookup_avatar_by_mail=Buscar avatar por correo
federated_avatar_lookup=Búsqueda de Avatar Federado
enable_custom_avatar=Activar avatar personalizado
choose_new_avatar=Selecciona nuevo avatar
update_avatar=Actualizar configuración del avatar
@@ -322,6 +338,10 @@ access_token_deletion=Borrado de Token de Acceso Personal
access_token_deletion_desc=Si elimina este token de acceso personal la aplicación asociada perderá el permiso de acceso. ¿Desea continuar?
delete_token_success=¡El token de acceso personal ha sido eliminado con éxito! No se olvide de actualizar también las aplicaciones asociadas.
orgs.none=No eres un miembro de ninguna organización.
orgs.leave_title=Salir de una organización
orgs.leave_desc=Perderá el acceso a todos los repositorios y equipos después dejar la organización. ¿Desea continuar?
delete_account=Elimina tu cuenta
delete_prompt=La operación eliminará tu cuenta de forma permanente y ¡<strong>NO</strong> se puede deshacer!
confirm_delete_account=Confirmar Eliminación
@@ -342,7 +362,7 @@ fork_from=Crear un Fork desde
fork_visiblity_helper=No es posible cambiar la visibilidad de un Fork
repo_desc=Descripción
repo_lang=Idioma
repo_lang_helper=Seleccione archivo .gitignore
repo_gitignore_helper=Seleccionar plantillas de .gitignore
license=Licencia
license_helper=Selecciona un fichero de licencia
readme=Readme
@@ -350,11 +370,12 @@ readme_helper=Seleccione una plantilla de archivo readme
auto_init=Inicializar los archivos seleccionados y plantillas de este repositorio
create_repo=Crear repositorio
default_branch=Rama por defecto
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_prune=Purgar
mirror_prune_desc=Remover referencias remotas que no existan remotamente
mirror_interval=Intervalo de la réplica (en horas)
mirror_address=Dirección de la réplica
mirror_address_desc=Por favor, incluya las credenciales de usuario necesarias en la dirección.
mirror_last_synced=Última sincronización
watchers=Seguidores
stargazers=Fans
forks=Forks
@@ -368,7 +389,8 @@ migrate_type=Tipo de migración
migrate_type_helper=Este repositorio será una <span class="text blue">réplica</span>
migrate_repo=Migrar Repositorio
migrate.clone_address=Clonar dirección
migrate.clone_address_desc=Puede ser una URL HTTP/HTTPS/GIT o una ruta local del servidor.
migrate.clone_address_desc=Esto puede ser una dirección URL HTTP/HTTPS/GIT.
migrate.clone_address_desc_import_local=También se le permite migrar un repositorio por la ruta del servidor local.
migrate.permission_denied=No te está permitido importar repositorios locales.
migrate.invalid_local_path=Rutal local inválida, no existe o no es un directorio.
migrate.failed=Migración fallida: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Crear un nuevo repositorio desde línea de comandos
push_exist_repo=Hacer Push de un repositorio existente desde línea de comandos
repo_is_empty=Este repositorio está vacío, por favor, ¡vuelva más tarde!
code=Código
files=Archivos
branch=Rama
tree=Árbol
filter_branch_and_tag=Filtrar por rama o etiqueta
@@ -409,9 +431,50 @@ file_raw=Raw
file_history=Histórico
file_view_raw=Ver Raw
file_permalink=Permalink
file_too_large=Este archivo es demasiado grande para ser mostrado
video_not_supported_in_browser=Su navegador no soporta el tag video de HTML5.
editor.new_file=Nuevo archivo
editor.upload_file=Subir archivo
editor.edit_file=Editar archivo
editor.preview_changes=Vista previa de los cambios
editor.cannot_edit_non_text_files=Sólo puede editar archivos de texto
editor.edit_this_file=Editar este archivo
editor.must_be_on_a_branch=Debes estar en una rama para hacer o proponer cambios en este archivo
editor.fork_before_edit=Debes hacer un fork de este repositorio antes de editar el archivo
editor.delete_this_file=Eliminar este archivo
editor.must_have_write_access=Debes tener permisos de escritura para hacer o proponer cambios a este archivo
editor.file_delete_success=¡El archivo '%s' ha sido eliminado con éxito!
editor.name_your_file=Nombre de archivo...
editor.filename_help=Para añadir un directorio, simplemente escribelo y presiona /. Para eliminar un directorio, ve al principio del campo y presiona retroceso.
editor.or=o
editor.cancel_lower=cancelar
editor.commit_changes=Hacer commit de los cambios
editor.add_tmpl=Añadir '%s<filename>'
editor.add=Añadir '%s'
editor.update=Actualizar '%s'
editor.delete=Eliminar '%s'
editor.commit_message_desc=Añadir una descripción extendida opcional...
editor.commit_directly_to_this_branch=Hacer commit directamente en la rama <strong class="branch-name">%s</strong>.
editor.create_new_branch=Crear una <strong>nueva rama</strong> para este commit y hacer un pull request.
editor.new_branch_name_desc=Nombre de la rama nueva...
editor.cancel=Cancelar
editor.filename_cannot_be_empty=El nombre del archivo no puede estar vacío.
editor.branch_already_exists=La rama '%s' ya existe en este repositorio.
editor.directory_is_a_file=La entrada '%s' en el directorio padre es un archivo no un directorio en este repositorio.
editor.file_is_a_symlink=El archivo '%s' es un enlace simbólico que no puede ser modificado desde el editor de la web.
editor.filename_is_a_directory=El nombre del fichero '%s' es un directorio existente en este repositorio.
editor.file_editing_no_longer_exists=El archivo '%s' que estás editando ya no existe en este repositorio.
editor.file_changed_while_editing=El contenido del archivo ha sido modificado desde que empezó a editarlo. <a target="_blank" href="%s">Clic aquí</a> para ver qué ha sido modificado o <strong>presiona confirmar de nuevo</strong> para sobrescribir estos cambios.
editor.file_already_exists=Ya existe un archivo con nombre '%s' en este repositorio.
editor.no_changes_to_show=No existen cambios para mostrar.
editor.fail_to_update_file=Error al actualizar/crear el archivo '%s', error: %v
editor.add_subdir=Añadir subdirectorio...
editor.unable_to_upload_files=Error al subir archivos a '%s', error: %v
editor.upload_files_to_dir=Subir archivos a '%s'
commits.commits=Commits
commits.search=Buscar Commits
commits.search=Buscar commits
commits.find=Buscar
commits.author=Autor
commits.message=Mensaje
@@ -435,6 +498,11 @@ issues.create=Crear incidencia
issues.new_label=Nueva Etiqueta
issues.new_label_placeholder=Nombre etiqueta...
issues.create_label=Crear etiqueta
issues.label_templates.title=Carga un conjunto predefinido de etiquetas
issues.label_templates.info=Tdavía no hay ninguna etiqueta. Puede hacer clic en el botón "Nueva etiqueta" para crear una o utilizar un conjunto predefinido abajo.
issues.label_templates.helper=Seleccionar un conjunto de etiquetas
issues.label_templates.use=Usar este conjunto de etiquetas
issues.label_templates.fail_to_load_file=Error al cargar el archivo de plantilla de etiqueta '%s': %v
issues.open_tab=%d abiertas
issues.close_tab=%d cerradas
issues.filter_label=Etiqueta
@@ -462,7 +530,8 @@ issues.next=Página Siguiente
issues.open_title=Abierta
issues.closed_title=Cerrada
issues.num_comments=%d comentarios
issues.commented_at=`comentada <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`comentado <a href="#%s"> %s</a>`
issues.delete_comment_confirm=¿Seguro que deseas eliminar este comentario?
issues.no_content=Aún no existe contenido.
issues.close_issue=Cerrar
issues.close_comment_issue=Comentar y cerrar
@@ -475,8 +544,7 @@ issues.commit_ref_at=`mencionada esta incidencia en un commit <a id="%[1]s" href
issues.poster=Autor
issues.collaborator=Colaborador
issues.owner=Propietario
issues.sign_up_for_free=Registro gratuito
issues.sign_in_require_desc=para unirse a esta conversación. ¿Ya dispone de una cuenta? <a href="%s">Inicie sesión para comentar</a>
issues.sign_in_require_desc=<a href="%s"> Inicie sesión</a> para unirse a esta conversación.
issues.edit=Editar
issues.cancel=Cancelar
issues.save=Guardar
@@ -491,6 +559,8 @@ issues.label_deletion=Borrado de Etiqueta
issues.label_deletion_desc=Al borrar la etiqueta su información será eliminada de todas las incidencias relacionadas. Desea continuar?
issues.label_deletion_success=Etiqueta borrada con éxito!
issues.num_participants=%d participantes
issues.attachment.open_tab='Haga clic para ver "%s" en una pestaña nueva'
issues.attachment.download=`Haga clic para descargar "%s"`
pulls.new=Nuevo Pull Request
pulls.compare_changes=Comparar cambios
@@ -508,8 +578,8 @@ pulls.tab_conversation=Conversación
pulls.tab_commits=Commits
pulls.tab_files=Archivos modificados
pulls.reopen_to_merge=Por favor reabra este Pull Request para proceder con la operación de fusionado.
pulls.merged=Fuisionado
pulls.has_merged=¡Este pull request se ha completado con éxito!
pulls.merged=Fusionado
pulls.has_merged=¡Este Pull Request se ha completado con éxito!
pulls.data_broken=Los datos de este pull request ya no están disponibles porque se ha eliminado la información del fork.
pulls.is_checking=Se está procediendo a la búsqueda de conflictos, por favor actualice la página en unos momentos.
pulls.can_auto_merge_desc=Este Pull Request puede ser fusionado automáticamente.
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Este Pull Request no puede ser fusionado automátic
pulls.cannot_auto_merge_helper=Por favor, fusiona manualmente para resolver los conflictos.
pulls.merge_pull_request=Fusionar Pull Request
pulls.open_unmerged_pull_exists=`Usted no puede realizar la operación de reapertura porque en estos momentos existe una solicitud de pull request (#%d) para el mismo repositorio con la misma información que se encuentra a la espera de aprobación`
pulls.delete_branch=Eliminar la rama
pulls.delete_branch_has_new_commits=La rama no se puede eliminar porque tiene nuevos commits después de la fusión.
milestones.new=Nuevo Milestone
milestones.open_tab=%d abiertas
@@ -570,20 +642,27 @@ settings.collaboration.undefined=Indefinido
settings.hooks=Webhooks
settings.githooks=Git Hooks
settings.basic_settings=Configuración Básica
settings.mirror_settings=Configuración de réplica
settings.sync_mirror=Sincronizar ahora
settings.mirror_sync_in_progress=Sincronización de réplica en curso, por favor actualice la página en unos minutos.
settings.site=Sitio oficial
settings.update_settings=Actualizar configuración
settings.change_reponame_prompt=Este cambio afectará a los enlaces al repositorio.
settings.advanced_settings=Ajustes avanzados
settings.wiki_desc=Habilitar la Wiki para que los colaboradores documenten
settings.wiki_desc=Activar sistema de wiki
settings.use_internal_wiki=Usar wiki integrada
settings.use_external_wiki=Usar Wiki externa
settings.external_wiki_url=URL externa de la Wiki
settings.external_wiki_url_desc=Los visitantes serán redireccionados a la URL cuando hagan click en la barra.
settings.issues_desc=Habilitar tracker ligero de incidencias
settings.issues_desc=Habilitar rastreo de incidencias
settings.use_internal_issue_tracker=Usar rastreo de incidencias ligero incluido
settings.use_external_issue_tracker=Usar tracker externo de incidencias
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Formato URL del tracker de incidencias externo
settings.tracker_issue_style=Estilo de etiquetado del tracker externo de incidencias:
settings.tracker_issue_style.numeric=Numérico <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alfanumérico <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style.numeric=Numérico
settings.tracker_issue_style.alphanumeric=Alfanumérico
settings.tracker_url_format_desc=Puedes usar las plantillas <code>{user} {repo} {index}</code> para el nombre de usuario, nombre del repositorio e índice de la incidencia.
settings.pulls_desc=Habilitar Pull Requests para aceptar contribuciones públicas
settings.danger_zone=Zona de Peligro
@@ -653,6 +732,8 @@ settings.event_send_everything=Necesito <strong>todo</strong>.
settings.event_choose=Déjeme elegir lo que necesito.
settings.event_create=Crear
settings.event_create_desc=Rama o etiqueta creada
settings.event_pull_request=Pull Request
settings.event_pull_request_desc=Pull request, abierta, cerrada, reabierta, editada, asignada, desasignada, con etiqueta actualizada, con etiqueta eliminada, o sincronizada.
settings.event_push=Push
settings.event_push_desc=Git push a un repositorio
settings.active=Activo
@@ -690,8 +771,8 @@ diff.show_unified_view=Unificar vista
diff.stats_desc=Se han <strong>modificado %d ficheros</strong> con <strong>%d adiciones</strong> y <strong>%d borrados</strong>
diff.bin=BIN
diff.view_file=Ver fichero
diff.file_supressed=El diff del archivo ha sido suprimido porque es demasiado grande
diff.too_many_files=Some files were not shown because too many files changed in this diff
diff.file_suppressed=La diferencia del archivo ha sido suprimido porque es demasiado grande
diff.too_many_files=Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio
release.releases=Releases
release.new_release=Nueva Release
@@ -722,6 +803,7 @@ release.deletion=Eliminar Release
release.deletion_desc=Eliminar este Release eliminará la etiqueta correspondiente. ¿Desea continuar?
release.deletion_success=¡El release ha sido eliminado correctamente!
release.tag_name_already_exist=Ya existe una Release con esta etiqueta.
release.tag_name_invalid=Nombre de la etiqueta no es válido.
release.downloads=Descargas
[org]
@@ -889,6 +971,7 @@ users.edit_account=Editar Cuenta
users.max_repo_creation=Límite máximo de repositorios
users.max_repo_creation_desc=(Configura a -1 para usar el límite global por defecto)
users.is_activated=Esta cuenta está activada
users.prohibit_login=Esta cuenta no tiene permitido ingresar
users.is_admin=Esta cuenta tiene permisos de administrador
users.allow_git_hook=Esta cuenta tiene permisos para crear hooks de Git
users.allow_import_local=Esta cuenta dispone de permisos para importar repositorios locales
@@ -957,6 +1040,7 @@ auths.delete_auth_title=Borrado de autenticación
auths.delete_auth_desc=Esta autenticación será eliminada. ¿Deseas continuar?
auths.still_in_used=Este método de autentificación aún es utilizado por algunos usuarios, por favor elimine o convierta estos usuarios a otro tipo de autentificación.
auths.deletion_success=¡La autenticación ha sido eliminada con éxito!
auths.login_source_exist=El origen de autenticación '%s' ya existe.
config.server_config=Configuración del servidor
config.app_name=Nombre de la Aplicación
@@ -967,6 +1051,7 @@ config.offline_mode=Modo Sin Conexión
config.disable_router_log=Deshabilitar Log del Router
config.run_user=Ejecutada como Usuario
config.run_mode=Modo de ejecución
config.git_version=Git Version
config.repo_root_path=Ruta del Repositorio
config.static_file_root_path=Ruta de los Ficheros Estáticos
config.log_file_root_path=Ruta de los Ficheros de Log
@@ -994,6 +1079,7 @@ config.db_ssl_mode=Modo SSL
config.db_ssl_mode_helper=(sólo para "postgres")
config.db_path=Ruta
config.db_path_helper=(para "sqlite3" y "tidb")
config.service_config=Configuración del servicio
config.register_email_confirm=Solicitar Confirmación por Correo Electrónico
config.disable_register=Deshabilitar el Registro
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Deshabilitar la comprobación de Tamaño Mínimo d
config.enable_captcha=Activar Captcha
config.active_code_lives=Habilitar Vida del Código
config.reset_password_code_lives=Restablecer Contraseña de Vida del Código
config.webhook_config=Configuración de Webhooks
config.queue_length=Tamaño de Cola de Envío
config.deliver_timeout=Timeout de Entrega
config.skip_tls_verify=Omitir la Verificación TLS
config.mailer_config=Configuración del servidor de correo
config.mailer_enabled=Activado
config.mailer_disable_helo=Desactivar HELO
@@ -1017,12 +1105,15 @@ config.mailer_user=Usuario
config.send_test_mail=Enviar email de prueba
config.test_mail_failed=Fallo al enviar el email de prueba a '%s': %v
config.test_mail_sent=El email de prueba ha sido enviado a '%s'.
config.oauth_config=Configuración OAuth
config.oauth_enabled=Activado
config.cache_config=Configuración de la Caché
config.cache_adapter=Adaptador de la Caché
config.cache_interval=Intervalo de la Caché
config.cache_conn=Conexión de la Caché
config.session_config=Configuración de la Sesión
config.session_provider=Proveedor de la Sesión
config.provider_config=Configuración del Proveedor
@@ -1032,9 +1123,24 @@ config.gc_interval_time=Intervalo de tiempo del GC
config.session_life_time=Tiempo de Vida de la Sesión
config.https_only=Sólo HTTPS
config.cookie_life_time=Tiempo de Vida de la Cookie
config.picture_config=Configuración de Imagen
config.picture_service=Servicio de Imágen
config.disable_gravatar=Desactivar Gravatar
config.enable_federated_avatar=Habilitar Avatares Federados
config.git_config=Configuración de Git
config.git_disable_diff_highlight=Desactivar resaltado de sintaxis del Diff
config.git_max_diff_lines=Líneas de Diff máximas (por un solo archivo)
config.git_max_diff_line_characters=Carácteres de Diff máximos (para una sola línea)
config.git_max_diff_files=Máximo de archivos de Diff (que se mostrarán)
config.git_gc_args=Argumentos de GC
config.git_migrate_timeout=Tiempo de espera de migración
config.git_mirror_timeout=Tiempo de espera de actualización de réplicas
config.git_clone_timeout=Tiempo de espera de operación de clones
config.git_pull_timeout=Tiempo de espera de operación de pull
config.git_gc_timeout=Tiempo de espera de operación de GC
config.log_config=Configuración del Log
config.log_mode=Modo del Log
@@ -1096,7 +1202,7 @@ hours=%[2]s %[1]d horas
days=%[2]s %[1]d días
weeks=%[2]s %[1]d semanas
months=%[2]s %[1]d meses
years=%s %d años
years=%[2]s %[1]d años
raw_seconds=segundos
raw_minutes=minutos

View File

@@ -96,6 +96,8 @@ offline_mode=Ota käyttöön Offline tila
offline_mode_popup=Poista käytöstä CDN myös tuotanto tilassa, kaikki resurssi tiedostot palvellaan paikallisesti.
disable_gravatar=Poista käytöstä Gravatar palvelu
disable_gravatar_popup=Poista käytöstä Gravatar ja mukautetut lähteet, kaikki profiilikuvat on käyttäjien palvelimelle lähettämiä tai oletus.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Poista käytöstä itse-rekisteröinti
disable_registration_popup=Poista käyttäjän itse rekisteröinti, vain ylläpito voi luoda tilejä.
enable_captcha=Ota käyttöön Captcha
@@ -114,6 +116,7 @@ sqlite3_not_available=Julkaisu versiosi ei tue SQLite3, ole hyvä ja lataa viral
invalid_db_setting=Tietokanta asetus ei ole oikea: %v
invalid_repo_path=Repo juuri polku on virheellinen: %v
run_user_not_match=Suoritus käyttäjä ei ole nykyinen käyttäjä: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Asetuksien tallennus epäonnistui: %v
invalid_admin_setting=Ylläpito tili asetus virheellinen: %v
install_success=Tervetuloa! Olemme iloisia että valitsit Gogs, pidä hauskaa ja pidä huolta itsestäsi.
@@ -124,6 +127,7 @@ uname_holder=Käyttäjätunnus tai sähköposti
password_holder=Salasana
switch_dashboard_context=Vaihda kojelaudan kontekstia
my_repos=Reponi
show_more_repos=Show more repositories...
collaborative_repos=Yhteistyö repot
my_orgs=Organisaationi
my_mirrors=Peilini
@@ -133,8 +137,9 @@ issues.in_your_repos=Repoissasi
[explore]
repos=Repot
users=Users
search=Search
users=Käyttäjät
organizations=Organisaatiot
search=Hae
[auth]
create_new_account=Luo uusi tili
@@ -148,10 +153,11 @@ forget_password=Unohtuiko salasana?
sign_up_now=Tarvitsetko tilin? Rekisteröidy nyt.
confirmation_mail_sent_prompt=Uusi varmistus sähköposti on lähetetty osoitteeseen <b>%s</b>, ole hyvä ja tarkista saapuneet seuraavan %d tunnin sisällä saadaksesi rekisteröintiprosessin valmiiksi.
active_your_account=Aktivoi tilisi
prohibit_login=Kirjautuminen kielletty
prohibit_login_desc=Your account is prohibited to login, please contact site admin.
resent_limit_prompt=Sori, olet jo tilannut aktivointi sähköpostin lähiaikoina. Ole hyvä ja odota 3 minuuttia ja yritä sitten uudelleen.
has_unconfirmed_mail=Hei %s, sinulla on varmistamaton sähköposti osoite (<b>%s</b>). Jos et ole saanut varmistus sähköpostia tai tarvitset uudelleenlähetyksen, ole hyvä ja klikkaa allaolevaa painiketta.
resend_mail=Klikkaa tästä uudelleenlähettääksesi aktivointi sähköpostisi
email_not_associate=Tätä sähköposti osoitetta ei ole liitetty mihinkään tiliin.
send_reset_mail=Klikkaa tästä (uudelleen)lähettääksesi salasanan nollaus sähköpostin
reset_password=Nollaa salasanasi
invalid_code=Sori, varmistuskoodisi on vanhentunut tai väärä.
@@ -184,6 +190,13 @@ TeamName=Tiimin nimi
AuthName=Luvan nimi
AdminEmail=Ylläpito sähköposti
NewBranchName=New branch name
CommitSummary=Commit summary
CommitMessage=Commit message
CommitChoice=Commit choice
TreeName=Tiedostopolku
Content=Sisältö
require_error=` ei voi olla tyhjä.`
alpha_dash_error=` täytyy olla kirjaimia tai numeroita tai väliviiva(-_) merkkejä.`
alpha_dash_dot_error=` täytyy olla kirjaimia tai numeroita tai väliviiva(-_) tai piste merkkejä.`
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=Käyttäjätunnus mallia '%s' ei ole sallittu.
[settings]
profile=Profiili
password=Salasana
avatar=Avatar
ssh_keys=SSH avaimet
social=Sosiaaliset tilit
applications=Sovellukset
@@ -256,6 +270,8 @@ change_username_prompt=Tämä muutos vaikuttaa tapaan kuinka linkit liittyvät t
continue=Jatka
cancel=Peruuta
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=Ota käyttöön mukautettu profiilikuva
choose_new_avatar=Valitse uusi profiilikuva
update_avatar=Päivitä profiilikuva asetus
@@ -322,6 +338,10 @@ access_token_deletion=Henkilökohtaisen pääsymerkin poisto
access_token_deletion_desc=Tämän henkilökohtaisen pääsymerkin poistaminen poistaa kaikki siihen liittyvät pääsyt sovellukseen. Haluatko jatkaa?
delete_token_success=Henkilökohtainen pääsymerkki on poistettu onnistuneesti! Älä unohda päivittää sovellustasi myös.
orgs.none=You are not a member of any organizations.
orgs.leave_title=Leave an organization
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account=Poista tilisi
delete_prompt=Toiminto poistaa tilisi pysyvästi ja tätä <strong>EI VOI</strong> peruuttaa myöhemmin!
confirm_delete_account=Varmista poisto
@@ -342,7 +362,7 @@ fork_from=Forkkaa lähteestä
fork_visiblity_helper=Et voi muuttaa forkatun repon näkyvyyttä.
repo_desc=Kuvaus
repo_lang=Kieli
repo_lang_helper=Valitse .gitignore tiedostot
repo_gitignore_helper=Select .gitignore templates
license=Lisenssi
license_helper=Valitse lisenssitiedosto
readme=Lueminut-tiedosto
@@ -355,6 +375,7 @@ mirror_prune_desc=Remove any remote-tracking references that no longer exist on
mirror_interval=Peili aikaväli (tuntia)
mirror_address=Peili osoite
mirror_address_desc=Ole hyvä ja liitä osoitteeseen tarvittavat käyttäjätunnukset.
mirror_last_synced=Last Synced
watchers=Tarkkailijat
stargazers=Tähtiharrastajat
forks=Haarat
@@ -368,7 +389,8 @@ migrate_type=Siirtotyyppi
migrate_type_helper=Tämä repo tulee olemaan <span class="text blue">peili</span>
migrate_repo=Siirrä repo
migrate.clone_address=Kloonaa osoite
migrate.clone_address_desc=Tämä voi olla HTTP/HTTPS/GIT URL tai paikallisen palvelimen polku.
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=Sinun ei sallita tuovan paikallisia repoja.
migrate.invalid_local_path=Virheellinen paikallinen polku, ei ole olemassa tai ei ole hakemisto.
migrate.failed=Siirto epäonnistui: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Luo uusi repo komentoriviltä
push_exist_repo=Työnnä olemassaoleva repo komentoriviltä
repo_is_empty=Tämä repo on tyhjä, ole hyvä ja tule takaisin myöhemmin!
code=Koodi
files=Files
branch=Branch
tree=Puu
filter_branch_and_tag=Suodata haara tai tagi
@@ -409,6 +431,47 @@ file_raw=Raaka
file_history=Historia
file_view_raw=Näytä raaka
file_permalink=Pysyvä linkki
file_too_large=This file is too large to be shown
video_not_supported_in_browser=Your browser doesn't support HTML5 video tag.
editor.new_file=Uusi tiedosto
editor.upload_file=Liitä tiedosto
editor.edit_file=Muokkaa tiedostoa
editor.preview_changes=Muutosten esikatselu
editor.cannot_edit_non_text_files=Cannot edit non-text files
editor.edit_this_file=Edit this file
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
editor.fork_before_edit=You must fork this repository before editing the file
editor.delete_this_file=Poista tämä tiedosto
editor.must_have_write_access=Sinulla on kirjoitusoikeus tai ehdottaa muutoksia tiedostoon
editor.file_delete_success=Tiedosto "%s" on poistettu onnistuneesti!
editor.name_your_file=Nimeä tiedostosi...
editor.filename_help=Lisää hakemisto, kirjoita se ja paina /. Poista hakemisto, siirry kentän alkuun ja paina ASKELPALAUTINTA.
editor.or=tai
editor.cancel_lower=peruuta
editor.commit_changes=Vahvista muutokset
editor.add_tmpl=Lisää '%s/<filename>'
editor.add=Lisää "%s"
editor.update=Päivitä '%s'
editor.delete=Poista "%s"
editor.commit_message_desc=Add an optional extended description...
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
editor.new_branch_name_desc=New branch name...
editor.cancel=Peruuta
editor.filename_cannot_be_empty=Filename cannot be empty.
editor.branch_already_exists=Branch '%s' already exists in this repository.
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
editor.file_is_a_symlink=The file '%s' is a symlink that cannot be modified from the web editor.
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
editor.file_already_exists=A file with name '%s' already exists in this repository.
editor.no_changes_to_show=There are no changes to show.
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
editor.add_subdir=Add subdirectory...
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
editor.upload_files_to_dir=Upload files to '%s'
commits.commits=Commitit
commits.search=Etsi commiteista
@@ -435,6 +498,11 @@ issues.create=Ilmoita ongelma
issues.new_label=Uusi tunniste
issues.new_label_placeholder=Tunnisteen nimi...
issues.create_label=Luo tunniste
issues.label_templates.title=Load a predefined set of labels
issues.label_templates.info=There arent any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
issues.label_templates.helper=Select a label set
issues.label_templates.use=Use this label set
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
issues.open_tab=%d avoinna
issues.close_tab=%d suljettu
issues.filter_label=Tunniste
@@ -462,7 +530,8 @@ issues.next=Seuraava
issues.open_title=Avoinna
issues.closed_title=Suljettu
issues.num_comments=%d kommenttia
issues.commented_at=`kommentoi <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`commented <a href="#%s">%s</a>`
issues.delete_comment_confirm=Are you sure you want to delete this comment?
issues.no_content=Sisältöä ei vielä ole.
issues.close_issue=Sulje
issues.close_comment_issue=Kommentoi ja sulje
@@ -475,8 +544,7 @@ issues.commit_ref_at=`viittasi tähän ongelmaan commitissa <a id="%[1]s" href="
issues.poster=Tekijä
issues.collaborator=Yhteistyökumppani
issues.owner=Omistaja
issues.sign_up_for_free=Rekisteröidy ilmaiseksi
issues.sign_in_require_desc=liittyäksesi tähän keskusteluu. Onko sinulla jo tili? <a href="%s">Kirjaudu sisään kommentoidaksesi</a>
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
issues.edit=Muokkaa
issues.cancel=Peruuta
issues.save=Tallenna
@@ -491,6 +559,8 @@ issues.label_deletion=Tunnisteen poistaminen
issues.label_deletion_desc=Tämän tunnisteen poistaminen poistaa sen tiedot kaikista siihen liittyvistä ongelmista. Haluatko jatkaa?
issues.label_deletion_success=Tunniste on poistettu onnistuneesti!
issues.num_participants=%d osallistujaa
issues.attachment.open_tab=`Click to see "%s" in a new tab`
issues.attachment.download=`Click to download "%s"`
pulls.new=Uusi pull pyyntö
pulls.compare_changes=Vertaa muutoksia
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Tätä pull-pyyntöä ei voi yhdistää automaattis
pulls.cannot_auto_merge_helper=Ole hyvä ja yhdistä manuaalisesti konfliktien ratkaisemiseksi.
pulls.merge_pull_request=Yhdistä Pull-pyyntö
pulls.open_unmerged_pull_exists=`Et voi suorittaa uudelleenavaus toimintoa koska on jo olemassa pull-pyyntö (#%d) samasta reposta samoilla yhdistämistiedoilla ja odottaa yhdistämistä.`
pulls.delete_branch=Delete Branch
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence.
milestones.new=Uusi merkkipaalu
milestones.open_tab=%d avoinna
@@ -570,20 +642,27 @@ settings.collaboration.undefined=Undefined
settings.hooks=Webkoukut
settings.githooks=Git koukut
settings.basic_settings=Perusasetukset
settings.mirror_settings=Mirror Settings
settings.sync_mirror=Sync Now
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
settings.site=Virallinen sivusto
settings.update_settings=Päivitä asetukset
settings.change_reponame_prompt=Tämä muutos vaikuttaa siihen miten linkit liittyvät repoon.
settings.advanced_settings=Lisäasetukset
settings.wiki_desc=Ota käyttöön wiki salliaksesi ihmisten kirjoittaa asiakirjoja
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Käytä ulkoista wikiä
settings.external_wiki_url=Ulkoinen Wiki URL
settings.external_wiki_url_desc=Vierailijat uudelleenohjataan URL-osoitteeseen kun he klikkaavat välilehteä.
settings.issues_desc=Ota käyttöön sisäänrakennettu kevyt vikaseuranta
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=Käytä ulkoista vikaseurantaa
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Ulkoisen vikaseurannan URL muoto
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style.numeric=Numeric
settings.tracker_issue_style.alphanumeric=Alphanumeric
settings.tracker_url_format_desc=Voit käyttää paikkamerkkiä <code>{user} {repo} {index}</code> käyttäjänimelle, reponimelle ja vikanumerolle.
settings.pulls_desc=Ota käyttöön pull-pyynnöt salliaksesi julkiset koodilahjoitukset
settings.danger_zone=Vaaravyöhyke
@@ -653,6 +732,8 @@ settings.event_send_everything=Tarvitsen <strong>kaiken</strong>.
settings.event_choose=Haluan valita, mitä tarvitsen.
settings.event_create=Luo
settings.event_create_desc=Branch, tai tagi luotu
settings.event_pull_request=Pull Request
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
settings.event_push=Push
settings.event_push_desc=Git push repoon
settings.active=Aktiivinen
@@ -690,7 +771,7 @@ diff.show_unified_view=Yhdistetty näkymä
diff.stats_desc=<strong>%d muutettua tiedostoa</strong> jossa <strong>%d lisäystä</strong> ja <strong>%d poistoa</strong>
diff.bin=BIN
diff.view_file=Näytä tiedosto
diff.file_supressed=File diff supressed because it is too large
diff.file_suppressed=File diff suppressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=Julkaisut
@@ -722,6 +803,7 @@ release.deletion=Version poisto
release.deletion_desc=Tämän version poistaminen poistaa vastaavan Git tagin. Haluatko jatkaa?
release.deletion_success=Versio on poistettu onnistuneesti!
release.tag_name_already_exist=Versio tällä taginimellä on jo olemassa.
release.tag_name_invalid=Tag name is not valid.
release.downloads=Lataukset
[org]
@@ -889,6 +971,7 @@ users.edit_account=Muokkaa tiliä
users.max_repo_creation=Maksimi repojen määrä jonka voi luoda
users.max_repo_creation_desc=(Aseta -1 käyttääksesi globaalia oletusrajaa)
users.is_activated=Tämä tili on aktivoitu
users.prohibit_login=This account is prohibited to login
users.is_admin=Tällä tilillä on ylläpito-oikeudet
users.allow_git_hook=Tällä tilillä on oikeudet luoda Git koukkuja
users.allow_import_local=Tällä tilillä on oikeudet tuoda paikallisia repoja
@@ -957,6 +1040,7 @@ auths.delete_auth_title=Todennuksen poistaminen
auths.delete_auth_desc=Tämä todennus poistetaan, haluatko jatkaa?
auths.still_in_used=Tämä todennus on yhä joidenkin käyttäjien käytössä, ole hyvä ja poista tai muunna nämä käyttäjät toiselle kirjaututumistyypille ensin.
auths.deletion_success=Todennus on poistettu onnistuneesti!
auths.login_source_exist=Login source '%s' already exists.
config.server_config=Palvelin asetukset
config.app_name=Sovellus nimi
@@ -967,6 +1051,7 @@ config.offline_mode=Offline-tila
config.disable_router_log=Poista käytöstä reitittimen loki
config.run_user=Suorita käyttäjänä
config.run_mode=Suoritustila
config.git_version=Git Version
config.repo_root_path=Repon juuren polku
config.static_file_root_path=Staattisen tiedoston juuren polku
config.log_file_root_path=Lokitiedoston juuren polku
@@ -994,6 +1079,7 @@ config.db_ssl_mode=SSL tila
config.db_ssl_mode_helper=(vain "postgres")
config.db_path=Polku
config.db_path_helper=("sqlite3" ja "tidb")
config.service_config=Palvelu asetukset
config.register_email_confirm=Vaadi sähköpostivahvistus
config.disable_register=Poista käytöstä rekisteröinti
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Poista käytöstä avaimen vähimmäiskoko tarkist
config.enable_captcha=Ota käyttöön Captcha
config.active_code_lives=Aktiivinen koodi elämät ennen vanhenemista
config.reset_password_code_lives=Nollaa salasana koodi elämät
config.webhook_config=Webkoukku asetukset
config.queue_length=Jonon pituus
config.deliver_timeout=Toimitus aikakatkaisu
config.skip_tls_verify=Ohita TLS tarkistaminen
config.mailer_config=Sähköpostipalvelin asetukset
config.mailer_enabled=Käytössä
config.mailer_disable_helo=Poista käytöstä HELO
@@ -1017,12 +1105,15 @@ config.mailer_user=Käyttäjä
config.send_test_mail=Lähetä testi sähköposti
config.test_mail_failed=Testi sähköpostin lähettäminen vastaanottajalle '%s': %v epäonnistui
config.test_mail_sent=Testi sähköposti on lähetetty vastaanottajalle '%s'.
config.oauth_config=OAuth asetukset
config.oauth_enabled=Käytössä
config.cache_config=Välimuistin asetukset
config.cache_adapter=Välimuistin sovitin
config.cache_interval=Välimuistin aikaväli
config.cache_conn=Välimuistin yhteys merkkijono
config.session_config=Istunnon asetukset
config.session_provider=Istunnon toimittaja
config.provider_config=Toimittajan asetukset
@@ -1032,9 +1123,24 @@ config.gc_interval_time=GC aikaväli aika
config.session_life_time=Istunnon elinikä
config.https_only=Vain HTTPS
config.cookie_life_time=Evästeen elinikä
config.picture_config=Kuva asetukset
config.picture_service=Kuva palvelu
config.disable_gravatar=Poista käytöstä Gravatar
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Loki asetukset
config.log_mode=Loki tila

View File

@@ -96,6 +96,8 @@ offline_mode=Activer le mode hors connexion
offline_mode_popup=Désactiver le CDN, même en production. Toutes les ressources seront distribuées en local.
disable_gravatar=Désactiver le service Gravatar
disable_gravatar_popup=Désactiver Gravatar et les sources personnalisées, tous les avatars sont téléchargés par les utilisateurs ou par défaut.
federated_avatar_lookup=Activer les recherches d'avatars unifiés
federated_avatar_lookup_popup=Activer la recherche unifiée d'avatars en utilisant le service open source unifié basé sur libravatar.
disable_registration=Désactiver le formulaire d'inscription
disable_registration_popup=Désactiver le formulaire d'inscription, seuls les administrateurs peuvent créer des comptes.
enable_captcha=Activez le Captcha
@@ -113,17 +115,19 @@ test_git_failed=Le test de la commande "git" a échoué : %v
sqlite3_not_available=Votre version publiée ne prend pas en charge SQLite3. Veuillez télécharger la version binaire officielle à cette adresse %s.
invalid_db_setting=Paramètres de base de données incorrects : %v
invalid_repo_path=Chemin vers la racine du dépôt invalide : %v
run_user_not_match=L'utilisateur entré n'est pas l'utilisateur actuel : %s -> %s
run_user_not_match=L'utilisateur d'exécution saisi n'est pas l'utilisateur d'exécution actuel : %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=La sauvegarde de la configuration a échoué : %v
invalid_admin_setting=Paramètres du compte administrateur invalides : %v
install_success=Bienvenue ! Nous sommes heureux que vous ayez choisi Gogs, amusez-vous et prenez soin de vous.
invalid_log_root_path=Le chemin principal des fichiers logs est invalide: %v
invalid_log_root_path=L'emplacement racine des fichiers logs est invalide : %v
[home]
uname_holder=Nom d'utilisateur ou e-mail
password_holder=Mot de passe
switch_dashboard_context=Basculer le Contexte du Tableau de Bord
switch_dashboard_context=Basculer le contexte du tableau de bord
my_repos=Mes dépôts
show_more_repos=Afficher plus de dépôts...
collaborative_repos=Dépôts collaboratifs
my_orgs=Mes organisations
my_mirrors=Mes miroirs
@@ -134,6 +138,7 @@ issues.in_your_repos=Dans vos dépôts
[explore]
repos=Dépôts
users=Utilisateurs
organizations=Organisations
search=Rechercher
[auth]
@@ -141,29 +146,30 @@ create_new_account=Créer un nouveau compte
register_hepler_msg=Déjà enregistré ? Connectez-vous !
social_register_hepler_msg=Déjà enregistré ? Associez-le !
disable_register_prompt=Désolé, les enregistrements ont été désactivés. Veuillez contacter l'administrateur du site.
disable_register_mail=Désolé, la Confirmation par Mail des Enregistrements a été désactivée.
disable_register_mail=Désolé, la confirmation par e-mail des enregistrements a été désactivée.
remember_me=Se souvenir de moi
forgot_password=Mot de passe oublié
forget_password=Mot de passe oublié ?
sign_up_now=Pas de compte ? Inscrivez-vous maintenant.
confirmation_mail_sent_prompt=Un nouveau mail de confirmation à été envoyé à <b>%s</b>. Veuillez vérifier votre boîte de réception dans un délai de %d heures pour compléter votre enregistrement.
active_your_account=Activer votre compte
prohibit_login=Connexion interdite
prohibit_login_desc=Votre compte est interdit de se connecter, contactez ladministrateur du site.
resent_limit_prompt=Désolé, vos tentatives d'activation sont trop fréquentes. Veuillez réessayer dans 3 minutes.
has_unconfirmed_mail=Bonjour %s, votre adresse e-mail (<b>%s</b>) n'a pas été confirmée. Si vous n'avez reçu aucun mail de confirmation ou souhaitez renouveler l'envoi, cliquez sur le bouton ci-dessous.
resend_mail=Cliquez ici pour renvoyer un mail de confirmation
email_not_associate=Cette adresse e-mail n'est associée à aucun compte.
send_reset_mail=Cliquez ici pour (r)envoyer le mail de réinitialisation du mot de passe
reset_password=Réinitialiser le mot de passe
invalid_code=Désolé, votre code de confirmation est invalide ou a expiré.
reset_password_helper=Cliquez ici pour réinitialiser votre mot de passe
password_too_short=Le mot de passe doit contenir 6 caractères minimum.
non_local_account=Les comptes non-locaux ne peuvent pas changer leur mot de passe via Gogs.
non_local_account=Les comptes non locaux ne peuvent pas changer leur mot de passe via Gogs.
[mail]
activate_account=Veuillez activer votre compte
activate_email=Veuillez vérifier votre adresse e-mail
reset_password=Réinitialiser votre mot de passe
register_success=Succès de l'enregistrement, Bienvenue
register_success=Inscription réussie, bienvenue
register_notify=Bienvenue à bord
[modal]
@@ -174,19 +180,26 @@ modify=Modifier
[form]
UserName=Nom d'utilisateur
RepoName=Nom du dépôt
Email=Adresse E-mail
Email=Adresse e-mail
Password=Mot de passe
Retype=Confirmez le mot de passe
SSHTitle=Nom de la clé SSH
HttpsUrl=URL HTTPS
PayloadUrl=URL des Données Utiles
TeamName=Nom d'équipe
PayloadUrl=URL des données utiles
TeamName=Nom de l'équipe
AuthName=Nom d'autorisation
AdminEmail=E-mail de l'administrateur
require_error=` Ne peut être vide `
alpha_dash_error=` doivent être des caractères alpha, numeriques ou console (-_) valides `
alpha_dash_dot_error=` doivent être des caractères alpha, numeriques, console (-_) valides ou des points `
NewBranchName=Nouveau nom de la branche
CommitSummary=Résumé du commit
CommitMessage=Message de commit
CommitChoice=Choix de commit
TreeName=Chemin du fichier
Content=Contenu
require_error=` ne peut pas être vide.`
alpha_dash_error=` doivent être des caractères alpha, numériques ou tirets (-_) valides.`
alpha_dash_dot_error=` doivent être des caractères alpha, numériques, tirets (-_) valides ou des points.`
size_error=` doit être à la taille de %s.`
min_size_error=` %s caractères minimum `
max_size_error=` %s caractères maximum `
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=Motif '%s' interdit pour les noms d'utilisateur.
[settings]
profile=Profil
password=Mot de Passe
avatar=Avatar
ssh_keys=Clés SSH
social=Réseaux Sociaux
applications=Applications
@@ -256,6 +270,8 @@ change_username_prompt=Cette modification affectera la manière dont les liens s
continue=Continuer
cancel=Annuler
lookup_avatar_by_mail=Recherche d'avatar par email
federated_avatar_lookup=Recherche d'avatars unifiés
enable_custom_avatar=Activer l'avatar personnalisé
choose_new_avatar=Sélectionner un nouvel avatar
update_avatar=Mettre à jour l'avatar
@@ -322,6 +338,10 @@ access_token_deletion=Suppression du jeton d'accès
access_token_deletion_desc=Supprimer ce jeton d'accès supprimera tous les accès de l'application. Voulez-vous continuer ?
delete_token_success=Le jeton d'accèsa été supprimé avec succès ! N'oubliez pas de mettre à jour vos applications.
orgs.none=You are not a member of any organizations.
orgs.leave_title=Leave an organization
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account=Supprimer votre compte
delete_prompt=Votre compte sera définitivement supprimé et cette opération est <strong>irréversible</strong> !
confirm_delete_account=Confirmer la suppression
@@ -342,7 +362,7 @@ fork_from=Fork de
fork_visiblity_helper=La visibilité d'un fork ne peut pas être modifiée.
repo_desc=Description
repo_lang=Langue
repo_lang_helper=Sélectionnez les fichiers .gitignore
repo_gitignore_helper=Choisissez un modèle de fichier .gitignore
license=Licence
license_helper=Sélectionner un fichier de licence
readme=Fichier Readme
@@ -351,10 +371,11 @@ auto_init=Initialiser ce dépôt avec le modèle et les fichiers sélectionnés
create_repo=Créer un dépôt
default_branch=Branche par défaut
mirror_prune=Purger
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_prune_desc=Supprimez toute référence de suivi à distance qui n'existe plus sur le dépôt distant
mirror_interval=Intervalle du miroir (heure)
mirror_address=Adresse du miroir
mirror_address_desc=Veuillez inclure les informations d'identification nécessaires dans l'adresse.
mirror_last_synced=Dernière synchronisation
watchers=Observateurs
stargazers=Stargazers
forks=Forks
@@ -368,7 +389,8 @@ migrate_type=Type de migration
migrate_type_helper=Ce dépôt sera un <span class="text blue"> miroir</span>
migrate_repo=Migrer le dépôt
migrate.clone_address=Adresse du clone
migrate.clone_address_desc=Cela peut être une URL HTTP/HTTPS/GIT ou un chemin d'accès local.
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=Vous n'êtes pas autorisé à importer des dépôts locaux.
migrate.invalid_local_path=Chemin local non valide, non existant ou n'étant pas un dossier.
migrate.failed=Echec de migration: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Créer un nouveau dépôt en ligne de commande
push_exist_repo=Soumettre un dépôt existant par ligne de commande
repo_is_empty=Ce dépôt est vide, veuillez revenir plus tard !
code=Code
files=Files
branch=Branche
tree=Aborescence
filter_branch_and_tag=Filtrer une branche ou un tag
@@ -409,6 +431,47 @@ file_raw=Raw
file_history=Historique
file_view_raw=Voir le Raw
file_permalink=Lien permanent
file_too_large=Ce fichier est trop gros pour être afficher
video_not_supported_in_browser=Votre navigateur ne supporte pas la balise video HTML5.
editor.new_file=Nouveau fichier
editor.upload_file=Téléverser un fichier
editor.edit_file=Modifier fichier
editor.preview_changes=Aperçu des modifications
editor.cannot_edit_non_text_files=Impossible de modifier les fichiers non-texte
editor.edit_this_file=Modifier ce fichier
editor.must_be_on_a_branch=Vous devez être sur une branche pour appliquer ou proposer des modifications à ce fichier
editor.fork_before_edit=Vous devez fourcher ce dépôt avant de modifier le fichier
editor.delete_this_file=Supprimer ce fichier
editor.must_have_write_access=Vous devez avoir un accès en écriture pour appliquer ou proposer des modifications à ce fichier
editor.file_delete_success=Fichier '%s' a été supprimé avec succès!
editor.name_your_file=Nommez votre fichier...
editor.filename_help=Pour ajouter un répertoire, il suffit de le taper puis d'appuyer sur /. Pour supprimer un répertoire, aller au début du champ et appuyerz sur retour arrière.
editor.or=ou
editor.cancel_lower=annuler
editor.commit_changes=Commit les modifications
editor.add_tmpl=Ajouter '%s/<filename>'
editor.add=Ajouter '%s'
editor.update=Mettre à jour '%s'
editor.delete=Supprimer '%s'
editor.commit_message_desc=Ajouter une optionnelle description détaillée...
editor.commit_directly_to_this_branch=Soumettre directement à la branche <strong class="branch-name">%s</strong>.
editor.create_new_branch=Créer une <strong>nouvelle branche</strong> pour cette validation et envoyer une nouvelle pull request.
editor.new_branch_name_desc=Nouveau nom de la branche...
editor.cancel=Annuler
editor.filename_cannot_be_empty=Nom de fichier ne peut pas être vide.
editor.branch_already_exists=La branche '%s' existe déjà dans ce dépôt.
editor.directory_is_a_file=L'entrée '%s' dans le chemin daccès parent est un fichier pas un répertoire dans ce dépôt.
editor.file_is_a_symlink=Le fichier « %s » est un lien symbolique qui ne peut être modifié depuis l'éditeur web.
editor.filename_is_a_directory=Le nom de fichier '%s' existe déjà dans ce dépot.
editor.file_editing_no_longer_exists=Le fichier '%s' que vous modifiez n'existe plus dans le dépôt.
editor.file_changed_while_editing=Le contenu du fichier à changé depuis que vous avez commencé à l'éditer. <a target="_blank" href="%s">Cliquez ici</a> pour voir ce qui à été modifié ou <strong>appuyez sur commit encore une fois</strong> pour remplacer ces changements.
editor.file_already_exists=La branche '%s' existe déjà dans ce dépôt.
editor.no_changes_to_show=Il ny a aucun changement à afficher.
editor.fail_to_update_file=Échec lors de la mise à jour/création du fichier '%s' avec lerreur : %v
editor.add_subdir=Ajouter un sous-répertoire...
editor.unable_to_upload_files=Échec lors de l'envoie du fichier '%s' avec lerreur : %v
editor.upload_files_to_dir=Transférer les fichiers vers '%s'
commits.commits=Commits
commits.search=Rechercher des commits
@@ -423,18 +486,23 @@ issues.new=Nouveau ticket
issues.new.labels=Etiquettes
issues.new.no_label=Pas d'étiquette
issues.new.clear_labels=Effacer les étiquettes
issues.new.milestone=Étape
issues.new.no_milestone=Pas d'étape
issues.new.clear_milestone=Effacer l'étape
issues.new.open_milestone=Ouvrir l'étape
issues.new.milestone=Jalon
issues.new.no_milestone=Aucun jalon
issues.new.clear_milestone=Effacer le jalon
issues.new.open_milestone=Ouvrir un jalon
issues.new.closed_milestone=Jalons fermés
issues.new.assignee=Affecté à
issues.new.clear_assignee=Supprimer les assignataires
issues.new.no_assignee=Pas d'assignataire
issues.create=Créer un rapport de problème
issues.create=Créer un ticket
issues.new_label=Nouvelle étiquette
issues.new_label_placeholder=Nom de l'étiquette...
issues.create_label=Créer une étiquette
issues.label_templates.title=Charger un ensemble prédéfini d'étiquettes
issues.label_templates.info=Il n'y a pas encore d'étiquettes. Vous pouvez cliquer sur le bouton "Nouveau Label" ci-dessus pour créer une ou utiliser un ensemble prédéfini ci-dessous.
issues.label_templates.helper=Sélectionnez un ensemble d'étiquettes
issues.label_templates.use=Utilisez ce jeu d'étiquettes
issues.label_templates.fail_to_load_file=Impossible de charger le fichier de modèle étiquette '%s' : %v
issues.open_tab=%d Ouvert
issues.close_tab=%d Fermé
issues.filter_label=Étiquette
@@ -462,21 +530,21 @@ issues.next=Page Suivante
issues.open_title=Ouvert
issues.closed_title=Fermé
issues.num_comments=%d commentaires
issues.commented_at=`commenté à <a id="%[1]s" href="#%[1]s"> %[2]s</a>`
issues.commented_at=`a commenté <a href="#%s"> %s</a>`
issues.delete_comment_confirm=Êtes-vous certain de vouloir supprimer ce commentaire?
issues.no_content=Il n'existe pas encore de contenu.
issues.close_issue=Fermer
issues.close_comment_issue=Commenter et fermer
issues.reopen_issue=Réouvrir
issues.reopen_comment_issue=Commenter et réouvrir
issues.create_comment=Créer un commentaire
issues.closed_at=`fermé à <a id="%[1]s"href="#%[1]s"> %[2]s"</a>`
issues.closed_at=`fermé à <a id="%[1]s"href="#%[1]s"> %[2]s</a>`
issues.reopened_at=`réouvert à <a id="%[1]s" href="#%[1]s"> %[2]s</a>`
issues.commit_ref_at=`a référencé ce problème à partir d'un commit <a id="%[1]s" href="#%[1]s"> %[2]s</a>`
issues.poster=Publier
issues.collaborator=Collaborateur
issues.owner=Propriétaire
issues.sign_up_for_free=Inscrivez-vous gratuitement
issues.sign_in_require_desc=pour rejoindre cette conversation. Vous avez déjà un compte ? <a href="%s">Connectez-vous commenter</a>
issues.sign_in_require_desc=<a href="%s">Connectez-vous</a> pour rejoindre cette conversation.
issues.edit=Modifier
issues.cancel=Annuler
issues.save=Enregistrer
@@ -491,6 +559,8 @@ issues.label_deletion=Suppression du Label
issues.label_deletion_desc=Cette opération supprimera également toutes les informations relatives aux tickets. Voulez-vous continuer ?
issues.label_deletion_success=Label supprimé avec succès !
issues.num_participants=%d Participants
issues.attachment.open_tab=`Cliquez ici pour voir '%s' dans un nouvel onglet`
issues.attachment.download=`Cliquez pour télécharger "%s"`
pulls.new=Nouvelle Pull Request
pulls.compare_changes=Comparer les changements
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Cette pull request ne peut être fusionnée automat
pulls.cannot_auto_merge_helper=Fusionner manuellement afin de résoudre les conflits.
pulls.merge_pull_request=Fusionner la Pull Request
pulls.open_unmerged_pull_exists=`Vous ne pouvez effectuer une réouverture car il y a déjà une pull-request ouverte (#%d) depuis le même dépôt avec les mêmes informations de fusion et est en attente de fusion.`
pulls.delete_branch=Supprimer la branche
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence.
milestones.new=Nouveau Jalon
milestones.open_tab=%d Ouvert
@@ -570,20 +642,27 @@ settings.collaboration.undefined=Indéfini
settings.hooks=Webhooks
settings.githooks=Git Hooks
settings.basic_settings=Paramètres de base
settings.mirror_settings=Réglages Miroir
settings.sync_mirror=Synchroniser maintenant
settings.mirror_sync_in_progress=Synchronisation du miroir en cours, merci de rafraîchir la page dans une minute environ.
settings.site=Site officiel
settings.update_settings=Valider
settings.change_reponame_prompt=Ce changement affectera comment les liens sont reliés avec le dépôt.
settings.advanced_settings=Paramètres avancés
settings.wiki_desc=Activer le wiki pour permettre l'écriture de documents
settings.wiki_desc=Activer le wiki
settings.use_internal_wiki=Utiliser le wiki interne
settings.use_external_wiki=Utiliser un wiki externe
settings.external_wiki_url=URL Wiki externe
settings.external_wiki_url_desc=Les visiteurs seront redirigés vers cette URL lorsqu'ils cliqueront sur l'onglet.
settings.issues_desc=Activer le bug-tracker léger intégré
settings.issues_desc=Activer le système de tickets
settings.use_internal_issue_tracker=Utiliser le système simplifié de tickets interne
settings.use_external_issue_tracker=Utiliser un bug-tracker externe
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Format d'URL du bug tracker
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style=Style de nommage des bugs du tracker externe :
settings.tracker_issue_style.numeric=Numérique
settings.tracker_issue_style.alphanumeric=Alphanumérique
settings.tracker_url_format_desc=Vous pouvez utiliser l'espace réservé <code>{user} {repo} {index}</code> pour le nom d'utilisateur, le nom du dépôt et le numéro de bug.
settings.pulls_desc=Activer les pull requests pour accepter les contributions publiques
settings.danger_zone=Zone de danger
@@ -606,7 +685,7 @@ settings.delete=Supprimer ce dépôt
settings.delete_desc=Attention, cette action est action irréversible. Soyez sûr de vous.
settings.delete_notices_1=- Cette opération <strong>ne peut pas </strong> être annulée.
settings.delete_notices_2=- Cette opération supprimera définitivement le dépôt, y compris les données Git, les tickets, les commentaires et les accès des collaborateurs.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.delete_notices_fork_1=-Tous les forks deviendront indépendants après leffacement.
settings.deletion_success=Le dépôt a été supprimé avec succès!
settings.update_settings_success=Options mises à jour avec succès.
settings.transfer_owner=Nouveau propriétaire
@@ -653,6 +732,8 @@ settings.event_send_everything=J'ai besoin de <strong>tout</strong>.
settings.event_choose=Permettez-moi de choisir ce dont j'ai besoin.
settings.event_create=Créer
settings.event_create_desc=Branche, ou Tag créé
settings.event_pull_request=Pull Request
settings.event_pull_request_desc=Pull request ouvert, fermé, rouvert, édité, attribuée, non attribuées, étiquette mise à jour, étiquette désactivée ou synchronisé.
settings.event_push=Push
settings.event_push_desc=Git push vers un dépôt
settings.active=Actif
@@ -690,8 +771,8 @@ diff.show_unified_view=Vue unifiée
diff.stats_desc=<strong> %d fichiers modifiés</strong> avec <strong>%d ajouts</strong> et <strong>%d suppressions</strong>
diff.bin=BIN
diff.view_file=Voir le fichier
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
diff.file_suppressed=Fichier diff supprimé car celui-ci est trop grand
diff.too_many_files=Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff
release.releases=Versions
release.new_release=Nouvelle version
@@ -722,6 +803,7 @@ release.deletion=Suppression de la Version
release.deletion_desc=Supprimer cette version supprimera le tag Git correspondant. Voulez-vous continuer ?
release.deletion_success=La version à été supprimée avec succès !
release.tag_name_already_exist=Une version avec ce nom de tag existe déjà.
release.tag_name_invalid=Nom de tag invalide.
release.downloads=Téléchargements
[org]
@@ -889,6 +971,7 @@ users.edit_account=Modifier le Compte
users.max_repo_creation=Nombre maximum de dépôts créés
users.max_repo_creation_desc=(Mettre à -1 pour utiliser la limite globale par défaut)
users.is_activated=Ce compte est activé
users.prohibit_login=Ce compte est interdit de se connecter
users.is_admin=Ce compte possède un niveau d'accès administrateur
users.allow_git_hook=Ce compte dispose des autorisations pour créer des crochets de Git
users.allow_import_local=Ce compte dispose des permissions nécessaire à l'import des dépôts locaux
@@ -957,6 +1040,7 @@ auths.delete_auth_title=Suppression de l'authentification
auths.delete_auth_desc=Cette authentification va être supprimée. voulez-vous continuer ?
auths.still_in_used=Cette authentification est encore utilisée par d'autres utilisateurs, supprimez-les ou convertir ces utilisateurs vers un autre type de session, avant.
auths.deletion_success=L'authentification a été supprimée avec succès !
auths.login_source_exist=La source de connexion « %s » existe déjà.
config.server_config=Configuration du Serveur
config.app_name=Nom de l'application
@@ -967,6 +1051,7 @@ config.offline_mode=Mode hors-ligne
config.disable_router_log=Désactiver la Journalisation du Routeur
config.run_user=Utilisateur système
config.run_mode=Mode d'Éxécution
config.git_version=Git Version
config.repo_root_path=Emplacement des Dépôts
config.static_file_root_path=Chemin statique des fichiers racines
config.log_file_root_path=Emplacement Racine du Fichier Journal
@@ -994,6 +1079,7 @@ config.db_ssl_mode=Mode SSL
config.db_ssl_mode_helper=("postgres" uniquement)
config.db_path=Emplacement
config.db_path_helper=(pour « sqlite3 » et « TIDB »)
config.service_config=Configuration du Service
config.register_email_confirm=Nécessite une confirmation par e-mail
config.disable_register=Désactiver les inscriptions
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Désactiver la vérification de la taille de clé
config.enable_captcha=Activez le Captcha
config.active_code_lives=Limites de Code Actif
config.reset_password_code_lives=Réinitialiser le Mot De Passe des Limites de Code
config.webhook_config=Configuration Webhook
config.queue_length=Longueur de la file d'attente
config.deliver_timeout=Expiration d'Envoi
config.skip_tls_verify=Ne pas vérifier TLS
config.mailer_config=Configuration du service de mail
config.mailer_enabled=Activé
config.mailer_disable_helo=Désactiver HELO
@@ -1017,12 +1105,15 @@ config.mailer_user=Utilisateur
config.send_test_mail=Envoyer courriel de Test
config.test_mail_failed=Impossible d'envoyer un e-mail de test à '%s': %v
config.test_mail_sent=Un e-mail de test à été envoyé à '%s'.
config.oauth_config=Configuration OAuth
config.oauth_enabled=Activé
config.cache_config=Configuration du Cache
config.cache_adapter=Adaptateur du Cache
config.cache_interval=Intervales du Cache
config.cache_conn=Liaison du Cache
config.session_config=Configuration de session
config.session_provider=Fournisseur de session
config.provider_config=Configuration du fournisseur
@@ -1032,9 +1123,24 @@ config.gc_interval_time=Intervals GC
config.session_life_time=Durée des sessions
config.https_only=HTTPS uniquement
config.cookie_life_time=Expiration du cookie
config.picture_config=Configuration d'Image
config.picture_service=Service d'Imagerie
config.disable_gravatar=Désactiver Gravatar
config.enable_federated_avatar=Activer les avatars unifiés
config.git_config=Configuration de Git
config.git_disable_diff_highlight=Désactiver la surbrillance syntaxique de Diff
config.git_max_diff_lines=Lignes de Diff Max (pour un seul fichier)
config.git_max_diff_line_characters=Nombre max de caractères de Diff (pour une seule ligne)
config.git_max_diff_files=Nombre max de fichiers de Diff (à afficher)
config.git_gc_args=Arguments de GC
config.git_migrate_timeout=Délai imparti pour une migration
config.git_mirror_timeout=Délai imparti pour mettre à jour le miroir
config.git_clone_timeout=Délai imparti pour l'opération "Clone"
config.git_pull_timeout=Délai imparti pour l'opération "Pull"
config.git_gc_timeout=Délai imparti pour l'opération "GC"
config.log_config=Configuration du Journal
config.log_mode=Mode du journal
@@ -1065,8 +1171,8 @@ notices.delete_success=Notifications système supprimées avec succès.
[action]
create_repo=a créé le dépôt <a href="%s">%s</a>
rename_repo=rebaptisé le dépôt de <code>%[1]s</code> à <a href="%[2]s">%[3]s</a>
commit_repo=a soumis à <a href="%[1]s/src/%[2]s">%[3]s</a> sur <a href="%[1]s">%[4]s</a>
rename_repo=a rebaptisé le dépôt de <code>%[1]s</code> vers <a href="%[2]s">%[3]s</a>
commit_repo=a commité dans <a href="%[1]s/src/%[2]s">%[3]s</a> sur <a href="%[1]s">%[4]s</a>
create_issue=`a ouvert un problème <a href="%s/issues/%s">%s#%[2]s</a>`
close_issue=`tickets clos <a href="%s/issues/%s">%s#%[2]s</a>`
reopen_issue=`tickets ré-ouverts <a href="%s/issues/%s">%s#%[2]s</a>`
@@ -1080,23 +1186,23 @@ push_tag=a soumis le tag <a href="%s/src/%s">%[2]s</a> sur <a href="%[1]s">%[3]s
compare_commits=Comparer ces %d commits
[tool]
ago=auparavant
from_now=à partir de maintenant
ago=il y a
from_now=dans
now=maintenant
1s=1 seconde %s
1m=1 minute %s
1h=1 heure %s
1d=1 jour %s
1w=1 semaine %s
1mon=1 mois %s
1y=1 an %s
seconds=%d secondes %s
minutes=%d minutes %s
hours=%d heures %s
days=%d jours %s
weeks=%d semaines %s
months=%d mois %s
years=%d ans %s
1s=%s 1 seconde
1m=%s 1 minute
1h=%s 1 heure
1d=%s 1 jour
1w=%s 1 semaine
1mon=%s 1 mois
1y=%s 1 an
seconds=%[2]s %[1]d secondes
minutes=%[2]s %[1]d minutes
hours=%[2]s %[1]d heures
days=%[2]s %[1]d jours
weeks=%[2]s %[1]d semaines
months=%[2]s %[1]d mois
years=%[2]s %[1]d ans
raw_seconds=secondes
raw_minutes=minutes

1214
conf/locale/locale_gl-ES.ini Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -96,6 +96,8 @@ offline_mode=Abilita Modalità Offline
offline_mode_popup=Disabilita il CDN anche in modalità produttiva, tutte le risorse saranno servite localmente.
disable_gravatar=Disattiva il servizio Gravatar
disable_gravatar_popup=Disabilita Gravatar e sorgenti customizzate, tutti gli avatar vengono caricati dagli utenti o come predefinito.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Disabilita Registrazione Manuale
disable_registration_popup=Disabilita la registrazione manuale degli utenti, solo gli amministratori possono creare account.
enable_captcha=Abilita Captcha
@@ -114,6 +116,7 @@ sqlite3_not_available=Questa versione non supporta SQLite3, si prega di scaricar
invalid_db_setting=La configurazione del database non è corretta: %v
invalid_repo_path=Percorso root del repository invalido: %v
run_user_not_match=Run user non è l'utente corrente: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Fallito il salvataggio della configurazione: %v
invalid_admin_setting=Impostazioni account Admin non valide: %v
install_success=Benvenuto! Siamo felici che tu abbia scelto Gogs, buon divertimento.
@@ -124,6 +127,7 @@ uname_holder=Nome Utente o E-mail
password_holder=Password
switch_dashboard_context=Cambia Dashboard Context
my_repos=I miei Repository
show_more_repos=Visualizza altre repositories...
collaborative_repos=Repository Condivisi
my_orgs=Le mie Organizzazioni
my_mirrors=I miei Mirror
@@ -134,6 +138,7 @@ issues.in_your_repos=Nei tuoi repository
[explore]
repos=Repository
users=Utenti
organizations=Organizations
search=Cerca
[auth]
@@ -148,16 +153,17 @@ forget_password=Password dimenticata?
sign_up_now=Bisogno di un account? Iscriviti ora.
confirmation_mail_sent_prompt=Una nuova email di conferma è stata inviata a <b>%s</b>, verifica la tua casella di posta entro le prossime %d ore per completare la registrazione.
active_your_account=Attiva il tuo Account
prohibit_login=Accesso Vietato
prohibit_login_desc=Il tuo account è impossibilitato al login, contatta l'amministratore del sito.
resent_limit_prompt=Siamo spiacenti, si stanno inviando e-mail di attivazione troppo spesso. Si prega di attendere 3 minuti.
has_unconfirmed_mail=Ciao %s, hai un indirizzo di posta elettronica non confermato (<b>%s</b>). Se non hai ricevuto una e-mail di conferma o vuoi riceverla nuovamente, fare clic sul pulsante qui sotto.
resend_mail=Clicca qui per inviare nuovamente l'e-mail di attivazione
email_not_associate=Questo indirizzo e-mail non è associato ad alcun account.
send_reset_mail=Clicca qui per (ri)inviare la tua e-mail di reimpostazione password
reset_password=Reimposta la tua Password
invalid_code=Siamo spiacenti, il codice di conferma è scaduto o non valido.
reset_password_helper=Clicca qui per reimpostare la password
password_too_short=La lunghezza della password non può essere meno 6 caratteri.
non_local_account=Non-local accounts cannot change passwords through Gogs.
non_local_account=Gli account non locali non possono modificare le password tramite Gogs.
[mail]
activate_account=Per favore attiva il tuo account
@@ -184,6 +190,13 @@ TeamName=Nome Team
AuthName=Nome autorizzazione
AdminEmail=Email dell'Admin
NewBranchName=Nuovo nome del branch
CommitSummary=Riepilogo dei commit
CommitMessage=Messaggio di commit
CommitChoice=Scelta di commit
TreeName=Percorso del file
Content=Contenuto
require_error=` non può essere vuoto.`
alpha_dash_error=` ammessi solo caratteri alfanumerici o trattini(-_).`
alpha_dash_dot_error=` ammessi solo caratteri alfanumerici o trattini(-_) o punti.`
@@ -220,7 +233,7 @@ org_still_own_repo=Questa organizzazione ha ancora la proprietà del repository,
target_branch_not_exist=Il ramo (branch) di destinazione non esiste.
[user]
change_avatar=Change your avatar
change_avatar=Cambia il tuo avatar
join_on=Si è unito il
repositories=Repository
activity=Attività pubblica
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=La struttura del nome utente '%s' non è consentit
[settings]
profile=Profilo
password=Password
avatar=Avatar
ssh_keys=Chiavi SSH
social=Account Sociali
applications=Applicazioni
@@ -256,6 +270,8 @@ change_username_prompt=Questa modifica influenzerà il modo in cui i link si rif
continue=Continua
cancel=Annulla
lookup_avatar_by_mail=Ricerca Avatar per mail
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=Abilita avatar personalizzato
choose_new_avatar=Scegli un nuovo avatar
update_avatar=Aggiorna le impostazioni avatar
@@ -322,6 +338,10 @@ access_token_deletion=Eliminazione Token di accesso personale
access_token_deletion_desc=Eliminare questo token di accesso personale rimuoverà tutti i relativi accessi di applicazione. Si desidera continuare?
delete_token_success=Il token di accesso personale è stato eliminato! Non dimenticare di aggiornare anche l'applicazione.
orgs.none=You are not a member of any organizations.
orgs.leave_title=Leave an organization
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account=Elimina Account
delete_prompt=L'operazione eliminerà permanentemente l'account e <strong>NON POTRÀ</strong> essere annullata!
confirm_delete_account=Conferma Eliminazione
@@ -342,7 +362,7 @@ fork_from=Forka da
fork_visiblity_helper=Non puoi cambiare la visibilità di un repository forkato.
repo_desc=Descrizione
repo_lang=Lingua
repo_lang_helper=Seleziona file .gitignore
repo_gitignore_helper=Seleziona i templates di .gitignore
license=Licenza
license_helper=Selezionare un file di licenza
readme=Readme
@@ -350,11 +370,12 @@ readme_helper=Seleziona un template per il readme
auto_init=Inizializzare questo repository con i file e il modello selezionati
create_repo=Crea Repository
default_branch=Ramo (Branch) predefinito
mirror_prune=Prune
mirror_prune=Rimuovi
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=Intervallo Mirror (in ore)
mirror_address=Indirizzo del mirror
mirror_address_desc=Si prega di includere nell'indirizzo le credenziali utente necessarie.
mirror_last_synced=Last Synced
watchers=Osservatori
stargazers=Fan
forks=Fork
@@ -368,7 +389,8 @@ migrate_type=Tipo di migrazione
migrate_type_helper=Questo repository sarà un <span class="text blue">mirror</span>
migrate_repo=Migra Repository
migrate.clone_address=Duplica Indirizzo
migrate.clone_address_desc=Può essere un URL HTTP/HTTPS/GIT o il percorso del server locale.
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=Non è consentito importare repository locali.
migrate.invalid_local_path=Percorso locale non valido, non esiste o non è una cartella.
migrate.failed=Migrazione non riuscita: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Crea nuovo repository da riga di comando
push_exist_repo=Push un repo esistente dalla riga di comando
repo_is_empty=Questo repository è vuoto, si prega di tornare più tardi!
code=Codice
files=Files
branch=Ramo (Branch)
tree=Albero (Tree)
filter_branch_and_tag=Filtra per branch o tag
@@ -409,6 +431,47 @@ file_raw=Originale
file_history=Cronologia
file_view_raw=Vedi originale
file_permalink=Permalink
file_too_large=Questo file è troppo grande per essere mostrato
video_not_supported_in_browser=Your browser doesn't support HTML5 video tag.
editor.new_file=Nuovo file
editor.upload_file=Carica File
editor.edit_file=Modifica file
editor.preview_changes=Anteprima modifiche
editor.cannot_edit_non_text_files=Non è possibile modificare i file non di testo
editor.edit_this_file=Modifica questo file
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
editor.fork_before_edit=You must fork this repository before editing the file
editor.delete_this_file=Delete this file
editor.must_have_write_access=You must have write access to make or propose changes to this file
editor.file_delete_success=File '%s' has been deleted successfully!
editor.name_your_file=Name your file...
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
editor.or=or
editor.cancel_lower=cancel
editor.commit_changes=Commit Changes
editor.add_tmpl=Add '%s/<filename>'
editor.add=Add '%s'
editor.update=Update '%s'
editor.delete=Delete '%s'
editor.commit_message_desc=Add an optional extended description...
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
editor.new_branch_name_desc=New branch name...
editor.cancel=Cancel
editor.filename_cannot_be_empty=Filename cannot be empty.
editor.branch_already_exists=Branch '%s' already exists in this repository.
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
editor.file_is_a_symlink=The file '%s' is a symlink that cannot be modified from the web editor.
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
editor.file_already_exists=A file with name '%s' already exists in this repository.
editor.no_changes_to_show=There are no changes to show.
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
editor.add_subdir=Add subdirectory...
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
editor.upload_files_to_dir=Upload files to '%s'
commits.commits=Commits
commits.search=Ricerca una versione
@@ -435,6 +498,11 @@ issues.create=Crea Problema
issues.new_label=Nuova etichetta
issues.new_label_placeholder=Nome dell'etichetta...
issues.create_label=Crea Etichetta
issues.label_templates.title=Load a predefined set of labels
issues.label_templates.info=There arent any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
issues.label_templates.helper=Select a label set
issues.label_templates.use=Use this label set
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
issues.open_tab=%d Aperti
issues.close_tab=%d Chiusi
issues.filter_label=Etichetta
@@ -462,7 +530,8 @@ issues.next=Pagina successiva
issues.open_title=Aperto
issues.closed_title=Chiuso
issues.num_comments=%d commenti
issues.commented_at=`commented <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`commented <a href="#%s">%s</a>`
issues.delete_comment_confirm=Are you sure you want to delete this comment?
issues.no_content=Non ci sono ancora contenuti.
issues.close_issue=Chiudi
issues.close_comment_issue=Commenta e chiudi
@@ -475,8 +544,7 @@ issues.commit_ref_at=`referenced this issue from a commit <a id="%[1]s" href="#%
issues.poster=Autore
issues.collaborator=Collaboratori
issues.owner=Proprietario
issues.sign_up_for_free=Registrati gratuitamente
issues.sign_in_require_desc=per partecipare a questa conversazione. Possiedi già un account?<a href="%s">Fai il login per commentare</a>
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
issues.edit=Modifica
issues.cancel=Annulla
issues.save=Salva
@@ -491,6 +559,8 @@ issues.label_deletion=Elimina Etichetta
issues.label_deletion_desc=Eliminare l'etichetta rimuovera le sue informazioni in tutti i problemi correlati. Vuoi continuare?
issues.label_deletion_success=Etichetta eliminata con successo!
issues.num_participants=%d Partecipanti
issues.attachment.open_tab=`Click to see "%s" in a new tab`
issues.attachment.download=`Click to download "%s"`
pulls.new=Nuova Pull Request
pulls.compare_changes=Confronta le modifiche
@@ -509,7 +579,7 @@ pulls.tab_commits=Commit
pulls.tab_files=File modificati
pulls.reopen_to_merge=Riapri questa pull request per effettuare il merge.
pulls.merged=Unito
pulls.has_merged=Questa pull reqeust è stata mergiata con successo!
pulls.has_merged=Questo contributo è stato incluso con successo!
pulls.data_broken=I dati di questa pull request si sono rotti causa dell'eliminazione delle informazioni di fork.
pulls.is_checking=Il controllo dei conflitti è ancora in corso, per favore aggiorna pagina tra qualche istante.
pulls.can_auto_merge_desc=La pull request non può essere mergiata automaticamente.
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Questa pull request non può essere mergiata automa
pulls.cannot_auto_merge_helper=Effettua il merge manualmente per risolvere i conflitti.
pulls.merge_pull_request=Unisci Pull Request
pulls.open_unmerged_pull_exists=`You can't perform reopen operation because there is already an open pull request (#%d) from same repository with same merge information and is waiting for merging.`
pulls.delete_branch=Delete Branch
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence.
milestones.new=Nuova Milestone
milestones.open_tab=%d Aperti
@@ -570,20 +642,27 @@ settings.collaboration.undefined=Undefined
settings.hooks=Webhooks
settings.githooks=Git Hooks
settings.basic_settings=Impostazioni di Base
settings.mirror_settings=Mirror Settings
settings.sync_mirror=Sync Now
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
settings.site=Sito Ufficiale
settings.update_settings=Aggiorna Impostazioni
settings.change_reponame_prompt=Questa modifica influirà i link al repository.
settings.advanced_settings=Opzioni avanzate
settings.wiki_desc=Abilitare il wiki per consentire alle persone di scrivere documenti
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Usa Wiki esterno
settings.external_wiki_url=URL Wiki esterno
settings.external_wiki_url_desc=I visitatori verranno reindirizzati all'URL quando cliccano sulla scheda.
settings.issues_desc=Abilita l'issue tracker builtin leggero
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=Utilizza gestore di problemi esterno
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Formato URL Gestore Problemi Esterno
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style.numeric=Numeric
settings.tracker_issue_style.alphanumeric=Alphanumeric
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Abilita le pull requests per accettare contributi pubblici
settings.danger_zone=Zona Pericolosa
@@ -653,6 +732,8 @@ settings.event_send_everything=Ho bisogno di <strong>tutto</strong>.
settings.event_choose=Lasciami scegliere ciò di cui ho bisogno.
settings.event_create=Crea
settings.event_create_desc=Branch, o tag creato
settings.event_pull_request=Pull Request
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
settings.event_push=Push
settings.event_push_desc=Git push in un repository
settings.active=Attivo
@@ -690,7 +771,7 @@ diff.show_unified_view=Visualizzazione unificata
diff.stats_desc=<strong>%d ha cambiato i file</strong> con <strong>%d aggiunte</strong> e <strong>%d eliminazioni</strong>
diff.bin=BIN
diff.view_file=Vedi File
diff.file_supressed=File diff supressed because it is too large
diff.file_suppressed=File diff suppressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=Rilasci
@@ -722,6 +803,7 @@ release.deletion=Eliminazione Release
release.deletion_desc=Eliminando questa release cancellarai anche i tag Git corrispondenti. Vuoi continuare?
release.deletion_success=La release è stata eliminata con successo!
release.tag_name_already_exist=Un rilascio con questo tag esiste già.
release.tag_name_invalid=Tag name is not valid.
release.downloads=Download
[org]
@@ -889,6 +971,7 @@ users.edit_account=Modifica Account
users.max_repo_creation=Limite massimo per la creazione di Repository
users.max_repo_creation_desc=(Inserire -1 per usare il limite globale di default)
users.is_activated=Questo account è attivato
users.prohibit_login=This account is prohibited to login
users.is_admin=Questo account ha permessi di amministratore
users.allow_git_hook=Questo account ha il permesso di creare hooks di Git
users.allow_import_local=Questo account dispone delle autorizzazioni per importare repository locali
@@ -957,6 +1040,7 @@ auths.delete_auth_title=Authentication Deletion
auths.delete_auth_desc=This authentication is going to be deleted, do you want to continue?
auths.still_in_used=This authentication is still used by some users, please delete or convert these users to another login type first.
auths.deletion_success=Authentication has been deleted successfully!
auths.login_source_exist=Login source '%s' already exists.
config.server_config=Configurazione Server
config.app_name=Nome Applicazione
@@ -967,6 +1051,7 @@ config.offline_mode=Modalità Offline
config.disable_router_log=Disattivare Log del Router
config.run_user=Utente Esecutore
config.run_mode=Modalità Esecuzione
config.git_version=Git Version
config.repo_root_path=Percorso Root del Repository
config.static_file_root_path=Percorso Root del File Statico
config.log_file_root_path=Percorso Root del File di Log
@@ -994,6 +1079,7 @@ config.db_ssl_mode=Modalità SSL
config.db_ssl_mode_helper=(solo per "postgres")
config.db_path=Percorso
config.db_path_helper=(per "sqlite3" e "tidb")
config.service_config=Configurazione Servizio
config.register_email_confirm=Richiedono Conferma dell'Email
config.disable_register=Disabilita Registrazione
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Disabilita controllo sulle dimensioni minime della
config.enable_captcha=Abilita Captcha
config.active_code_lives=Attiva Vita del Codice
config.reset_password_code_lives=Reimpostare Password della Vita del Codice
config.webhook_config=Configurazione Webhook
config.queue_length=Lunghezza della coda
config.deliver_timeout=Tempo Limite di Consegna
config.skip_tls_verify=Salta verifiche TLS
config.mailer_config=Configurazione Mailer
config.mailer_enabled=Attivo
config.mailer_disable_helo=Disattiva HELO
@@ -1017,12 +1105,15 @@ config.mailer_user=Utente
config.send_test_mail=Invia email di test
config.test_mail_failed=Impossibile inviare mail a '%s': %v
config.test_mail_sent=Una mail di prova è stata inviata a '%s'.
config.oauth_config=Configurazione OAuth
config.oauth_enabled=Attivo
config.cache_config=Configurazione Cache
config.cache_adapter=Adattatore Cache
config.cache_interval=Intervallo Cache
config.cache_conn=Connessione Cache
config.session_config=Configurazione Sessione
config.session_provider=Fornitore Sessione
config.provider_config=Impostazioni Provider
@@ -1032,9 +1123,24 @@ config.gc_interval_time=Intervallo di tempo della GC
config.session_life_time=Durata Sessione
config.https_only=Solo HTTPS
config.cookie_life_time=Durata Cookie
config.picture_config=Configurazione Foto
config.picture_service=Servizio foto
config.disable_gravatar=Disabilita Gravatar
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Configurazione Log
config.log_mode=Modalità Log

View File

@@ -96,6 +96,8 @@ offline_mode=オフラインモードを有効にする
offline_mode_popup=プロダクションモードでは、CDNを使用せずにローカルからリソースファイルを使用します。
disable_gravatar=Gravatarのサービスを無効にします
disable_gravatar_popup=Gravatarとカスタムソースを無効にして、全てのアバターをユーザーによってアップロードされたものかデフォルトなものにします。
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=自己登録を無効にする
disable_registration_popup=自己登録を無効にし、管理者のみがアカウント作成できる
enable_captcha=Captchaを有効にする
@@ -114,6 +116,7 @@ sqlite3_not_available=このリリース バージョンは SQLite3 をサポー
invalid_db_setting=データベースの設定が正しくありません: %v
invalid_repo_path=リポジトリのルート パスが無効です: %v
run_user_not_match=実行ユーザーは、現在のユーザーではない: %s-> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=構成の保存に失敗した: %v
invalid_admin_setting=管理者アカウントの設定が無効です: %v
install_success=ようこそ!我々はあなたが Gogs を選んでくれて嬉しいです!楽しみましょう!
@@ -124,6 +127,7 @@ uname_holder=ユーザー名またはEメール
password_holder=パスワード
switch_dashboard_context=ダッシュ ボードのコンテキストを切替
my_repos=自分のリポジトリ
show_more_repos=リポジトリをさらに表示…
collaborative_repos=共同リポジトリ
my_orgs=自分の組織
my_mirrors=自分のミラー
@@ -134,6 +138,7 @@ issues.in_your_repos=あなたのリポジトリ
[explore]
repos=リポジトリ
users=ユーザ
organizations=組織
search=検索
[auth]
@@ -148,10 +153,11 @@ forget_password=パスワードを忘れましたか?
sign_up_now=アカウントが必要ですか?今すぐ登録しましょう!
confirmation_mail_sent_prompt=新しい確認メールを <b>%s</b> に送りました。登録を完了させるために、%d時間以内にあなたのメールボックスを確認してください。
active_your_account=アカウントを有効化
prohibit_login=ログイン禁止
prohibit_login_desc=あなたのアカウントはログインを禁止されています。サイト管理者にお問い合わせください。
resent_limit_prompt=申し訳ありませんが、アクティベーションメールは頻繁に送信しています。3 分お待ちください。
has_unconfirmed_mail=こんにちは %s さん、あなたの電子メール アドレス (<b>%s</b>) は未確認です。もし確認メールをまだ確認できていないか、改めて再送信する場合は、下のボタンをクリックしてください。
resend_mail=アクティベーションメールを再送信するにはここをクリック
email_not_associate=この電子メール アドレスは、アカウントには関連付けられません。
send_reset_mail=パスワードリセットのメールを再送するにはここをクリック
reset_password=パスワードリセット
invalid_code=申し訳ありませんが、確認用コードが期限切れまたは無効です。
@@ -184,6 +190,13 @@ TeamName=チーム名
AuthName=承認名
AdminEmail=管理者の電子メール
NewBranchName=新しいブランチ名
CommitSummary=Commit summary
CommitMessage=Commit message
CommitChoice=Commit choice
TreeName=File path
Content=コンテンツ
require_error=空にできません
alpha_dash_error=アルファベット、数字、ハイフン"-"、アンダースコア"_"のいずれかの必要があります
alpha_dash_dot_error=' アルファベット、数値、ダッシュ(-)、アンダースコア(_) 、ドット(.)のいずれかを入力する必要があります。 '
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=ユーザ名のパターン '%s' は許可され
[settings]
profile=プロフィール
password=パスワード
avatar=アバター
ssh_keys=SSH キー
social=SNSアカウント
applications=アプリケーション
@@ -256,6 +270,8 @@ change_username_prompt=この変更はリンクをアカウントに関連付け
continue=続行
cancel=キャンセル
lookup_avatar_by_mail=メールからアバターを取得
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=カスタムのアバターを有効にする
choose_new_avatar=新しいアバターを選択
update_avatar=アバターの設定を更新
@@ -322,6 +338,10 @@ access_token_deletion=パーソナルアクセストークンの削除
access_token_deletion_desc=パーソナルアクセストークンを削除すると、関連するアプリケーションのすべてのアクセスが削除されます。続行しますか?
delete_token_success=パーソナルアクセストークンは正常に削除されました!同時にあなたのアプリケーションを更新することを忘れないでください。
orgs.none=You are not a member of any organizations.
orgs.leave_title=Leave an organization
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account=アカウントを削除
delete_prompt=この操作をするとアカウントが完全に削除され、<strong>二度と元に戻すことができなくなります</strong>
confirm_delete_account=削除の確認
@@ -342,7 +362,7 @@ fork_from=フォーク元
fork_visiblity_helper=フォークされたリポジトリの可視状態は変更できません。
repo_desc=説明
repo_lang=言語
repo_lang_helper=.gitignoreファイルを選択
repo_gitignore_helper=Select .gitignore templates
license=ライセンス
license_helper=ライセンス ファイルを選択
readme=Readme
@@ -355,6 +375,7 @@ mirror_prune_desc=Remove any remote-tracking references that no longer exist on
mirror_interval=ミラー 間隔(時)
mirror_address=ミラー アドレス
mirror_address_desc=Please include necessary user credentials in the address.
mirror_last_synced=最終同期
watchers=ウォッチャー
stargazers=Stargazers
forks=フォーク
@@ -368,7 +389,8 @@ migrate_type=マイグレーションの種類
migrate_type_helper=このリポジトリは、<span class="text blue"> ミラー</span> になります
migrate_repo=リポジトリを移行
migrate.clone_address=クローンアドレス
migrate.clone_address_desc=これは、HTTP/HTTPS/GIT URL またはローカル サーバー パスを設定できます。
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=ローカル リポジトリをインポートすることはできません。
migrate.invalid_local_path=ローカルパスが無効です。存在しないかディレクトリではありません。
migrate.failed=移行に失敗しました: %v
@@ -393,7 +415,7 @@ create_new_repo_command=コマンドラインで新しいリポジトリを作
push_exist_repo=コマンド ・ ラインから既存のリポジトリをプッシュ
repo_is_empty=このリポジトリは空です、後で戻って来て下さい!
code=コード
files=Files
branch=ブランチ
tree=ツリー
filter_branch_and_tag=ブランチまたはタグをフィルタリング
@@ -409,6 +431,47 @@ file_raw=Raw
file_history=履歴
file_view_raw=Rawデータを見る
file_permalink=パーマリンク
file_too_large=このファイルは大きすぎるため、表示できません。
video_not_supported_in_browser=Your browser doesn't support HTML5 video tag.
editor.new_file=New file
editor.upload_file=Upload file
editor.edit_file=ファイルを編集
editor.preview_changes=Preview Changes
editor.cannot_edit_non_text_files=Cannot edit non-text files
editor.edit_this_file=このファイルを編集
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
editor.fork_before_edit=You must fork this repository before editing the file
editor.delete_this_file=このファイルを削除
editor.must_have_write_access=You must have write access to make or propose changes to this file
editor.file_delete_success=File '%s' has been deleted successfully!
editor.name_your_file=Name your file...
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
editor.or=or
editor.cancel_lower=キャンセル
editor.commit_changes=変更をコミット
editor.add_tmpl=Add '%s/<filename>'
editor.add='%s' を追加
editor.update='%s' を更新
editor.delete='%s' を削除
editor.commit_message_desc=Add an optional extended description...
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
editor.new_branch_name_desc=New branch name...
editor.cancel=キャンセル
editor.filename_cannot_be_empty=Filename cannot be empty.
editor.branch_already_exists=Branch '%s' already exists in this repository.
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
editor.file_is_a_symlink=The file '%s' is a symlink that cannot be modified from the web editor.
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
editor.file_already_exists=A file with name '%s' already exists in this repository.
editor.no_changes_to_show=There are no changes to show.
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
editor.add_subdir=Add subdirectory...
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
editor.upload_files_to_dir=Upload files to '%s'
commits.commits=コミット
commits.search=コミットの検索
@@ -435,6 +498,11 @@ issues.create=問題を作成
issues.new_label=新しいラベル
issues.new_label_placeholder=ラベル名...
issues.create_label=ラベルを作成
issues.label_templates.title=Load a predefined set of labels
issues.label_templates.info=There arent any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
issues.label_templates.helper=Select a label set
issues.label_templates.use=Use this label set
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
issues.open_tab=%d オープン
issues.close_tab=%d クローズ
issues.filter_label=ラベル
@@ -462,7 +530,8 @@ issues.next=次ページ
issues.open_title=オープン
issues.closed_title=クローズ
issues.num_comments=%d コメント
issues.commented_at=`コメント <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`commented <a href="#%s">%s</a>`
issues.delete_comment_confirm=Are you sure you want to delete this comment?
issues.no_content=まだコンテンツがありません
issues.close_issue=閉じる
issues.close_comment_issue=コメントしてクローズ
@@ -475,8 +544,7 @@ issues.commit_ref_at=`referenced this issue from a commit <a id="%[1]s" href="#%
issues.poster=ポスター
issues.collaborator=コラボレータ
issues.owner=オーナー
issues.sign_up_for_free=無料でサインアップ
issues.sign_in_require_desc=to join this conversation. Already have an account? <a href="%s">Sign in to comment</a>
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
issues.edit=編集
issues.cancel=キャンセル
issues.save=保存
@@ -491,6 +559,8 @@ issues.label_deletion=ラベルの削除
issues.label_deletion_desc=ラベルを削除すると、関連するすべての問題の情報が削除されます。続行しますか。
issues.label_deletion_success=ラベルは正常に削除されました。
issues.num_participants=%d Participants
issues.attachment.open_tab=`Click to see "%s" in a new tab`
issues.attachment.download=`Click to download "%s"`
pulls.new=新しいプルリクエスト
pulls.compare_changes=変更を比較
@@ -500,7 +570,7 @@ pulls.compare_compare=比較
pulls.filter_branch=フィルターブランチ
pulls.no_results=結果が見つかりませんでした。
pulls.nothing_to_compare=There is nothing to compare because base and head branches are even.
pulls.has_pull_request=`There is already a pull request between these two targets: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
pulls.has_pull_request=`既にプルリクエストがこれらのターゲット間に存在します: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
pulls.create=プルリクエストを作成します。
pulls.title_desc=wants to merge %[1]d commits from <code>%[2]s</code> into <code>%[3]s</code>
pulls.merged_title_desc=merged %[1]d commits from <code>%[2]s</code> into <code>%[3]s</code> %[4]s
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=This pull request can't be merged automatically bec
pulls.cannot_auto_merge_helper=競合を解決するためには、手動でマージする必要があります。
pulls.merge_pull_request=プルリクエストをマージします。
pulls.open_unmerged_pull_exists=`You can't perform reopen operation because there is already an open pull request (#%d) from same repository with same merge information and is waiting for merging.`
pulls.delete_branch=Delete Branch
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence.
milestones.new=新しいマイルストーン
milestones.open_tab=%d オープン
@@ -554,7 +626,7 @@ wiki.save_page=ページを保存
wiki.last_commit_info=%s このページを編集 %s
wiki.edit_page_button=編集
wiki.new_page_button=新規ページ
wiki.delete_page_button=Delete Page
wiki.delete_page_button=ページの削除
wiki.delete_page_notice_1=This will delete the page <code>"%s"</code>. Please be certain.
wiki.page_already_exists=既に同じ名前のWiki ページが存在します。
wiki.pages=ページ
@@ -563,27 +635,34 @@ wiki.last_updated=最終更新 %s
settings=設定
settings.options=オプション
settings.collaboration=コラボレーション
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.admin=管理
settings.collaboration.write=書込
settings.collaboration.read=読込
settings.collaboration.undefined=Undefined
settings.hooks=Webhooks
settings.githooks=Git のフック
settings.basic_settings=基本設定
settings.mirror_settings=Mirror Settings
settings.sync_mirror=今すぐ同期
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
settings.site=公式サイト
settings.update_settings=設定の更新
settings.change_reponame_prompt=この変更はリンクがリポジトリに関連付ける方法に影響します。
settings.advanced_settings=拡張設定
settings.wiki_desc=Wikiでドキュメントの作成を許可
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=外部 wiki を使用します。
settings.external_wiki_url=外部 Wiki の URL
settings.external_wiki_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.issues_desc=組み込み簡易課題トラッカーを有効
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=外部課題トラッキングシステムを使用
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=外部課題トラッキングツール URLのフォーマット
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style.numeric=数値
settings.tracker_issue_style.alphanumeric=Alphanumeric
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
settings.pulls_desc=Enable pull requests to accept public contributions
settings.danger_zone=危険地帯
@@ -598,10 +677,10 @@ settings.transfer_desc=リポジトリをあなたが管理者権限を持って
settings.transfer_notices_1=-新しい所有者が個人ユーザーの場合、あなたがアクセスできなくなります。
settings.transfer_notices_2=- You will conserve access if new owner is an organization and if you're one of the owners.
settings.transfer_form_title=操作を確認するために、以下の情報を入力してください。
settings.wiki_delete=Erase Wiki Data
settings.wiki_delete_desc=Once you erase wiki data there is no going back. Please be certain.
settings.wiki_delete=Wikiのデータ消去
settings.wiki_delete_desc=Wikiのデータを消去すると元に戻すことは出来ません。よく確認してください。
settings.wiki_delete_notices_1=- This will delete and disable the wiki for %s
settings.wiki_deletion_success=Repository wiki data have been erased successfully.
settings.wiki_deletion_success=Wikiのデータ消去が完了しました。
settings.delete=このリポジトリを削除
settings.delete_desc=リポジトリを削除すると元に戻せません。確実に確認してください。
settings.delete_notices_1=-この操作は<strong>元に戻せません</strong> 。
@@ -653,6 +732,8 @@ settings.event_send_everything=<strong>すべて</strong> が必要です。
settings.event_choose=必要なものを選択しましょう。
settings.event_create=Create
settings.event_create_desc=ブランチ、またはタグを作成
settings.event_pull_request=Pull Request
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
settings.event_push=プッシュ
settings.event_push_desc=Git リポジトリにプッシュ
settings.active=アクティブ
@@ -690,7 +771,7 @@ diff.show_unified_view=Unified View
diff.stats_desc=共有<strong>%d 個のファイルを変更した</strong>、<strong>%d 個の追加</strong> と <strong>%d 個の削除</strong>を含む
diff.bin=BIN
diff.view_file=ファイルの表示
diff.file_supressed=File diff supressed because it is too large
diff.file_suppressed=File diff suppressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=リリース
@@ -722,6 +803,7 @@ release.deletion=リリースの削除
release.deletion_desc=このリリースを削除すると、対応するGitのタグも削除されます。よろしいですか
release.deletion_success=リリースが正常に削除されました。
release.tag_name_already_exist=このタグ名には既にリリースが存在します。
release.tag_name_invalid=Tag name is not valid.
release.downloads=Downloads
[org]
@@ -889,6 +971,7 @@ users.edit_account=アカウントの編集
users.max_repo_creation=Maximum Repository Creation Limit
users.max_repo_creation_desc=(Set -1 to use global default limit)
users.is_activated=アカウントがアクティブされました
users.prohibit_login=This account is prohibited to login
users.is_admin=このアカウントには管理者の権限を持つ
users.allow_git_hook=このアカウントには Git のフックを作成する権限を持つ
users.allow_import_local=This account has permissions to import local repositories
@@ -957,6 +1040,7 @@ auths.delete_auth_title=認証削除
auths.delete_auth_desc=認証を削除します、継続しますか?
auths.still_in_used=This authentication is still used by some users, please delete or convert these users to another login type first.
auths.deletion_success=認証が正常に削除されました。
auths.login_source_exist=Login source '%s' already exists.
config.server_config=サーバーの構成
config.app_name=アプリケーション名
@@ -967,6 +1051,7 @@ config.offline_mode=オフラインモード
config.disable_router_log=ルーターのログを無効にする
config.run_user=実行ユーザ
config.run_mode=実行モード
config.git_version=Git Version
config.repo_root_path=リポジトリのルートパス
config.static_file_root_path=静的ファイルのルートパス
config.log_file_root_path=ログ ファイルのルート パス
@@ -994,6 +1079,7 @@ config.db_ssl_mode=SSL モード
config.db_ssl_mode_helper=(「postgres」のみ
config.db_path=パス
config.db_path_helper=(for "sqlite3" and "tidb")
config.service_config=サービスの構成
config.register_email_confirm=電子メールの確認を必要
config.disable_register=登録を無効にする
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=最小キー サイズ チェックを無効にし
config.enable_captcha=Captchaを有効にする
config.active_code_lives=コードリンクの有効期限をアクティブ
config.reset_password_code_lives=パスワードリンクの有効期限をリセット
config.webhook_config=Webhook設定
config.queue_length=キューの長さ
config.deliver_timeout=送信タイムアウト
config.skip_tls_verify=TLSの確認を省略
config.mailer_config=メーラーの構成
config.mailer_enabled=有効にした
config.mailer_disable_helo=HELOコマンド無効
@@ -1017,12 +1105,15 @@ config.mailer_user=ユーザ
config.send_test_mail=Send Test Email
config.test_mail_failed=Fail to send test email to '%s': %v
config.test_mail_sent=Test email has been sent to '%s'.
config.oauth_config=OAuth 構成
config.oauth_enabled=Enabled
config.cache_config=キャッシュの構成
config.cache_adapter=キャッシュ アダプター
config.cache_interval=キャッシュ間隔
config.cache_conn=キャッシュ接続
config.session_config=セッションの構成
config.session_provider=セッション プロバイダー
config.provider_config=プロバイダーの構成
@@ -1032,9 +1123,24 @@ config.gc_interval_time=GC 間隔
config.session_life_time=セッションのライフタイム
config.https_only=HTTPS のみ
config.cookie_life_time=クッキーのライフタイム
config.picture_config=画像構成
config.picture_service=画像サービス
config.disable_gravatar=グラバターを無効にする
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=ログの構成
config.log_mode=ログ モード

1215
conf/locale/locale_ko-KR.ini Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ explore=Izpētīt
help=Palīdzība
sign_in=Pierakstīties
sign_out=Izrakstīties
sign_up=Pieteikties
sign_up=Reģistrēties
register=Reģistrēties
website=Mājas lapa
version=Versija
@@ -96,6 +96,8 @@ offline_mode=Iespējot bezsaistes režīmu
offline_mode_popup=Atspējot CDN arī produkcijas režīmā, visi resursu faili tiks piegādāti no servera.
disable_gravatar=Atspējot Gravatar pakalpojumu
disable_gravatar_popup=Atspējot Gravatar un citus avotus, visus avatarus augšupielādēts lietotāji vai izmantos noklusēto attēlu.
federated_avatar_lookup=Iespējot apvienoto profila bilžu meklētāju
federated_avatar_lookup_popup=Iespējot apvienoto profila bilžu meklētāju, lai izmantotu atvērtā koda apvienoto servisu balstītu uz libravatar.
disable_registration=Atspējot lietotāju reģistrāciju
disable_registration_popup=Atspējot lietotāju reģistrāciju, tikai administrators varēs izveidot jaunus lietotāju kontus.
enable_captcha=Iespējot drošības kodu
@@ -114,6 +116,7 @@ sqlite3_not_available=Jūsu versija neatbalsta SQLite3, lūdzu lejupielādējiet
invalid_db_setting=Datu bāzes iestatījums nav pareizs: %v
invalid_repo_path=Repozitorija atrašanās vieta ir nekorekta: %v
run_user_not_match=Izpildes lietotājs nav pašreizējais lietotājs: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Neizdevās saglabāt konfigurāciju: %v
invalid_admin_setting=Nekorekts admin konta iestatījums: %v
install_success=Laipni lūdzam! Mēs priecājamies, ka Jūs izvēlaties Gogs, patīkamu lietošanu!
@@ -124,6 +127,7 @@ uname_holder=Lietotājvārds vai e-pasts
password_holder=Parole
switch_dashboard_context=Mainīt infopaneļa kontekstu
my_repos=Mani repozitoriji
show_more_repos=Parādīt vairāk repozitorojus...
collaborative_repos=Sadarbības repozitoriji
my_orgs=Manas organizācijas
my_mirrors=Mani spoguļi
@@ -134,6 +138,7 @@ issues.in_your_repos=Jūsu repozitorijos
[explore]
repos=Repozitoriji
users=Lietotāji
organizations=Organizations
search=Meklēt
[auth]
@@ -148,16 +153,17 @@ forget_password=Aizmirsi paroli?
sign_up_now=Nepieciešams konts? Reģistrējies tagad.
confirmation_mail_sent_prompt=Jauns apstiprināšanas e-pasts ir nosūtīts uz <b>%s</b>, lūdzu, pārbaudies savu e-pasta kontu tuvāko %d stundu laikā, lai pabeigtu reģistrācijas procesu.
active_your_account=Aktivizēt savu kontu
prohibit_login=Aizliegt pieteikšanos
prohibit_login_desc=Ar Jūsu kontu nav atļauts pieteikties, sazinoties ar lapas administratoru.
resent_limit_prompt=Atvainojiet, Jūs sūtījāt aktivizācijas e-pastu pārāk bieži. Lūdzu, gaidiet 3 minūtes.
has_unconfirmed_mail=Sveiki %s, Jums ir neapstiprināta e-pasta adrese (<b>%s</b>). Ja neesat saņēmis apstiprināšanas e-pastu vai Jums ir nepieciešams nosūtīt jaunu, lūdzu, nospiediet pogu, kas atrodas zemāk.
resend_mail=Nospiediet šeit, lai vēlreiz nosūtītu aktivizācijas e-pastu
email_not_associate=Šī e-pasta adrese nav saistīta ar Jūsu kontu.
send_reset_mail=Spiediet šeit, lai nosūtītu paroles maiņas vēstuli uz Jūsu e-pastu
reset_password=Atjaunot savu paroli
invalid_code=Atvainojiet, Jūsu apstiprināšanas kodam ir beidzies derīguma termiņš vai arī tas ir nepareizs.
reset_password_helper=Nospiediet šeit, lai atjaunotu paroli
password_too_short=Paroles garums nedrīkst būt mazāks par 6.
non_local_account=Non-local accounts cannot change passwords through Gogs.
non_local_account=Tikai lokālie konti var nomainīt savu paroli Gogs.
[mail]
activate_account=Lūdzu, aktivizējiet savu kontu
@@ -184,6 +190,13 @@ TeamName=Komandas nosaukums
AuthName=Autorizācijas nosaukums
AdminEmail=Admin e-pasta adrese
NewBranchName=Jauna atzara nosaukums
CommitSummary=Revīzijas kopsavilkums
CommitMessage=Revīzijas ziņojums
CommitChoice=Revīzijas izvēle
TreeName=Faila ceļš
Content=Saturs
require_error=` nedrīkst būt tukšs.`
alpha_dash_error=` drīkst saturēt tikai latīņu alfabēta burtus, ciparus vai domuzīmes (-_).`
alpha_dash_dot_error=` drīkst saturēt tikai latīņu alfabēta burtus, ciparus, domuzīmes (-_) vai punktu.`
@@ -220,7 +233,7 @@ org_still_own_repo=Šī organizācija ir vismaz viena repozitorija īpašnieks,
target_branch_not_exist=Mērķa atzars neeksistē
[user]
change_avatar=Change your avatar
change_avatar=Mainīt profila attēlu
join_on=Pievienojās
repositories=Repozitoriji
activity=Publiskā aktivitāte
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=Lietotāja vārds '%s' nav atļauts.
[settings]
profile=Profils
password=Parole
avatar=Profila attēls
ssh_keys=SSH atslēgas
social=Sociālie konti
applications=Lietotnes
@@ -256,6 +270,8 @@ change_username_prompt=Šī izmaiņa ietekmēs saites, kas norāda uz Jūsu kont
continue=Turpināt
cancel=Atcelt
lookup_avatar_by_mail=Meklēt profila bildes pēc e-pasta
federated_avatar_lookup=Apvienotais profila bilžu meklētājs
enable_custom_avatar=Iespējot maināmu profila attēlu
choose_new_avatar=Izvēlēties jaunu profila attēlu
update_avatar=Saglabāt profila bildi
@@ -322,6 +338,10 @@ access_token_deletion=Personīgā piekļuves talona dzēšana
access_token_deletion_desc=Dzēšot personīgo piekļuves talonu, tiks liegta piekļuve aplikācijām, kas to izmanto. Vai vēlaties turpināt?
delete_token_success=Personīgās piekļuves talons veiksmīgi izdzēsts! Neaizmirstiet nomainīt uz citu aplikācijās, kas to izmantoja.
orgs.none=You are not a member of any organizations.
orgs.leave_title=Leave an organization
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account=Dzēst savu kontu
delete_prompt=Šī darbība pilnībā izdzēsīs Jūsu kontu, kā arī tā ir <strong>NEATGRIEZENISKA</strong>!
confirm_delete_account=Apstiprināt dzēšanu
@@ -342,7 +362,7 @@ fork_from=Atdalīt no
fork_visiblity_helper=Atdalītam repozitorijam nav iespējams nomainīt tā redzamību
repo_desc=Apraksts
repo_lang=Valoda
repo_lang_helper=Izvēlieties .gitignore failus
repo_gitignore_helper=Izvēlieties .gitignore sagatavi
license=Licence
license_helper=Izvēlieties licences failu
readme=LasiMani
@@ -350,11 +370,12 @@ readme_helper=Izvēlieties faila LasiMani sagatavi
auto_init=Inicializēt šo repozitoriju ar izvēlētajiem failiem un sagatavi
create_repo=Izveidot repozitoriju
default_branch=Noklusējuma atzars
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_prune=Izmest
mirror_prune_desc=Izdzēst visas ārējās atsauces, kas ārējā repozitorijā vairs neeksistē
mirror_interval=Spoguļošanas intervāls (stundās)
mirror_address=Spoguļa adrese
mirror_address_desc=Lūdzu iekļaujiet adresē nepieciešamo lietotājvārdu/paroli.
mirror_last_synced=Pēdējo reizi sinhronizēts
watchers=Novērotāji
stargazers=Zvaigžņdevēji
forks=Atdalītie repozitoriji
@@ -368,7 +389,8 @@ migrate_type=Migrācijas veids
migrate_type_helper=Šis repozitorijs būs <span class="text blue">spogulis</span>
migrate_repo=Migrēt repozitoriju
migrate.clone_address=Klonēšanas adrese
migrate.clone_address_desc=Tas var būt HTTP/HTTPS/GIT URL vai ceļš uz lokālā servera.
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=Jums nav tiesību importēt lokālu repozitoriju.
migrate.invalid_local_path=Nekorents lokālais ceļš, tas neeksistē vai nav direktorijs.
migrate.failed=Migrācija neizdevās: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Izveidot jaunu repozitoriju komandrindā
push_exist_repo=Nosūtīt izmaiņas no komandrindas eksistējošam repozitorijam
repo_is_empty=Šis repozitorijs ir tukšs, apskatiet atkal vēlāk!
code=Kods
files=Files
branch=Atzars
tree=Koks
filter_branch_and_tag=Filtrēt atzarus vai tagus
@@ -409,6 +431,47 @@ file_raw=Neapstrādāts
file_history=Vēsture
file_view_raw=Rādīt neapstrādātu
file_permalink=Patstāvīgā saite
file_too_large=Šis fails ir par lielu, lai to parādītu
video_not_supported_in_browser=Your browser doesn't support HTML5 video tag.
editor.new_file=Jauns fails
editor.upload_file=Augšupielādēt failu
editor.edit_file=Labot failu
editor.preview_changes=Priekšskatīt izmaiņas
editor.cannot_edit_non_text_files=Nevar rediģēt failus, kas nav teksta faili
editor.edit_this_file=Rediģēt šo failu
editor.must_be_on_a_branch=Ir jābūt izvēlētam atzaram, lai varētu veikt vai piedāvāt izmaiņas šim failam
editor.fork_before_edit=Lai varētu labot failu ir nepieciešams atdalīt repozitoriju
editor.delete_this_file=Dzēst šo failu
editor.must_have_write_access=Jums ir jābūt rakstīšanas tiesībām, lai varētu veikt vai piedāvāt izmaiņas šim failam
editor.file_delete_success=Fails '%s' ir veiksmīgi izdzēsts!
editor.name_your_file=Ievadiet faila nosaukumu...
editor.filename_help=Lai pievienotu direktoriju, ierakstiet tās nosaukumu un nospiediet /. Lai noņemtu direktoriju, ielieciet kursoru pirms faila nosaukuma un nospiediet atpakaļatkāpes taustiņu.
editor.or=vai
editor.cancel_lower=atcelt
editor.commit_changes=Pabeigt revīziju
editor.add_tmpl=Pievienot '%s/<filename>'
editor.add=Pievienot '%s'
editor.update=Atjaunināt '%s'
editor.delete=Dzēst '%s'
editor.commit_message_desc=Pievienot neobligātu paplašinātu aprakstu...
editor.commit_directly_to_this_branch=Apstiprināt revīzijas izmaiņas atzarā <strong class="branch-name">%s</strong>.
editor.create_new_branch=Izveidot <strong>jaunu atzaru</strong> un izmaiņu pieprasījumu šai revīzijai.
editor.new_branch_name_desc=Jaunā atzara nosaukums...
editor.cancel=Atcelt
editor.filename_cannot_be_empty=Nav ievadīts faila nosaukums.
editor.branch_already_exists=Atzars '%s' šajā repozitorijā jau eksistē.
editor.directory_is_a_file=Ieraksts '%s' vecāka ceļā ir fails nevis direktorija šajā repozitorijā.
editor.file_is_a_symlink=The file '%s' is a symlink that cannot be modified from the web editor.
editor.filename_is_a_directory=Faila nosaukums '%s' sakrīt ar direktorijas nosaukumu šajā repozitorijā.
editor.file_editing_no_longer_exists=Fails '%s', ko labojat, vairs neeksistē repozitorijā.
editor.file_changed_while_editing=Faila saturs ir mainījies kopš brīža, kad sākāt to labot. <a target="_blank" href="%s">Nospiediet šeit</a>, lai redzētu kas ir mainījies vai <strong>nospiediet atkārtoti pabeigt revīziju</strong>, lai pārrakstītu izmaiņas.
editor.file_already_exists=Fails ar nosaukumu '%s' repozitorijā jau eksistē.
editor.no_changes_to_show=Nav izmaiņu, ko rādīt.
editor.fail_to_update_file=Neizdevās izmainīt/izveidot failu '%s', kļūda: %v
editor.add_subdir=Pievienot apakšdirektoriju...
editor.unable_to_upload_files=Neizdevās augšupielādēt failus uz direktoriju '%s', kļūda: %v
editor.upload_files_to_dir=Augšupielādēt failus uz direktoriju '%s'
commits.commits=Revīzijas
commits.search=Meklēt revīzijas
@@ -435,6 +498,11 @@ issues.create=Pieteikt problēmu
issues.new_label=Jauna etiķete
issues.new_label_placeholder=Etiķetes nosaukums...
issues.create_label=Izveidot etiķeti
issues.label_templates.title=Ielādēt sākotnēji noteikto etiķešu kopu
issues.label_templates.info=Nav definēta neviena etiķete. Nospiediet pogu "Izveidot etiķeti", lai to izveidotu vai izmantojiet zemāk piedāvātās etiķetes.
issues.label_templates.helper=Izvēlieties etiķešu kopu
issues.label_templates.use=Izmantot šo etiķešu kopu
issues.label_templates.fail_to_load_file=Neizdevās ielādēt etiķetes sagataves failu '%s': %v
issues.open_tab=%d atvērti
issues.close_tab=%d aizvērti
issues.filter_label=Etiķete
@@ -462,7 +530,8 @@ issues.next=Nākamā
issues.open_title=Atvērta
issues.closed_title=Slēgta
issues.num_comments=%d komentāri
issues.commented_at=`komentēja <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=` komentēja <a href="#%s">%s</a>`
issues.delete_comment_confirm=Vai patiešām vēlaties dzēst šo komentāru?
issues.no_content=Vēl nav satura.
issues.close_issue=Aizvērt
issues.close_comment_issue=Komentēt un aizvērt
@@ -475,8 +544,7 @@ issues.commit_ref_at=`pieminēja šo problēmu revīzijā <a id="%[1]s" href="#%
issues.poster=Autors
issues.collaborator=Līdzstrādnieks
issues.owner=Īpašnieks
issues.sign_up_for_free=Pievienojieties
issues.sign_in_require_desc=, lai piedalītos diskusijā. Jau ir konts? <a href="%s">Pierakstieties, lai komentētu</a>
issues.sign_in_require_desc=<a href="%s">Pierakstieties</a>, lai pievienotos šai sarunai.
issues.edit=Labot
issues.cancel=Atcelt
issues.save=Saglabāt
@@ -491,6 +559,8 @@ issues.label_deletion=Etiķetes dzēšana
issues.label_deletion_desc=Dzēšot šo etiķeti, tā tiks noņemta no visām saistītajām problēmām. Vai vēlaties turpināt?
issues.label_deletion_success=Etiķete tika veiksmīgi izdzēsta!
issues.num_participants=%d dalībnieki
issues.attachment.open_tab=`Noklikšķiniet, lai apskatītos "%s" jaunā logā`
issues.attachment.download=`Noklikšķiniet, lai lejupielādētu "%s"`
pulls.new=Jauns izmaiņu pieprasījums
pulls.compare_changes=Salīdzināt izmaiņas
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Šis izmaiņu pieprasījums nevar tikt automātiski
pulls.cannot_auto_merge_helper=Lūdzu sapludiniet manuāli, lai atrisinātu konfliktus.
pulls.merge_pull_request=Izmaiņu pieprasījuma sapludināšana
pulls.open_unmerged_pull_exists=`Jūs nevarat veikt atkārtotas atvēršanas darbību, jo jau eksistē izmaiņu pieprasījums (#%d) no šī repozitorija ar tādu pašu sapludināšanas informāciju un gaida sapludināšanu.`
pulls.delete_branch=Delete Branch
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence.
milestones.new=Jauns atskaites punkts
milestones.open_tab=%d atvērti
@@ -563,27 +635,34 @@ wiki.last_updated=Pēdējo reizi labota %s
settings=Iestatījumi
settings.options=Opcijas
settings.collaboration=Sadarbība
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.collaboration.admin=Administrators
settings.collaboration.write=Rakstīšanas
settings.collaboration.read=Skatīšanās
settings.collaboration.undefined=Nedefinētas
settings.hooks=Tīmekļa āķi
settings.githooks=Git āķi
settings.basic_settings=Pamatiestatījumi
settings.mirror_settings=Spoguļa iestatījumi
settings.sync_mirror=Sinhronizēt tagad
settings.mirror_sync_in_progress=Notiek spoguļa sinhronizācija, uzgaidiet aptuveni minūti un atjaunojiet lapu.
settings.site=Oficiālā mājas lapa
settings.update_settings=Mainīt iestatījumus
settings.change_reponame_prompt=Šī izmaiņa ietekmēs saites, kas ir saistītas ar šo repozitoriju.
settings.advanced_settings=Papildu iestatījumi
settings.wiki_desc=Iespējot vikivietni, lai atļautu cilvēkiem rakstīt dokumentus
settings.wiki_desc=Iespējot vikivietnes
settings.use_internal_wiki=Izmantot iebūvēto vikivietni
settings.use_external_wiki=Izmantot ārējo vikivietni
settings.external_wiki_url=Ārējās Vikivietnes adrese
settings.external_wiki_url_desc=Apmeklētāji tiks novirzīti uz adresi, kad viņi uzklikšķinās uz cilnes.
settings.issues_desc=Iespējot iebūvētu vieglu problēmu sekotāju
settings.issues_desc=Iespējot problēmu sekotāju
settings.use_internal_issue_tracker=Izmantot iebūvētu vieglu problēmu sekotāju
settings.use_external_issue_tracker=Izmantot ārējo problēmu sekotāju
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Ārējā problēmu sekotāja adreses formāts
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style=Ārējā problēmu reģistra nosaukumu stils:
settings.tracker_issue_style.numeric=Cipari
settings.tracker_issue_style.alphanumeric=Burti un cipari
settings.tracker_url_format_desc=Jūs varat izmantot <code>{user}{repo}{index}</code> lietotājvārdam, repozitorija nosaukumam un problēmas identifikātoram.
settings.pulls_desc=Iespējot izmaiņu pieprasījumus lai saņemtu publiskus ieguldījumus
settings.danger_zone=Bīstamā zona
@@ -606,7 +685,7 @@ settings.delete=Dzēst šo repozitoriju
settings.delete_desc=Dzēšot repozitoriju, tā datus vairs nebūs iespējams atgūt. Pirms dzēšanas pārliecinieites vai patiešām vēlaties to darīt.
settings.delete_notices_1=- Šī darbība ir <strong>NEATGRIEZENISKA</strong>.
settings.delete_notices_2=- Šī darbība neatgriezeniski izdzēsīs visus šī repozitorija datus, tai skaitā Git datus, problēmu ziņojumus, komentārus un definētās piekļuves tiesības.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.delete_notices_fork_1=- Visi atdalītie repozitoriji kļūs neatkarīgi pēc dzēšanas.
settings.deletion_success=Repozitorijs tika veiksmīgi dzēsts!
settings.update_settings_success=Repozitorija opcijas ir veiksmīgi saglabātas.
settings.transfer_owner=Jaunais īpašnieks
@@ -653,6 +732,8 @@ settings.event_send_everything=Vēlos saņemt <strong>visu</strong>.
settings.event_choose=Atzīmēt, ko vēlos saņemt.
settings.event_create=Izveidot
settings.event_create_desc=Atzara vai taga izveidošana
settings.event_pull_request=Izmaiņu pieprasījums
settings.event_pull_request_desc=Atvērts, aizvērts, atkāroti atvērts, labots, piešķirts vai noņemts izmaiņu pieprasījums, vai mainīta etiķete, vai veikta sinhronizācija.
settings.event_push=Izmaiņu nosūtīšana
settings.event_push_desc=Git izmaiņu nosūtīšana uz repozitoriju
settings.active=Aktīvs
@@ -690,8 +771,8 @@ diff.show_unified_view=Apvienotais skats
diff.stats_desc=<strong>%d mainītis faili</strong> ar <strong>%d papildinājumiem</strong> un <strong>%d dzēšanām</strong>
diff.bin=BIN
diff.view_file=Parādīt failu
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
diff.file_suppressed=Failā izmaiņas netiks attēlotas, jo tās ir par lielu
diff.too_many_files=Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels
release.releases=Laidieni
release.new_release=Jauns laidiens
@@ -722,6 +803,7 @@ release.deletion=Laidiena dzēšana
release.deletion_desc=Dzēšot šo laidienu tiks dzēsts arī atbilstošs Git tags. Vai vēlaties turpināt?
release.deletion_success=Laidiens tika veiksmīgi dzēsts!
release.tag_name_already_exist=Laidiens ar šādu taga nosaukumu jau eksistē.
release.tag_name_invalid=Nekorekts birkas nosaukams.
release.downloads=Lejupielādes
[org]
@@ -889,6 +971,7 @@ users.edit_account=Labot kontu
users.max_repo_creation=Maksimāls repozitoriju veidošanas limits
users.max_repo_creation_desc=(Uzlikt -1 lai izmantotu globālu limitu pēc noklusējuma)
users.is_activated=Konts ir aktivizēts
users.prohibit_login=Šim kontam ir aizliegts autorizēties
users.is_admin=Šim kontam ir administratora piekļuves tiesības
users.allow_git_hook=Šim kontam ir tiesības pievienot/labot Git āķus
users.allow_import_local=Šim kontam ir tiesības importēt lokālus repozitorijus
@@ -919,7 +1002,7 @@ auths.enabled=Iespējota
auths.updated=Atjaunināta
auths.auth_type=Autentifikācijas tips
auths.auth_name=Autentifikācijas nosaukums
auths.security_protocol=Security Protocol
auths.security_protocol=Drošības protokols
auths.domain=Domēns
auths.host=Resursdators
auths.port=Ports
@@ -957,6 +1040,7 @@ auths.delete_auth_title=Autentifikācijas dzēšana
auths.delete_auth_desc=Šī autentifikācija tiks dzēsta, vai vēlaties turpināt?
auths.still_in_used=Daži lietotāji joprojām izmanto šo autentifikācijas veidu. Nepieciešams veikt šo lietotāju konvertāciju vai dzēšanu.
auths.deletion_success=Autentifikācija tika veiksmīgi izdzēsta!
auths.login_source_exist=Login source '%s' already exists.
config.server_config=Servera konfigurācija
config.app_name=Lietotnes nosaukums
@@ -967,6 +1051,7 @@ config.offline_mode=Bezsaistes režīms
config.disable_router_log=Atspējot maršrutētāja žurnalizēšanu
config.run_user=Izpildes lietotājs
config.run_mode=Izpildes režīms
config.git_version=Git Version
config.repo_root_path=Repozitoriju glabāšanas vieta
config.static_file_root_path=Statisko failu atrašanās vieta
config.log_file_root_path=Žurnalizēšanas failu glabāšanas vieta
@@ -994,6 +1079,7 @@ config.db_ssl_mode=SSL režīms
config.db_ssl_mode_helper=(tikai PostgreSQL datu bāzei)
config.db_path=Ceļš
config.db_path_helper=(priekš "sqlite3" and "tidb")
config.service_config=Pakalpojuma konfigurācija
config.register_email_confirm=Pieprasīt e-pasta apstiprināšanu
config.disable_register=Atspējot jaunu lietotāju reģistrāciju
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Atspējot atslēgas minimālā garuma pārbaudi
config.enable_captcha=Iespējot drošības kodu
config.active_code_lives=Aktīvā koda ilgums
config.reset_password_code_lives=Paroles atiestatīšanas koda ilgums
config.webhook_config=Tīkla āķu konfigurācija
config.queue_length=Rindas garums
config.deliver_timeout=Piegādes noildze
config.skip_tls_verify=Izlaist TLS pārbaudi
config.mailer_config=Sūtītāja konfigurācija
config.mailer_enabled=Iespējots
config.mailer_disable_helo=Atspējot HELO
@@ -1017,12 +1105,15 @@ config.mailer_user=Lietotājs
config.send_test_mail=Nosūtīt pārbaudes e-pastu
config.test_mail_failed=Neizdevās nosūtīt pārbaudes e-pasta vēstuli uz '%s': %v
config.test_mail_sent=Pārbaudes e-pasta vēstule tika nosūtīta uz '%s'.
config.oauth_config=OAuth konfigurācija
config.oauth_enabled=Iespējota
config.cache_config=Kešatmiņas konfigurācija
config.cache_adapter=Kešatmiņas adapteris
config.cache_interval=Kešatmiņas intervāls
config.cache_conn=Kešatmiņas pieslēguma parametri
config.session_config=Sesijas konfigurācja
config.session_provider=Sesijas nodrošinātājs
config.provider_config=Pakalpojumu sniedzēja konfigurācija
@@ -1032,9 +1123,24 @@ config.gc_interval_time=GC laika intervāls
config.session_life_time=Sesijas ilgums
config.https_only=Tikai HTTPS
config.cookie_life_time=Sīkdatņu glabāšanas ilgums
config.picture_config=Attēlu konfigurācija
config.picture_service=Lokāli attēli
config.disable_gravatar=Atspējot Gravatar
config.enable_federated_avatar=Iespējot apvienotās profila bildes
config.git_config=Git konfigurācija
config.git_disable_diff_highlight=Atspējot salīdzināšanas sintakses iekrāsošanu
config.git_max_diff_lines=Maksimālais salīdzināmo rindu skaits vienam failam
config.git_max_diff_line_characters=Maksimālais salīdzināmo simbolu skaits vienai rindai
config.git_max_diff_files=Maksimālais salīdzināmo failu skaits, ko attēlot
config.git_gc_args=GC argumenti
config.git_migrate_timeout=Migrācijas noilgums
config.git_mirror_timeout=Spoguļa atjaunošanas noilgums
config.git_clone_timeout=Klonēšanas darbības noilgums
config.git_pull_timeout=Izmaiņu saņemšanas darbības noilgums
config.git_gc_timeout=GC darbības noilgums
config.log_config=Žurnalizēšanas konfigurācija
config.log_mode=Žurnalizēšanas veids

View File

@@ -96,6 +96,8 @@ offline_mode=Off line modus inschakelen
offline_mode_popup=Schakel CDN uit in productiemodus, alle bestanden worden lokaal aangeboden.
disable_gravatar=Gravatar Service uitschakelen
disable_gravatar_popup=Schakel Gravatar en andere bronnen uit, alle avatars worden door gebruikers geüpload of zijn standaard.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Schakel zelfregistratie uit
disable_registration_popup=Schakel zelfregistratie uit, alleen admins kunnen accounts maken.
enable_captcha=Inschakelen Captcha
@@ -114,6 +116,7 @@ sqlite3_not_available=Uw versie biedt geen ondersteuning voor SQLite3, download
invalid_db_setting=Uw database instellingen zijn niet correct: %v
invalid_repo_path=Repositorie basis map is niet correct: %v
run_user_not_match=De uitvoerende gebruiker is niet de huidig gebruiker: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Kan de configuratie niet opslaan: %v
invalid_admin_setting=Uw admin-instellingen zijn niet geldig: %v
install_success=Welkom! Wij zijn veheugd dat u voor Gogs heeft gekozen, veel plezier en tot ziens
@@ -124,6 +127,7 @@ uname_holder=Gebruikersnaam of e-mail
password_holder=Wachtwoord
switch_dashboard_context=Wissel voorpaginacontext
my_repos=Mijn repositories
show_more_repos=Toon meer repositories...
collaborative_repos=Gedeelde repositories
my_orgs=Mijn organisaties
my_mirrors=Mijn mirrors
@@ -134,6 +138,7 @@ issues.in_your_repos=In uw repositories
[explore]
repos=Repositories
users=Gebruikers
organizations=Organizations
search=Zoeken
[auth]
@@ -148,10 +153,11 @@ forget_password=Wachtwoord vergeten?
sign_up_now=Een account nodig? Meld u nu aan.
confirmation_mail_sent_prompt=Een bevestigingsemail is gestuurd naar <b>%s</b>, Bevestig u aanvraag binnen %d uren om uw registratie te voltooien.
active_your_account=Activeer uw account
prohibit_login=Login Prohibited
prohibit_login_desc=Your account is prohibited to login, please contact site admin.
resent_limit_prompt=Sorry, u heeft te snel na elkaar een aanvraag gedaan voor een activatie mail. Wacht drie minuten voor uw volgende aanvraag.
has_unconfirmed_mail=Beste %s, u heeft een onbevestigd e-mailadres (<b>%s</b>). Als u nog geen bevestiging heeft ontvangen, of u een nieuwe aanvraag wilt doen, klik dan op de onderstaande knop.
resend_mail=Klik hier om uw activatie mail nog een keer te verzenden
email_not_associate=Dit e-mailadres is niet gekoppeld aan een account.
send_reset_mail=Klik hier om uw wachtwoord reset mail (nogmaals) te versturen
reset_password=Reset uw wachtwoord
invalid_code=Sorry, uw bevestigingscode is verlopen of niet meer geldig.
@@ -184,6 +190,13 @@ TeamName=Team naam
AuthName=Autorisatienaam
AdminEmail=E-mail beheerder
NewBranchName=Nieuwe branch naam
CommitSummary=Commit samenvatting
CommitMessage=Commit bericht
CommitChoice=Commit choice
TreeName=Bestandspad
Content=Inhoud
require_error=kan niet leeg zijn.
alpha_dash_error=moet een valide alfanumeriek of dash(-_) karakter zijn.
alpha_dash_dot_error=moet een valide alfanumeriek, dash(-_) of (.) punt karakter zijn.
@@ -220,7 +233,7 @@ org_still_own_repo=De organisatie heeft nog eigendomen op repositories. U moet d
target_branch_not_exist=Doel branch bestaat niet
[user]
change_avatar=Change your avatar
change_avatar=Wijzig je profielfoto
join_on=Aangemeld op
repositories=repositories
activity=Openbare activiteit
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=Het gebruikersnaam patroon '%s' is niet toegestaan
[settings]
profile=Profiel
password=Wachtwoord
avatar=Profielfoto
ssh_keys=SSH-sleutels
social=Sociale netwerk-accounts
applications=Toepassingen
@@ -256,6 +270,8 @@ change_username_prompt=Deze verandering zal de weg links hebben betrekking op uw
continue=Doorgaan
cancel=Annuleren
lookup_avatar_by_mail=Zoek profielfoto per email
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=Aangepaste avatar inschakelen
choose_new_avatar=Kies een nieuwe avatar
update_avatar=Avatar instelling bijwerken
@@ -322,6 +338,10 @@ access_token_deletion=Persoonlijke toegang token verwijderen
access_token_deletion_desc=Verwijderen van deze persoonlijke toegang token zal alle verwante toegang verwijderen. Wilt u doorgaan?
delete_token_success=Persoonlijke toegangstoken is met succes verwijderd! Vergeet niet uw toepassingen ook bij te werken.
orgs.none=You are not a member of any organizations.
orgs.leave_title=Leave an organization
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account=Verwijder uw account
delete_prompt=Deze handeling zal uw account definitief verwijderen, u kunt dit <strong> NIET </strong> terug draaien!
confirm_delete_account=Bevestig verwijdering
@@ -342,7 +362,7 @@ fork_from=Afsplitsing van
fork_visiblity_helper=U kunt de zichtbaarheid van een geforkte repository niet aanpassen.
repo_desc=Omschrijving
repo_lang=Taal
repo_lang_helper=Selecteer .gitignore bestanden
repo_gitignore_helper=Selecteer .gitignore sjablonen
license=Licentie
license_helper=Selecteer een licentie bestand
readme=Leesmij-bestand
@@ -350,11 +370,12 @@ readme_helper=Selecteer een sjabloon voor het Leesmij-bestand
auto_init=Initialiseer deze repositorie met de geselecteerde bestanden en sjabloon
create_repo=Nieuwe repository
default_branch=Standaard branch
mirror_prune=Prune
mirror_prune=Opschonen
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_interval=Mirror interval(uur)
mirror_address=Kopie-adres
mirror_address_desc=Gelieve noodzakelijke gebruikersgegevens in de adresbalk.
mirror_last_synced=Laatste synchronisatie
watchers=Volgers
stargazers=Stargazers
forks=Forks
@@ -368,7 +389,8 @@ migrate_type=Migratie type
migrate_type_helper=Deze repositorie zal een <span class="text blue">mirror</span> zijn
migrate_repo=Migreer repositorie
migrate.clone_address=Clone adres
migrate.clone_address_desc=Dit kan een HTTP/HTTPS/GIT URL zijn of een lokaal pad.
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=U bent niet toegestaan om deze lokale repositories te importeren.
migrate.invalid_local_path=Ongeldig lokaal pad, het pad bestaat niet of het is geen map.
migrate.failed=Migratie is mislukt: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Maak een nieuwe repositorie aan vanaf de console
push_exist_repo=Push een bestaande repositorie vanaf de console
repo_is_empty=Deze repositories is leeg is, probeer het later opnieuw!
code=Code
files=Files
branch=Aftakking
tree=Boom
filter_branch_and_tag=Filter branch of tag
@@ -409,6 +431,47 @@ file_raw=Ruwe
file_history=Geschiedenis
file_view_raw=Weergave ruwe
file_permalink=Permalink
file_too_large=Dit bestand is te groot om te worden getoond
video_not_supported_in_browser=Your browser doesn't support HTML5 video tag.
editor.new_file=Nieuw bestand
editor.upload_file=Bestand uploaden
editor.edit_file=Bewerk bestand
editor.preview_changes=Wijzigingen nagaan
editor.cannot_edit_non_text_files=Kan niet-tekstbestanden niet bewerken
editor.edit_this_file=Bestand aanpassen
editor.must_be_on_a_branch=Je moet in een branch zijn om aanpassingen te maken of voor te stellen
editor.fork_before_edit=Je moet deze repository eerst vorken om dit bestand aan te kunnen passen
editor.delete_this_file=Verwijder dit bestand
editor.must_have_write_access=You must have write access to make or propose changes to this file
editor.file_delete_success=Bestand '%s' is succesvol verwijderd!
editor.name_your_file=Name your file...
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
editor.or=of
editor.cancel_lower=annuleren
editor.commit_changes=Commit Changes
editor.add_tmpl=Add '%s/<filename>'
editor.add=Add '%s'
editor.update=Update '%s'
editor.delete=Delete '%s'
editor.commit_message_desc=Add an optional extended description...
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
editor.new_branch_name_desc=New branch name...
editor.cancel=Cancel
editor.filename_cannot_be_empty=Filename cannot be empty.
editor.branch_already_exists=Branch '%s' already exists in this repository.
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
editor.file_is_a_symlink=The file '%s' is a symlink that cannot be modified from the web editor.
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
editor.file_already_exists=A file with name '%s' already exists in this repository.
editor.no_changes_to_show=There are no changes to show.
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
editor.add_subdir=Add subdirectory...
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
editor.upload_files_to_dir=Upload files to '%s'
commits.commits=Commits
commits.search=Zoeken
@@ -435,6 +498,11 @@ issues.create=Maak probleem
issues.new_label=Nieuw Label
issues.new_label_placeholder=Tekst label...
issues.create_label=Maak label
issues.label_templates.title=Load a predefined set of labels
issues.label_templates.info=There arent any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
issues.label_templates.helper=Select a label set
issues.label_templates.use=Use this label set
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
issues.open_tab=%d Open
issues.close_tab=%d gesloten
issues.filter_label=Label
@@ -462,7 +530,8 @@ issues.next=Volgende
issues.open_title=Open
issues.closed_title=Gesloten
issues.num_comments=%d opmerkingen
issues.commented_at=`gaf commentaar op <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`commented <a href="#%s">%s</a>`
issues.delete_comment_confirm=Are you sure you want to delete this comment?
issues.no_content=Er is nog geen inhoud.
issues.close_issue=Sluit
issues.close_comment_issue=Sluit en geef commentaar
@@ -475,8 +544,7 @@ issues.commit_ref_at=`verwees naar dit probleem vanuit een commit <a id="%[1]s"
issues.poster=Poster
issues.collaborator=Medewerker
issues.owner=Eigenaar
issues.sign_up_for_free=Gratis aanmelden
issues.sign_in_require_desc=om deel te nemen in deze conversatie. Heeft u al een account? <a href="%s">Meld u aan om te reageren</a>
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
issues.edit=Bewerken
issues.cancel=Annuleren
issues.save=Opslaan
@@ -491,6 +559,8 @@ issues.label_deletion=Verwijder label
issues.label_deletion_desc=Het verwijderen van dit label zal alle informatie in de gerelateerde problemen verwijderen. Wilt u doorgaan?
issues.label_deletion_success=Label werd met succes verwijderd!
issues.num_participants=%d deelnemers
issues.attachment.open_tab=`Click to see "%s" in a new tab`
issues.attachment.download=`Click to download "%s"`
pulls.new=Nieuwe Pull aanvraag
pulls.compare_changes=Vergelijk veranderingen
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Dit pull-request kan niet worden gemerged omdat er
pulls.cannot_auto_merge_helper=Gelieve beide versies manueel samen te voegen om de conflicten op te lossen.
pulls.merge_pull_request=Samenvoegen van pull verzoek
pulls.open_unmerged_pull_exists=U kan de bewerking 'heropenen' niet uitvoeren omdat er al een pull-aanvraag (#%d) is van dezelfde repository met dezelfde informatie. Voeg deze eerst samen.
pulls.delete_branch=Delete Branch
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence.
milestones.new=Nieuwe mijlpaal
milestones.open_tab=%d geopend
@@ -570,20 +642,27 @@ settings.collaboration.undefined=Undefined
settings.hooks=Webhooks
settings.githooks=Git-hooks
settings.basic_settings=Basis instellingen
settings.mirror_settings=Mirror Settings
settings.sync_mirror=Sync Now
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
settings.site=Officiële site
settings.update_settings=Instellingen bewerken
settings.change_reponame_prompt=Deze verandering zal gevolgen hebben voor hoe links zich verhouden tot de repository.
settings.advanced_settings=Geavanceerde opties
settings.wiki_desc=Wiki inschakelen, om mensen documenten te laten schrijven
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Externe wiki gebruiken
settings.external_wiki_url=Externe wiki-URL
settings.external_wiki_url_desc=Bezoekers worden doorgestuurd naar de URL als ze op het tabblad klikken.
settings.issues_desc=Ingebouwde compacte issuetracker inschakelen
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=Externe issuetracker gebruiken
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=URL-formaat externe issuetracker
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style.numeric=Numeric
settings.tracker_issue_style.alphanumeric=Alphanumeric
settings.tracker_url_format_desc=U kan de aanduidingen <code>{user} {repo} {index}</code> gebruiken voor de gebruikersnaam, de naam van de repository en de lijst van open tickets.
settings.pulls_desc=Schakel 'pull request' in om publieke bijdragen te mogelijk te maken
settings.danger_zone=Gevaren zone
@@ -653,6 +732,8 @@ settings.event_send_everything=Ik moet <strong>alles</strong> hebben.
settings.event_choose=Laat me kiezen wat ik nodig heb.
settings.event_create=Creëer
settings.event_create_desc=Branch, of tag aangemaakt
settings.event_pull_request=Pull Request
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
settings.event_push=Push
settings.event_push_desc=Git push naar een repository
settings.active=Actief
@@ -690,7 +771,7 @@ diff.show_unified_view=Gecombineerde weergave
diff.stats_desc=<strong>%d gewijzigde bestanden</strong> met <strong>toevoegingen van %d</strong> en <strong>%d verwijderingen</strong>
diff.bin=BIN
diff.view_file=Bestand weergeven
diff.file_supressed=File diff supressed because it is too large
diff.file_suppressed=File diff suppressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=Releases
@@ -722,6 +803,7 @@ release.deletion=Release verwijderen
release.deletion_desc=Als deze release verwijdert, worden de bijbehorende Git tag ook gewist. Wilt u doorgaan?
release.deletion_success=Release is verwijderd!
release.tag_name_already_exist=Versie met deze naam bestaat al.
release.tag_name_invalid=Tag name is not valid.
release.downloads=Downloads
[org]
@@ -777,7 +859,7 @@ members.invite_desc=Voeg nieuw lid toe aan %s:
members.invite_now=Nu uitnodigen
teams.join=Lid worden
teams.leave=Vertlaat
teams.leave=Verlaat
teams.read_access=Leestoegang
teams.read_access_helper=Dit team is in staat om zijn repositories te bekijken en te klonen.
teams.write_access=Schrijf toegang
@@ -889,6 +971,7 @@ users.edit_account=Bewerk account
users.max_repo_creation=Maximum-limiet voor aanmaken van repositories
users.max_repo_creation_desc=(Zet op -1 om de globale limiet te gebruiken)
users.is_activated=Dit account is geactiveerd
users.prohibit_login=This account is prohibited to login
users.is_admin=Dit account heeft beheerdersrechten
users.allow_git_hook=Deze account beschikt over machtigingen voor het maken van Git haken
users.allow_import_local=Dit account mag lokale repositories importeren
@@ -957,6 +1040,7 @@ auths.delete_auth_title=Authenticatie verwijderd
auths.delete_auth_desc=Deze authenticatie zal verwijderd worden, wil je verdergaan?
auths.still_in_used=This authentication is still used by some users, please delete or convert these users to another login type first.
auths.deletion_success=Authentication has been deleted successfully!
auths.login_source_exist=Login source '%s' already exists.
config.server_config=Serverconfiguratie
config.app_name=Applicatienaam
@@ -967,6 +1051,7 @@ config.offline_mode=Offline-modus
config.disable_router_log=Router-log uitschakelen
config.run_user=Uitvoerende gebruiker
config.run_mode=Uitvoer modus
config.git_version=Git Version
config.repo_root_path=Repositorie basis pad
config.static_file_root_path=Statische bestanden basis pad
config.log_file_root_path=Log bestand basis pad
@@ -994,6 +1079,7 @@ config.db_ssl_mode=SSL modus
config.db_ssl_mode_helper=(alleen voor "postgres")
config.db_path=Pad
config.db_path_helper=(voor "sqlite3" en "tidb")
config.service_config=Serviceconfiguratie
config.register_email_confirm=E-mailbevestiging registreren
config.disable_register=Registratie uitgeschakeld
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Controle op key-lengte uitschakelen
config.enable_captcha=CAPTCHA inschakelen
config.active_code_lives=Actieve Code leven
config.reset_password_code_lives=Reset wachtwoord Code leven
config.webhook_config=Webhook configuratie
config.queue_length=Lengte van wachtrij
config.deliver_timeout=Bezorging verlooptijd
config.skip_tls_verify=TLS certificaat controle overslaan
config.mailer_config=Mailerconfiguatie
config.mailer_enabled=Ingeschakeld
config.mailer_disable_helo=Schakel HELO uit
@@ -1017,12 +1105,15 @@ config.mailer_user=Gebruiker
config.send_test_mail=Testbericht verzenden
config.test_mail_failed=Verzending van een testmail naar '%s' is mislukt: %v
config.test_mail_sent=Test-email is verstuurd naar '%s'.
config.oauth_config=OAuth-configuratie
config.oauth_enabled=Ingeschakeld
config.cache_config=Cache-configuratie
config.cache_adapter=Cache-adapter
config.cache_interval=Cache-interval
config.cache_conn=Cache-connectie
config.session_config=Sessieconfiguratie
config.session_provider=Sessieprovider
config.provider_config=Provider config
@@ -1032,9 +1123,24 @@ config.gc_interval_time=GC interval time
config.session_life_time=Sessie duur
config.https_only=Alleen HTTPS
config.cookie_life_time=Cookie duur leeftijd
config.picture_config=Foto configuratie
config.picture_service=Foto service
config.disable_gravatar=Gravatar uitschakelen
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Logconfiguratie
config.log_mode=Log-modus

View File

@@ -60,7 +60,7 @@ ssl_mode=Tryb SSL
path=Ścieżka
sqlite_helper=Ścieżka do pliku bazy danych SQLite3 lub TiDB. <br>Proszę użyć ścieżki bezwzględnej podczas uruchamiania usługi.
err_empty_db_path=Ścieżka do bazy danych SQLite3 lub TiDB nie może być pusta.
err_invalid_tidb_name=Nazwa bazy danych TiDB nie może zawierać znaków "." i "-".
err_invalid_tidb_name=Nazwa bazy danych TiDB nie może zawierać znaków „.” i „-”.
no_admin_and_disable_registration=Rejestracji nie można wyłączyć bez tworzenia konta admina.
err_empty_admin_password=Hasło admina nie może być puste.
@@ -86,7 +86,7 @@ optional_title=Ustawienia opcjonalne
email_title=Ustawienia serwera e-mail
smtp_host=Serwer SMTP
smtp_from=Od
smtp_from_helper=Adres w polu "Od", zgodnie z RFC 5322. Może być to po prostu adres email, bądź adres w formacie "Nazwa" <email@example.com>.
smtp_from_helper=Adres w polu Od, zgodnie z RFC 5322. Może być to po prostu adres email, bądź adres w formacie Nazwa <email@example.com>.
mailer_user=E-mail nadawcy
mailer_password=Hasło nadawcy
register_confirm=Włącz potwierdzenia rejestracji
@@ -96,6 +96,8 @@ offline_mode=Włącz tryb offline
offline_mode_popup=Wyłącz CDN, nawet w trybie produkcyjnym, wszystkie pliki zasobów będą podawane lokalnie.
disable_gravatar=Wyłącz usługę Gravatar
disable_gravatar_popup=Wyłącz Gravatar i niestandardowe źrodła, awatary muszą być przesyłane przez użytkowników.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Wyłącz samodzielną rejestrację
disable_registration_popup=Wyłącz samodzielną rejestrację użytkownika, tylko administrator będzie mógł tworzyć konta.
enable_captcha=Włącz Captcha
@@ -109,11 +111,12 @@ admin_password=Hasło
confirm_password=Potwierdź hasło
admin_email=E-mail administratora
install_gogs=Zainstaluj Gogs
test_git_failed=Nie udało się przetestować polecenia "git": %v
test_git_failed=Nie udało się przetestować polecenia git: %v
sqlite3_not_available=Twoje wydanie nie obsługuje SQLite3, proszę pobrać oficjalne wydanie z %s, a NIE wersję z gobuild.
invalid_db_setting=Ustawienia bazy danych nie są poprawne: %v
invalid_repo_path=Ścieżka repozytoriów nie jest poprawna: %v
run_user_not_match=Użytkownik aplikacji nie jest aktualnym użytkownikiem: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Nie udało się zapisać konfiguracji: %v
invalid_admin_setting=Nieprawidłowe ustawienia konta admina: %v
install_success=Cześć! Cieszymy się, że wybierałeś Gogs, baw się dobrze.
@@ -124,6 +127,7 @@ uname_holder=Nazwa użytkownika lub e-mail
password_holder=Hasło
switch_dashboard_context=Przełącz kontekst pulpitu
my_repos=Moje repozytoria
show_more_repos=Pokaż więcej repozytoriów...
collaborative_repos=Wspólne repozytoria
my_orgs=Moje organizacje
my_mirrors=Moje kopie lustrzane
@@ -134,6 +138,7 @@ issues.in_your_repos=W Twoich repozytoriach
[explore]
repos=Repozytoria
users=Użytkownicy
organizations=Organizations
search=Wyszukiwanie
[auth]
@@ -148,16 +153,17 @@ forget_password=Zapomniałeś hasła?
sign_up_now=Potrzebujesz konta? Zarejestruj się teraz.
confirmation_mail_sent_prompt=Nowa wiadomość e-mail z potwierdzeniem została wysłana do <b>%s</b>, proszę sprawdzić swoją skrzynkę odbiorczą w ciągu najbliższych godzin %d aby dokończyć proces rejestracji.
active_your_account=Aktywuj swoje konto
prohibit_login=Logowanie zabronione
prohibit_login_desc=Nie możesz się zalogować na to konto, skontaktuj się z administratorem strony.
resent_limit_prompt=Niestety, zbyt często wysyłasz e-mail aktywacyjny. Proszę odczekać 3 minuty.
has_unconfirmed_mail=Witaj, %s, masz niepotwierdzony adres e-mail (<b>%s</b>). Jeśli nie otrzymałeś wiadomości e-mail z potwierdzeniem lub potrzebujesz wysłać nową, kliknij na poniższy przycisk.
resend_mail=Kliknij tutaj, aby wysłać e-mail aktywacyjny
email_not_associate=Ten adres e-mail nie jest skojarzony z żadnym kontem.
send_reset_mail=Kliknij tutaj, aby (ponownie) wysłać e-mail z instrukcjami resetowania hasła
reset_password=Resetowanie hasła
invalid_code=Niestety, Twój kod potwierdzający wygasł lub jest nieprawidłowy.
reset_password_helper=Kliknij tutaj, aby zresetować hasło
password_too_short=Długość hasła nie może być mniejsza niż 6 znaków.
non_local_account=Non-local accounts cannot change passwords through Gogs.
non_local_account=Nie lokalne konta nie mogą zmieniać haseł przez Gogs.
[mail]
activate_account=Prosimy aktywować swoje konto
@@ -184,6 +190,13 @@ TeamName=Nazwa zespołu
AuthName=Nazwa autoryzacji
AdminEmail=E-mail administratora
NewBranchName=Nazwa nowej gałęzi
CommitSummary=Podsumowanie commitu
CommitMessage=Wiadomość commitu
CommitChoice=Wybór commitu
TreeName=Ścieżka pliku
Content=Treść
require_error=` nie może być puste.`
alpha_dash_error=` musi się składać z prawidłowych znaków alfanumerycznych, myślników oraz podkreśleń.`
alpha_dash_dot_error=` musi się składać z prawidłowych znaków alfanumerycznych, myślników, podkreśleń oraz kropek.`
@@ -220,7 +233,7 @@ org_still_own_repo=Ta organizacja dalej jest właścicielem repozytorium, które
target_branch_not_exist=Gałąź docelowa nie istnieje.
[user]
change_avatar=Change your avatar
change_avatar=Zmień swój awatar
join_on=Dołączył
repositories=Repozytoria
activity=Publiczna aktywność
@@ -230,12 +243,13 @@ following=Obserwowani
follow=Obserwuj
unfollow=Przestań obserwować
form.name_reserved=Nazwa użytkownika "%s" jest zarezerwowana.
form.name_pattern_not_allowed=Wzorzec nazwy użytkownika "%s" jest niedozwolony.
form.name_reserved=Nazwa użytkownika %s jest zarezerwowana.
form.name_pattern_not_allowed=Wzorzec nazwy użytkownika %s jest niedozwolony.
[settings]
profile=Profil
password=Hasło
avatar=Awatar
ssh_keys=Klucze SSH
social=Konta społecznościowe
applications=Aplikacje
@@ -256,6 +270,8 @@ change_username_prompt=Ta zmiana wpłynie na sposób w jaki łącza odnoszą si
continue=Kontynuuj
cancel=Anuluj
lookup_avatar_by_mail=Wyszukaj Avatar po mailu
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=Włącz niestandardowe awatary
choose_new_avatar=Wybierz nowy avatar
update_avatar=Zaktualizuj ustawienia awatara
@@ -322,6 +338,10 @@ access_token_deletion=Usuwanie osobistego tokena dostępu
access_token_deletion_desc=Usunięcie tego tokena osobistego dostęp spowoduje usunięcie wszystkich powiązanych dostępów do aplikacji. Czy chcesz kontynuować?
delete_token_success=Osobisty token dostępu został usunięty pomyślnie! Nie zapomnij również zaktualizować swoich aplikacji.
orgs.none=You are not a member of any organizations.
orgs.leave_title=Leave an organization
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account=Usuń swoje konto
delete_prompt=Ta operacja trwale usunie Twoje konto i <strong>NIE MOŻE</strong> zostać cofnięta!
confirm_delete_account=Potwierdź usunięcie
@@ -342,7 +362,7 @@ fork_from=Forkuj z
fork_visiblity_helper=Fork nie może zmieniać swojej widoczności
repo_desc=Opis
repo_lang=Język
repo_lang_helper=Wybierz pliki .gitignore
repo_gitignore_helper=Wybierz szablony pliku .gitignore
license=Licencja
license_helper=Wybierz plik licencji
readme=Readme
@@ -350,25 +370,27 @@ readme_helper=Wybierz szablon readme
auto_init=Zainicjuj to repozytorium używając wybranych plików i szablonu
create_repo=Utwórz repozytorium
default_branch=Domyślna gałąź
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_prune=Wyczyść
mirror_prune_desc=Usuń wszystkie śledzone odwołania które nie istnieją w zdalnym repozytorium
mirror_interval=Częstotliwość kopiowania (godziny)
mirror_address=Adres kopii lustrzanej
mirror_address_desc=Proszę podać wymagane poświadczenia użytkownika w adresie.
mirror_last_synced=Ostatnia synchronizacja
watchers=Obserwujący
stargazers=Polubienia
forks=Forki
form.reach_limit_of_creation=Właściciel osiągnął limit maksymalnej ilości repozytoriów %d.
form.name_reserved=Nazwa repozytorium "%s" jest zarezerwowana.
form.name_pattern_not_allowed=Wzorzec nazwy repozytorium "%s" jest niedozwolony.
form.name_reserved=Nazwa repozytorium %s jest zarezerwowana.
form.name_pattern_not_allowed=Wzorzec nazwy repozytorium %s jest niedozwolony.
need_auth=Wymaga autoryzacji
migrate_type=Typ migracji
migrate_type_helper=To repozytorium będzie <span class="text blue">kopią lustrzaną</span>
migrate_repo=Przenieś repozytorium
migrate.clone_address=Sklonuj adres
migrate.clone_address_desc=To może być adres HTTP/HTTPS/GIT lub ścieżka lokalna serwera.
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=Nie możesz importować lokalnych repozytoriów.
migrate.invalid_local_path=Ścieżka jest niepoprawna. Nie istnieje lub nie jest katalogiem.
migrate.failed=Migracja nie powiodła się: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Utwórz nowe repozytorium z wiersza poleceń
push_exist_repo=Prześlij istniejące repozytorium z wiersza poleceń
repo_is_empty=To repozytorium jest puste, proszę wrócić później!
code=Kod
files=Files
branch=Gałąź
tree=Drzewo
filter_branch_and_tag=Filtruj gałąź lub tag
@@ -409,6 +431,47 @@ file_raw=Czysty
file_history=Historia
file_view_raw=Zobacz czysty
file_permalink=Bezpośredni odnośnik
file_too_large=Ten plik jest zbyt duży, aby go wyświetlić
video_not_supported_in_browser=Your browser doesn't support HTML5 video tag.
editor.new_file=Nowy plik
editor.upload_file=Załaduj plik
editor.edit_file=Edytuj plik
editor.preview_changes=Podgląd zmian
editor.cannot_edit_non_text_files=Nie można edytować plików nietekstowych
editor.edit_this_file=Edytuj ten plik
editor.must_be_on_a_branch=Musisz być na gałęzi aby zgłosić lub zaproponować zmiany do tego pliku
editor.fork_before_edit=Musisz sforkować to repozytorium przed edycją tego pliku
editor.delete_this_file=Usuń ten plik
editor.must_have_write_access=Musisz mieć uprawnienia do zapisu aby zgłosić lub zaproponować zmiany do tego pliku
editor.file_delete_success=Plik '%s' został usunięty pomyślnie!
editor.name_your_file=Nazwij plik...
editor.filename_help=Aby dodać katalog, wpisz nazwę i naciśnij przycisk /. Aby usunąć katalog, przejdź do początku pola i naciśnij klawisz backspace.
editor.or=lub
editor.cancel_lower=anuluj
editor.commit_changes=Zatwierdź zmiany
editor.add_tmpl=Dodaj '%s/<filename>'
editor.add=Dodaj '%s'
editor.update=Zaktualizuj '%s'
editor.delete=Usuń '%s'
editor.commit_message_desc=Dodaj dodatkowy rozszerzony opis...
editor.commit_directly_to_this_branch=Commituj bezpośrednio do gałęzi <strong class="branch-name">%s</strong>.
editor.create_new_branch=Stwórz <strong>nową gałąź</strong> dla tego commita i rozpocznij pull request.
editor.new_branch_name_desc=Nazwa nowej gałęzi...
editor.cancel=Anuluj
editor.filename_cannot_be_empty=Nazwa pliku nie może być pusta.
editor.branch_already_exists=Gałąź '%s' już istnieje w tym repozytorium.
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
editor.file_is_a_symlink=The file '%s' is a symlink that cannot be modified from the web editor.
editor.filename_is_a_directory=Nazwa '%s' jest istniejącym katalogiem w tym repozytorium.
editor.file_editing_no_longer_exists=Plik '%s' który edytujesz nie istnieje już w tym repozytorium.
editor.file_changed_while_editing=Zawartość pliku została zmieniona od rozpoczęcia edycji. <a target="_blank" href="%s">Kliknij tutaj</a> aby zobaczyć, co zostało zmienione lub <strong>naciśnij commit ponownie</strong> aby nadpisać te zmiany.
editor.file_already_exists=Nazwa pliku '%s' już istnieje w tym repozytorium.
editor.no_changes_to_show=Brak zmian do pokazania.
editor.fail_to_update_file=Tworzenie/aktualizacja pliku '%s' nie powiodła się z błędem: %v
editor.add_subdir=Dodaj podkatalog...
editor.unable_to_upload_files=Wysyłanie plików do '%s' nie powiodło się z błędem: %v
editor.upload_files_to_dir=Prześlij pliki do '%s'
commits.commits=Commity
commits.search=Przeszukaj commity
@@ -435,6 +498,11 @@ issues.create=Utwórz problem
issues.new_label=Nowa etykieta
issues.new_label_placeholder=Etykieta...
issues.create_label=Utwórz etykietę
issues.label_templates.title=Załaduj wstępnie przygotowany zestaw etykiet
issues.label_templates.info=Nie ma jeszcze żadnych etykiet. Kliknij na przycisk „Nowa etykieta” powyżej, aby utworzyć lub użyć poniższego zestawu wstępnie zdefiniowanego.
issues.label_templates.helper=Wybierz zestaw etykiet
issues.label_templates.use=Użyj ten zestaw etykiet
issues.label_templates.fail_to_load_file=Ładowanie pliku szablonu etykiety '%s' nie powiodło się: %v
issues.open_tab=Otwarte %d
issues.close_tab=Zamknięte %d
issues.filter_label=Etykieta
@@ -462,7 +530,8 @@ issues.next=Następny
issues.open_title=Otwarty
issues.closed_title=Zamknięty
issues.num_comments=%d komentarzy
issues.commented_at=`komentuje <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=`skomentował <a href="#%s">%s</a>`
issues.delete_comment_confirm=Czy na pewno chcesz usunąć ten komentarz?
issues.no_content=Nie ma jeszcze treści.
issues.close_issue=Zamknij
issues.close_comment_issue=Skomentuj i zamknij
@@ -475,8 +544,7 @@ issues.commit_ref_at=`wspomina ten problem w commicie <a id="%[1]s" href="#%[1]s
issues.poster=Autor
issues.collaborator=Współpracownik
issues.owner=Właściciel
issues.sign_up_for_free=Zarejestruj się za darmo
issues.sign_in_require_desc=do przyłączenia się do tej rozmowy. Masz już konto? <a href="%s">Zaloguj się by komentować</a>
issues.sign_in_require_desc=<a href="%s"> Zaloguj się</a>, aby dołączyć do tej rozmowy.
issues.edit=Edytuj
issues.cancel=Anuluj
issues.save=Zapisz
@@ -491,6 +559,8 @@ issues.label_deletion=Usunięcie etykiety
issues.label_deletion_desc=Usunięcie tej etykiety spowoduje usuniecie jej ze wszystkich powiązanych problemów. Czy na pewno chcesz kontynuować?
issues.label_deletion_success=Etykieta została usunięta pomyślnie!
issues.num_participants=%d uczestników
issues.attachment.open_tab=`Kliknij, aby zobaczyć „%s” w nowej karcie`
issues.attachment.download=`Kliknij, aby pobrać „%s”`
pulls.new=Nowy pull request
pulls.compare_changes=Porównaj zmiany
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Pull request nie może być automatycznie scalony z
pulls.cannot_auto_merge_helper=Proszę scalić ręcznie, aby rozwiązać konflikty.
pulls.merge_pull_request=Scal Pull Request
pulls.open_unmerged_pull_exists=`Nie można otworzyć ponownie ponieważ już istnieje gotowy do scalenia pull request (#%d) z tego samego repozytorium z tymi samymi informacjami.`
pulls.delete_branch=Delete Branch
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence.
milestones.new=Nowy kamień milowy
milestones.open_tab=Otwarte %d
@@ -532,7 +604,7 @@ milestones.desc=Opis
milestones.due_date=Termin realizacji (opcjonalnie)
milestones.clear=Wyczyść
milestones.invalid_due_date_format=Format daty realizacji jest nieprawidłowy, musi być "rrrr-mm-dd".
milestones.create_success=Kamień milowy "%s" został utworzony pomyślnie!
milestones.create_success=Kamień milowy %s został utworzony pomyślnie!
milestones.edit=Edytuj kamień milowy
milestones.edit_subheader=Użyj lepszego opisu, tak aby nie wprowadzać w błąd użytkowników.
milestones.cancel=Anuluj
@@ -555,7 +627,7 @@ wiki.last_commit_info=%s edytuje tę stronę %s
wiki.edit_page_button=Edytuj
wiki.new_page_button=Nowa strona
wiki.delete_page_button=Usuń stronę
wiki.delete_page_notice_1=Strona zostanie usunięta <code>"%s"</code>. Bądź ostrożny.
wiki.delete_page_notice_1=Strona zostanie usunięta <code>%s</code>. Bądź ostrożny.
wiki.page_already_exists=Strona Wiki o tej samej nazwie już istnieje.
wiki.pages=Strony
wiki.last_updated=Ostatnia aktualizacja %s
@@ -563,27 +635,34 @@ wiki.last_updated=Ostatnia aktualizacja %s
settings=Ustawienia
settings.options=Opcje
settings.collaboration=Współpraca
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.collaboration.admin=Administrator
settings.collaboration.write=Zapis
settings.collaboration.read=Odczyt
settings.collaboration.undefined=Niezdefiniowany
settings.hooks=Webhooki
settings.githooks=Hooki Git
settings.basic_settings=Ustawienia podstawowe
settings.mirror_settings=Kopia lustrzana ustawień
settings.sync_mirror=Synchronizuj teraz
settings.mirror_sync_in_progress=Synchronizacja kopii lustrzanej jest w toku, odśwież stronę w ciągu minuty.
settings.site=Oficjalna Strona
settings.update_settings=Aktualizuj ustawienia
settings.change_reponame_prompt=Zmiana nazwy repozytorium wpłynie na linki do niego.
settings.advanced_settings=Ustawienia zaawansowane
settings.wiki_desc=Włączenie Wiki pozwoli innym pisać dokumenty
settings.wiki_desc=Włącz system wiki
settings.use_internal_wiki=Użyj wbudowanego wiki
settings.use_external_wiki=Użyj zewnętrznego Wiki
settings.external_wiki_url=Adres URL zewnętrznego Wiki
settings.external_wiki_url_desc=Odwiedzający zostaną przekierowani do adresu URL po kliknięciu zakładki.
settings.issues_desc=Włącz wbudowany lekki system zgłaszania problemów
settings.issues_desc=Włącz system zgłaszania problemów
settings.use_internal_issue_tracker=Użyj wbudowany lekki system zgłaszania problemów
settings.use_external_issue_tracker=Użyj zewnętrznego systemu zgłaszania problemów
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Format dla adresu URL zewnętrznego systemu
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style=Styl nazw zewnętrznego systemu zgłaszania problemów:
settings.tracker_issue_style.numeric=Numeryczny
settings.tracker_issue_style.alphanumeric=Alfanumeryczne
settings.tracker_url_format_desc=Symbole zastępcze <code>{user} {repo} {index}</code> mogą być użyte dla nazwy użytkownika, nazwy repozytorium i numeru problemu.
settings.pulls_desc=Włącz obsługę pull request, aby akceptować publiczny wkład
settings.danger_zone=Strefa niebezpieczeństwa
@@ -606,7 +685,7 @@ settings.delete=Usuń to repozytorium
settings.delete_desc=Po usunięciu repozytorium nie ma odwrotu. Upewnij się, że tego chcesz.
settings.delete_notices_1=- Ta operacja <strong>NIE MOŻE</strong> zostać cofnięta.
settings.delete_notices_2=- Ta operacja trwale usunie wszystko z tego repozytorium, w tym dane Git, problemy, komentarze i dostęp dla współpracowników.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.delete_notices_fork_1=Wszystkie forki staną się niezależne po usunięciu.
settings.deletion_success=Repozytorium zostało pomyślnie usunięte!
settings.update_settings_success=Opcje repozytorium zostały pomyślnie zaktualizowane.
settings.transfer_owner=Nowy właściciel
@@ -653,6 +732,8 @@ settings.event_send_everything=Potrzebuję <strong>wszystkiego</strong>.
settings.event_choose=Pozwól mi wybrać, czego potrzebuję.
settings.event_create=Utwórz
settings.event_create_desc=Utworzono gałąź lub tag
settings.event_pull_request=Pull Request
settings.event_pull_request_desc=Otworzono żądanie pull, zamknięto, otwarto ponownie, zaktualizowano, przypisano, nieprzypisano, zaktualizowano etykietę, wyczyszczono etykietę lub zsynchronizowano.
settings.event_push=Wypchnięcie
settings.event_push_desc=Wypchnięcie (push) do repozytorium Git
settings.active=Aktywny
@@ -690,8 +771,8 @@ diff.show_unified_view=Zunifikowany widok
diff.stats_desc=<strong>%d zmienionych plików</strong> z <strong>%d dodań</strong> i <strong>%d usunięć</strong>
diff.bin=BIN
diff.view_file=Wyświetl plik
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
diff.file_suppressed=Plik diff jest za duży
diff.too_many_files=Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików
release.releases=Wydania
release.new_release=Nowe wydanie
@@ -712,7 +793,7 @@ release.write=Napisz
release.preview=Podgląd
release.loading=Ładowanie...
release.prerelease_desc=To jest wersja wstępna
release.prerelease_helper=Chcemy zwrócić uwagę, że ta wersja jest oznaczona jako eksperymentalna.
release.prerelease_helper=Oznacz to wydanie jako wersję wstępną.
release.cancel=Anuluj
release.publish=Publikuj wersję
release.save_draft=Zapisz szkic
@@ -722,6 +803,7 @@ release.deletion=Usuwanie wydania
release.deletion_desc=Usunięcie tego wydania spowoduje usunięcie odpowiednich tagów Git. Czy chcesz kontynuować?
release.deletion_success=Wydanie zostało pomyślnie usunięte!
release.tag_name_already_exist=Wersja o tej nazwie tagu już istnieje.
release.tag_name_invalid=Nazwa tagu jest niepoprawna.
release.downloads=Pliki do pobrania
[org]
@@ -743,8 +825,8 @@ team_name_helper=Będziesz używał tej nazwy do wywoływania tego zespołu w dy
team_desc_helper=Czym zajmuje się ten zespół?
team_permission_desc=Jaki poziom uprawnień powinien mieć ten zespół?
form.name_reserved=Nazwa organizacji "%s" jest zarezerwowana.
form.name_pattern_not_allowed=Wzorzec nazwy organizacji "%s" jest niedozwolony.
form.name_reserved=Nazwa organizacji %s jest zarezerwowana.
form.name_pattern_not_allowed=Wzorzec nazwy organizacji %s jest niedozwolony.
settings=Ustawienia
settings.options=Opcje
@@ -889,6 +971,7 @@ users.edit_account=Edytuj konto
users.max_repo_creation=Maksymalna liczba repozytoriów
users.max_repo_creation_desc=(Ustaw -1, aby użyć globalnego limitu)
users.is_activated=To konto jest aktywne
users.prohibit_login=Nie możesz się zalogować na to konto
users.is_admin=To konto ma uprawnienia administratora
users.allow_git_hook=To konto posiada uprawnienia do tworzenia hooków Git
users.allow_import_local=To konto ma uprawnienia do importu lokalnych repozytoriów
@@ -919,7 +1002,7 @@ auths.enabled=Włączono
auths.updated=Zaktualizowano
auths.auth_type=Typ uwierzytelniania
auths.auth_name=Nazwa uwierzytelniania
auths.security_protocol=Security Protocol
auths.security_protocol=Protokół zabezpieczeń
auths.domain=Domena
auths.host=Host
auths.port=Port
@@ -957,6 +1040,7 @@ auths.delete_auth_title=Usunięcie uwierzytelnienia
auths.delete_auth_desc=To uwierzytelnienie zostanie usunięte, czy chcesz kontynuować?
auths.still_in_used=Ten rodzaj autentykacji jest wciąż wykorzystywany przez niektórych użytkowników. Usuń lub przekonwertuj użytkowników, aby wykorzystywali inny typ logowania.
auths.deletion_success=Uwierzytelnienie zostało usunięte pomyślnie!
auths.login_source_exist=Login source '%s' already exists.
config.server_config=Konfiguracja serwera
config.app_name=Nazwa aplikacji
@@ -967,6 +1051,7 @@ config.offline_mode=Tryb offline
config.disable_router_log=Wyłącz dziennik routera
config.run_user=Użytkownik uruchomieniowy
config.run_mode=Tryb uruchamienia
config.git_version=Git Version
config.repo_root_path=Ścieżka repozytoriów
config.static_file_root_path=Ścieżka plików statycznych
config.log_file_root_path=Ścieżka plików dziennika
@@ -991,9 +1076,10 @@ config.db_host=Host
config.db_name=Nazwa
config.db_user=Użytkownik
config.db_ssl_mode=Tryb SSL
config.db_ssl_mode_helper=(tylko dla "postgres")
config.db_ssl_mode_helper=(tylko dla postgres)
config.db_path=Ścieżka
config.db_path_helper=(dla "sqlite3" i "tidb")
config.db_path_helper=(dla sqlite3 i tidb)
config.service_config=Konfiguracja usługi
config.register_email_confirm=Wymagaj potwierdzenia e-mail
config.disable_register=Wyłącz rejestrację
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Wyłącz sprawdzanie minimalnego rozmiaru klucza
config.enable_captcha=Włącz Captcha
config.active_code_lives=Ważność kodów aktywacyjnych
config.reset_password_code_lives=Czas życia kodu resetowania hasła
config.webhook_config=Konfiguracja webhooka
config.queue_length=Długość kolejki
config.deliver_timeout=Limit czasu zdarzenia
config.skip_tls_verify=Pomiń weryfikację protokołu TLS
config.mailer_config=Konfiguracja poczty
config.mailer_enabled=Aktywne
config.mailer_disable_helo=Wyłącz HELO
@@ -1017,12 +1105,15 @@ config.mailer_user=Użytkownik
config.send_test_mail=Wyślij email testowy
config.test_mail_failed=Nieudane wysłanie wiadomości email do '%s': %v
config.test_mail_sent=Testowa wiadomość email została wysłana do '%s'.
config.oauth_config=Konfiguracja OAuth
config.oauth_enabled=Aktywne
config.cache_config=Konfiguracja cache
config.cache_adapter=Adapter cache
config.cache_interval=Interwał pamięci podręcznej
config.cache_conn=Połączenie z pamięcią podręczną
config.session_config=Konfiguracja sesji
config.session_provider=Dostawca sesji
config.provider_config=Konfiguracja dostawcy
@@ -1032,9 +1123,24 @@ config.gc_interval_time=Interwał odśmiecania
config.session_life_time=Czas życia sesji
config.https_only=Tylko HTTPS
config.cookie_life_time=Czas życia ciasteczka
config.picture_config=Ustawienia obrazów
config.picture_service=Serwis obrazów
config.disable_gravatar=Wyłącz Gravatara
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Konfiguracja Git
config.git_disable_diff_highlight=Wyłączyć wyróżnianie składni diff
config.git_max_diff_lines=Maksymalna ilość linii diff (dla pojedynczego pliku)
config.git_max_diff_line_characters=Maksymalna ilość znaków diff (dla pojedynczego pliku)
config.git_max_diff_files=Maksymalna ilość plików diff (które zostaną wyświetlone)
config.git_gc_args=Argumenty GC
config.git_migrate_timeout=Limit czasu migracji
config.git_mirror_timeout=Limit czasu aktualizacji kopii lustrzanej
config.git_clone_timeout=Limit czasu operacji klonowania
config.git_pull_timeout=Limit czasu dla operacji pull
config.git_gc_timeout=Limit czasu odśmiecania pamięci
config.log_config=Konfiguracja dziennika
config.log_mode=Tryb dziennika

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@ home=Главная
dashboard=Панель управления
explore=Обзор
help=Помощь
sign_in=Войти
sign_in=Вход
sign_out=Выход
sign_up=Регистрация
register=Регистрация
@@ -27,7 +27,7 @@ repository=Репозиторий
organization=Организация
mirror=Зеркало
new_repo=Новый репозиторий
new_migrate=Новая Миграция
new_migrate=Новая миграция
new_mirror=Новое зеркало
new_fork=Новое ответвление репозитория
new_org=Новая организация
@@ -96,6 +96,8 @@ offline_mode=Включение офлайн режима
offline_mode_popup=Отключить CDN даже в производственном режиме, все файлы ресурсов будут раздаваться локально.
disable_gravatar=Отключить службу Gravatar
disable_gravatar_popup=Отключить Gravatar и пользовательские источники, все аватары по-умолчанию загружаются пользователями.
federated_avatar_lookup=Включить поиск внешних Аватаров
federated_avatar_lookup_popup=Включите Поиск федеративного аватара для использования федеративной службы с открытым исходным кодом на основе libravatar.
disable_registration=Отключить самостоятельную регистрацию
disable_registration_popup=Запретить пользователям самостоятельную регистрацию, только администратор может создавать аккаунты.
enable_captcha=Включить капчу
@@ -114,6 +116,7 @@ sqlite3_not_available=Ваша версия не поддерживает SQLite
invalid_db_setting=Настройки базы данных не правильные: %v
invalid_repo_path=Недопустимый путь к корню репозитория: %v
run_user_not_match=Текущий пользователь не является пользователем для запуска: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Не удалось сохранить конфигурацию: %v
invalid_admin_setting=Указан недопустимый параметр учетной записи администратора: %v
install_success=Добро пожаловать! Мы рады, что вы выбрали Gogs. Веселитесь и берегите себя.
@@ -124,6 +127,7 @@ uname_holder=Имя пользователь или E-mail
password_holder=Пароль
switch_dashboard_context=Переключить контекст панели управления
my_repos=Мои репозитории
show_more_repos=Показать больше репозиториев...
collaborative_repos=Совместные репозитории
my_orgs=Мои организации
my_mirrors=Мои зеркала
@@ -134,6 +138,7 @@ issues.in_your_repos=В ваших репозиториях
[explore]
repos=Репозитории
users=Пользователи
organizations=Организации
search=Поиск
[auth]
@@ -148,10 +153,11 @@ forget_password=Забыли пароль?
sign_up_now=Нужен аккаунт? Зарегистрируйтесь.
confirmation_mail_sent_prompt=Новое письмо для подтверждения было направлено на <b>%s</b>, пожалуйста, проверьте ваш почтовый ящик в течение %d часов для завершения регистрации.
active_your_account=Активируйте свой аккаунт
prohibit_login=Вход запрещен
prohibit_login_desc=Вход для вашей учетной записи был запрещен, пожалуйста, свяжитесь с администратором сайта.
resent_limit_prompt=Извините, вы уже запросили активацию по электронной почте недавно. Пожалуйста, подождите 3 минуты, а затем повторите попытку.
has_unconfirmed_mail=Здравствуйте, %s! У вас есть неподтвержденный адрес электронной почты (<b>%s</b>). Если вам не приходило письмо с подтверждением или нужно выслать новое письмо, нажмите на кнопку ниже.
resend_mail=Нажмите здесь, чтобы переотправить активационное письмо
email_not_associate=Этот адрес электронной почты не связан ни с одной учетной записью.
send_reset_mail=Нажмите сюда, чтобы отправить письмо для сброса пароля
reset_password=Сброс пароля
invalid_code=Извините, ваш код подтверждения истек или не является допустимым.
@@ -184,6 +190,13 @@ TeamName=Название команды
AuthName=Имя авторизации
AdminEmail=Электронная почта администратора
NewBranchName=Новая ветка
CommitSummary=Резюме коммита
CommitMessage=Зафиксировать сообщение
CommitChoice=Выбор коммита
TreeName=Путь к файлу
Content=Содержимое
require_error=` не может быть пустым.`
alpha_dash_error=«должен быть допустимым символьным, числовым или dash(-_) значением.»
alpha_dash_dot_error=«должен быть допустимым символьным, числовым или dash(-_) символами, включая точку.»
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=Имя пользователя «%s» не доп
[settings]
profile=Профиль
password=Пароль
avatar=Аватар
ssh_keys=SSH ключи
social=Учетные записи в соцсетях
applications=Приложения
@@ -256,6 +270,8 @@ change_username_prompt=Это изменение может повлечь за
continue=Далее
cancel=Отмена
lookup_avatar_by_mail=Найти Аватар по адресу эл. почты
federated_avatar_lookup=Найти внешний Аватар
enable_custom_avatar=Включить собственный аватар
choose_new_avatar=Выбрать новый аватар
update_avatar=Обновить настройку аватара
@@ -322,6 +338,10 @@ access_token_deletion=Удаление личного токена доступ
access_token_deletion_desc=Удаление этого персонального токена доступа приведет к удалению всех связанных прав доступа к приложению. Вы хотите продолжить?
delete_token_success=Персональный токен доступа успешно удален! Не забудьте изменить настройки вашего приложения.
orgs.none=Вы не состоите ни в одной организации.
orgs.leave_title=Покинуть организацию
orgs.leave_desc=Вы потеряете доступ ко всем репозиториям и командам, как только покинете организацию. Вы хотите продолжить?
delete_account=Удалить свой аккаунт
delete_prompt=Этим действием вы удалите свою учетную запись навсегда и <strong>НЕ СМОЖЕТЕ</strong> ее вернуть!
confirm_delete_account=Подтвердите удаление
@@ -342,7 +362,7 @@ fork_from=Ответвление от
fork_visiblity_helper=Ответвленному репозиторию нельзя поменять уровень видимости
repo_desc=Описание
repo_lang=Язык
repo_lang_helper=Выберите файлы .gitignore
repo_gitignore_helper=Выберите шаблоны .gitignore
license=Лицензия
license_helper=Выберите файл лицензии
readme=Readme
@@ -351,10 +371,11 @@ auto_init=Инициализировать этот репозиторий вы
create_repo=Создать репозиторий
default_branch=Ветка по умолчанию
mirror_prune=Очистить
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_prune_desc=Удалите ссылки на удаленно отслеживаемые объекты, которых больше нет на удаленном сервере
mirror_interval=Интервал зеркалирования (час)
mirror_address=Адрес зеркала
mirror_address_desc=Укажите необходимые учетные данные в адрес.
mirror_last_synced=Последняя синхронизация
watchers=Наблюдатели
stargazers=Звездочеты
forks=Ответвления
@@ -368,7 +389,8 @@ migrate_type=Тип миграции
migrate_type_helper=Этот репозиторий будет <span class="text blue">зеркалом</span>
migrate_repo=Перенос репозитория
migrate.clone_address=Скопировать адрес
migrate.clone_address_desc=Это может быть HTTP/HTTPS/GIT адрес или локальный путь на сервере.
migrate.clone_address_desc=Это может быть HTTP/HTTPS/GIT URL-адрес.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=У вас нет прав на импорт локальных репозиториев.
migrate.invalid_local_path=Недопустимый локальный путь. Возможно он не существует или является не папкой.
migrate.failed=Миграция не удалась: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Создать новый репозиторий из к
push_exist_repo=Отправить существующий репозиторий из командной строки
repo_is_empty=Этот репозиторий пуст, пожалуйста, возвращайтесь позже!
code=Код
files=Файлы
branch=Ветка
tree=Дерево
filter_branch_and_tag=Фильтр по ветке или тегу
@@ -409,6 +431,47 @@ file_raw=Исходник
file_history=История
file_view_raw=Посмотреть исходник
file_permalink=Постоянная ссылка
file_too_large=Этот файл слишком большой, поэтому он не может быть отображен
video_not_supported_in_browser=Ваш браузер не поддерживает HTML5 видео тэг.
editor.new_file=Новый файл
editor.upload_file=Загрузить файл
editor.edit_file=Редактировать файл
editor.preview_changes=Просмотр изменений
editor.cannot_edit_non_text_files=Возможно редактировать только текстовые файлы
editor.edit_this_file=Отредактируйте этот файл
editor.must_be_on_a_branch=Чтобы сделать или предложить изменения вы должны выбрать ветку
editor.fork_before_edit=Создайте ветку репозитория перед редактированием файла
editor.delete_this_file=Удалить файл
editor.must_have_write_access=Вам необходимо иметь доступ на запись, чтобы вносить или предлагать правки этого файла
editor.file_delete_success=Файл «%s» был успешно удален!
editor.name_your_file=Назовите свой файл...
editor.filename_help=Чтобы добавить каталог, просто наберите название и нажмите /. Чтобы удалить каталог, перейдите к началу поля и нажмите клавишу backspace.
editor.or=или
editor.cancel_lower=отмена
editor.commit_changes=Фиксация изменений
editor.add_tmpl=Добавить '%s/<filename>'
editor.add=Добавить '%s'
editor.update=Обновить '%s'
editor.delete=Удалить '%s'
editor.commit_message_desc=Добавьте необязательное расширенное описание...
editor.commit_directly_to_this_branch=Сделайте коммит прямо в ветку <strong class="branch-name">%s</strong>.
editor.create_new_branch=Создайте <strong>новую ветвь</strong> для этого коммита, и сделайте пул запрос.
editor.new_branch_name_desc=Новое название ветки...
editor.cancel=Отмена
editor.filename_cannot_be_empty=Имя файла не может быть пустым.
editor.branch_already_exists=Ветка «%s» уже существует в этом репозитории.
editor.directory_is_a_file=Запись «%s» в пути на верх является файлом, а не каталогом этого репозитория.
editor.file_is_a_symlink=Файл '%s' является символической ссылкой, которая не может быть изменена через веб-редактор.
editor.filename_is_a_directory=Файл «%s» является каталогом в этом репозитории.
editor.file_editing_no_longer_exists=Редактируемый вами файл «%s» больше не существует в репозитории.
editor.file_changed_while_editing=Содержимое файла изменилось со времени начала редактирования. <a target="_blank" href="%s"> нажмите здесь,</a> чтобы увидеть, что было изменено, или <strong>нажмите кнопку commit снова</strong>, чтобы перезаписать эти изменения.
editor.file_already_exists=Файл с именем «%s» уже существует в этом репозитории.
editor.no_changes_to_show=Нет изменений.
editor.fail_to_update_file=Не удалось обновить/создать файл «%s» из-за ошибки: %v
editor.add_subdir=Добавьте подкаталог...
editor.unable_to_upload_files=Не удалось загрузить файлы в «%s» из-за ошибки: %v
editor.upload_files_to_dir=Загрузить файлы '%s'
commits.commits=Коммиты
commits.search=Поиск коммитов
@@ -435,6 +498,11 @@ issues.create=Добавить задачу
issues.new_label=Новая метка
issues.new_label_placeholder=Имя метки...
issues.create_label=Добавить метку
issues.label_templates.title=Загрузить набор предопределённых меток
issues.label_templates.info=Меток пока нет. Вы можете нажать на кнопку «Создать метку», чтобы создать новую или использовать одну из готового набора ниже.
issues.label_templates.helper=Выберите метку
issues.label_templates.use=Использовать ярлык
issues.label_templates.fail_to_load_file=Не удалось загрузить файл шаблона метки «%s»: %v
issues.open_tab=%d открыто(ы)
issues.close_tab=%d закрыто(ы)
issues.filter_label=Метка
@@ -462,7 +530,8 @@ issues.next=Следующая страница
issues.open_title=Открыто
issues.closed_title=Закрыто
issues.num_comments=комментариев: %d
issues.commented_at=` прокомментировал <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commented_at=«прокомментировал <a href="#%s"> %s</a>»
issues.delete_comment_confirm=Вы уверены, что хотите удалить этот комментарий?
issues.no_content=Пока нет содержимого.
issues.close_issue=Закрыть
issues.close_comment_issue=Прокомментировать и закрыть
@@ -475,8 +544,7 @@ issues.commit_ref_at=`упомянул эту задачу в коммите <a
issues.poster=Автор
issues.collaborator=Соавтор
issues.owner=Владелец
issues.sign_up_for_free=Зарегистрируйтесь бесплатно
issues.sign_in_require_desc=чтобы присоединиться к обсуждению. Уже есть аккаунт? <a href="%s">Войдите чтобы прокомментировать</a>
issues.sign_in_require_desc=<a href="%s">Войдите</a>, чтобы присоединиться к обсуждению.
issues.edit=Изменить
issues.cancel=Отмена
issues.save=Сохранить
@@ -491,6 +559,8 @@ issues.label_deletion=Удаление метки
issues.label_deletion_desc=Удаление ярлыка затронет все связанные задачи. Продолжить?
issues.label_deletion_success=Метка была удалена успешно!
issues.num_participants=%d участников
issues.attachment.open_tab=`Нажмите, чтобы увидеть "%s" в новой вкладке`
issues.attachment.download=`Нажмите, чтобы скачать "%s"`
pulls.new=Новый запрос на слияние
pulls.compare_changes=Сравнить изменения
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Этот запрос на слияние не мо
pulls.cannot_auto_merge_helper=Пожалуйста, совершите слияние вручную для урегулирования конфликтов.
pulls.merge_pull_request=Слить пулл-реквест
pulls.open_unmerged_pull_exists=`Вы не можете снова открыть, поскольку уже существует запрос на слияние (#%d) из того же репозитория с той же информацией о слиянии и ожидающий слияния. `
pulls.delete_branch=Удалить ветку
pulls.delete_branch_has_new_commits=Нельзя удалить ветку, так как она имеет новые коммиты после слияния.
milestones.new=Новая контрольная точка
milestones.open_tab=%d открыты
@@ -570,20 +642,27 @@ settings.collaboration.undefined=Не определено
settings.hooks=Автоматическое обновление
settings.githooks=Git хуки
settings.basic_settings=Основные параметры
settings.mirror_settings=Настройки Зеркала
settings.sync_mirror=Синхронизировать
settings.mirror_sync_in_progress=Выполняется синхронизация Зеркала, пожалуйста, обновите эту страницу через минуту.
settings.site=Официальный сайт
settings.update_settings=Обновить настройки
settings.change_reponame_prompt=Это изменение повлияет на отношения ссылок к этому репозиторию.
settings.advanced_settings=Расширенные настройки
settings.wiki_desc=Включить Вики, чтобы позволить людям писать документы
settings.wiki_desc=Включить систему Wiki
settings.use_internal_wiki=Использовать встроенную wiki
settings.use_external_wiki=Использовать внешнюю Wiki
settings.external_wiki_url=URL-адрес внешней Вики
settings.external_wiki_url_desc=Посетители будут перенаправлены на URL-адрес, когда они кликнут по вкладке.
settings.issues_desc=Включить встроенную, легковесную систему отслеживания ошибок
settings.issues_desc=Включить систему отслеживания ошибок
settings.use_internal_issue_tracker=Использовать встроенную легковесную систему отслеживания ошибок
settings.use_external_issue_tracker=Использовать внешнюю систему отслеживания ошибок
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Внешний формат ссылки системы отслеживания ошибок.
settings.tracker_issue_style=Стиль Именования Внешней Системы Учета Задач:
settings.tracker_issue_style.numeric=Числовой <span class="ui light grey text"> (1234)</span>
settings.tracker_issue_style.alphanumeric=Буквенно-цифровой <span class="ui light grey text"> (ABC-123, DEF-234,...)</span>
settings.tracker_issue_style.numeric=Цифровой
settings.tracker_issue_style.alphanumeric=Буквенноцифровой
settings.tracker_url_format_desc=Вы можете использовать шаблон <code>{user} {repo} {index}</code> для имени пользователя, репозитория и номера задачи.
settings.pulls_desc=Включить публичные запросы на слияние
settings.danger_zone=Опасная зона
@@ -608,7 +687,7 @@ settings.delete_notices_1=- Эта операция <strong>НЕ МОЖЕТ</str
settings.delete_notices_2=- Эта операция навсегда удалит всё из этого репозитория, включая данные Git, связанные с ним задачи, комментарии и права доступа для сотрудников.
settings.delete_notices_fork_1=- Все отвлетвления станут независимыми после удаления.
settings.deletion_success=Репозиторий был успешно удалён!
settings.update_settings_success=Настройка репозитория обновлена успешно.
settings.update_settings_success=Настройки репозитория обновлены успешно.
settings.transfer_owner=Новый владелец
settings.make_transfer=Выполнить передачу
settings.transfer_succeed=Владение репозиторием было успешно передано.
@@ -653,6 +732,8 @@ settings.event_send_everything=Мне нужно <strong>все</strong>.
settings.event_choose=Позвольте мне выбрать то, что нужно.
settings.event_create=Создать
settings.event_create_desc=Ветка или тэг созданы
settings.event_pull_request=Запросы на слияние
settings.event_pull_request_desc=Запрос слияния открыт, закрыт, переоткрыт, изменён, назначен, снят, метка обновлена, метка убрана, или синхронизирован.
settings.event_push=Push
settings.event_push_desc=Push в репозиторий
settings.active=Активен
@@ -690,8 +771,8 @@ diff.show_unified_view=Единый вид
diff.stats_desc=<strong> %d измененных файлов</strong> с <strong>%d добавлено</strong> и <strong>%d удалено</strong>
diff.bin=BIN
diff.view_file=Просмотреть файл
diff.file_supressed=Разница между файлами не показана из-за своего большого размера
diff.too_many_files=Некоторые файлы не были показать из-за большого количества измененных файлов
diff.file_suppressed=Разница между файлами не показана из-за своего большого размера
diff.too_many_files=Некоторые файлы не были показаны из-за большого количества измененных файлов
release.releases=Релизы
release.new_release=Новый релиз
@@ -722,6 +803,7 @@ release.deletion=Удаление релиза
release.deletion_desc=Удаление этого релиза удалит соответствующую Git метку. Вы хотите продолжить?
release.deletion_success=Релиз был успешно удален!
release.tag_name_already_exist=Релиз с этим именем метки уже существует.
release.tag_name_invalid=Имя тега является не допустимым.
release.downloads=Загрузки
[org]
@@ -806,7 +888,7 @@ teams.add_nonexistent_repo=Вы добавляете в отсутствующи
[admin]
dashboard=Панель управления
users=Пользователи
organizations=Организации
organizations=Группы
repositories=Репозитории
authentication=Авторизация
config=Настройки
@@ -889,6 +971,7 @@ users.edit_account=Изменение учетной записи
users.max_repo_creation=Ограничение максимального количества создаваемых репозиториев
users.max_repo_creation_desc=(Установить -1 для использования стандартного глобального значения предела)
users.is_activated=Эта учетная запись активирована
users.prohibit_login=Вход с данной учетной записи запрещен
users.is_admin=У этой учетной записи есть права администратора
users.allow_git_hook=Пользователь имеет право создать Git перехватчик
users.allow_import_local=Пользователь имеет право импортировать локальные репозитории
@@ -957,6 +1040,7 @@ auths.delete_auth_title=Удаление канала аутентификаци
auths.delete_auth_desc=Этот канал аутентификации будет удален. Вы уверены что хотите продолжить?
auths.still_in_used=Эта проверка подлинности до сих пор используется некоторыми пользователями, удалите или преобразуйте этих пользователей в другой тип входа в систему.
auths.deletion_success=Канал аутентификации успешно удален!
auths.login_source_exist=Источник входа '%s' уже существует.
config.server_config=Конфигурация сервера
config.app_name=Имя приложения
@@ -967,6 +1051,7 @@ config.offline_mode=Автономный режим
config.disable_router_log=Отключение журнала маршрутизатора
config.run_user=Запуск пользователем
config.run_mode=Режим выполнения
config.git_version=Git Version
config.repo_root_path=Путь до корня репозитория
config.static_file_root_path=Статичный путь до файла
config.log_file_root_path=Путь до папки с логами
@@ -994,6 +1079,7 @@ config.db_ssl_mode=Режим SSL
config.db_ssl_mode_helper=(только для «postgres»)
config.db_path=Путь
config.db_path_helper=(для "SQLite3" и "TiDB")
config.service_config=Сервисная конфигурация
config.register_email_confirm=Требуется подтверждение по электронной почте
config.disable_register=Отключить регистрацию
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Отключить проверку на мини
config.enable_captcha=Включить капчу
config.active_code_lives=Время жизни кода для активации
config.reset_password_code_lives=Время жизни кода сброса пароля
config.webhook_config=Настройка автоматического обновления репозиции
config.queue_length=Длина очереди
config.deliver_timeout=Задержка доставки
config.skip_tls_verify=Пропустить TLS проверка
config.mailer_config=Настройки почты
config.mailer_enabled=Включено
config.mailer_disable_helo=Отключить HELO
@@ -1017,12 +1105,15 @@ config.mailer_user=Пользователь
config.send_test_mail=Отправить тестовое письмо
config.test_mail_failed=Не удалось отправить тестовое письмо «%s»: %v
config.test_mail_sent=Тестовое письмо было отправлено «%s».
config.oauth_config=Конфигурация OAuth
config.oauth_enabled=Включено
config.cache_config=Настройки кеша
config.cache_adapter=Адаптер кэша
config.cache_interval=Интервал кэширования
config.cache_conn=Подключение кэша
config.session_config=Конфигурация сессии
config.session_provider=Провайдер сессии
config.provider_config=Конфигурация провайдера
@@ -1032,9 +1123,24 @@ config.gc_interval_time=Интервал работы сборщика мусо
config.session_life_time=Время жизни сессии
config.https_only=Только HTTPS
config.cookie_life_time=Время жизни файла cookie
config.picture_config=Настройка изображения
config.picture_service=Сервис изображений
config.disable_gravatar=Отключить Gravatar
config.enable_federated_avatar=Включить внешние Аватары
config.git_config=Конфигурация GIT
config.git_disable_diff_highlight=Отключить подсветку синтаксиса Diff
config.git_max_diff_lines=Максимальное количество строк Diff (на файл)
config.git_max_diff_line_characters=Максимальное количество символов Diff (в строке)
config.git_max_diff_files=Максимальное количество Diff-файлов (при показе)
config.git_gc_args=Аргументы GC
config.git_migrate_timeout=Тайм-аут миграции
config.git_mirror_timeout=Время Ожидания Обновления Зеркала
config.git_clone_timeout=Время Ожидания Операции Клонирования
config.git_pull_timeout=Время Ожидания Операции Извлечения
config.git_gc_timeout=Время Ожидания Операции Сборки Мусора
config.log_config=Конфигурация журнала
config.log_mode=Режим журналирования

1214
conf/locale/locale_sr-SP.ini Normal file

File diff suppressed because it is too large Load Diff

1214
conf/locale/locale_sv-SE.ini Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -96,6 +96,8 @@ offline_mode=Çevrim Dışı Modu Etkinleştir
offline_mode_popup=CDN'i, üretim modunda bile devre dışı bırak, tüm kaynak dosyaları yerel olarak sunulacaktır.
disable_gravatar=Gravatar Servisini Devre Dışı Bırak
disable_gravatar_popup=Gravatar ve özel kaynakları devre dışı bırak. Tüm avatarlar kullanıcılar tarafından yüklenir veya varsayılan kalır.
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Kendi Kendine Kaydolmayı Devre Dışı Bırak
disable_registration_popup=Kullanıcının kendi kendine kaydolmasını devre dışı bırak, yalnızca yönetici yeni hesaplar oluşturabilir.
enable_captcha=Captcha'yı Etkinleştir
@@ -114,6 +116,7 @@ sqlite3_not_available=Yayın sürümünüz SQLite3'ü desteklemiyor, lütfen %s'
invalid_db_setting=Veritabanı ayarları geçersiz: %v
invalid_repo_path=Depo kök dizini geçersiz: %v
run_user_not_match=Çalıştırma kullanıcısı geçerli kullanıcı değil: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Yapılandırma kaydedilemedi: %v
invalid_admin_setting=Yönetici hesap ayarları geçersiz: %v
install_success=Merhaba! Gogs'u tercih ettiğiniz için çok mutluyuz, keyfini çıkarın!
@@ -124,6 +127,7 @@ uname_holder=Kullanıcı Adı veya E-Posta
password_holder=Parola
switch_dashboard_context=Panoya Geçiş Yap
my_repos=Depolarım
show_more_repos=Daha fazla depo göster...
collaborative_repos=Katkıya Açık Depolar
my_orgs=Organizasyonlarım
my_mirrors=Yansılarım
@@ -134,6 +138,7 @@ issues.in_your_repos=Depolarınızda
[explore]
repos=Depolar
users=Kullanıcılar
organizations=Organizations
search=Ara
[auth]
@@ -148,16 +153,17 @@ forget_password=Parolanızı mı unuttunuz?
sign_up_now=Bir hesaba mı ihtiyacınız var? Şimdi kaydolun.
confirmation_mail_sent_prompt=<b>%s</b> adresinize yeni bir doğrulama e-postası gönderildi, kaydolma aşamalarını tamamlamak için lütfen %d saat içinde e-posta adresinizi kontrol edin.
active_your_account=Hesabınızı Aktifleştirin
prohibit_login=Oturum açılması yasak
prohibit_login_desc=Hesabınızla oturum açmanız yasaklanmış, lütfen site yöneticisi ile iletişime geçin.
resent_limit_prompt=Üzgünüz, zaten bir doğrulama e-postası talep ettiniz. Lütfen 3 dakika bekleyip tekrar deneyin.
has_unconfirmed_mail=Merhaba %s, doğrulanmamış bir e-posta adresin var (<b>%s</b>). Bir doğrulama e-postası almadıysanız ya da yenisine ihtiyacınız varsa lütfen aşağıdaki düğmeye tıklayın.
resend_mail=Doğrulama e-postasını tekrar almak için buraya tıklayın
email_not_associate=Bu e-posta adresi hiçbir hesaba bağlı değil.
send_reset_mail=Parola sıfırlama e-postasını (yeniden) göndermek için buraya tıklayın
reset_password=Parolanızı Sıfırlayın
invalid_code=Üzgünüz, doğrulama kodunuz geçersiz veya süresi dolmuş.
reset_password_helper=Parolanızı sıfırlamak için buraya tıklayın
password_too_short=Parola uzunluğu 6 karakterden az olamaz.
non_local_account=Non-local accounts cannot change passwords through Gogs.
non_local_account=Yerel olmayan hesapların şifrelerini Gogs aracılığıyla değiştiremezsiniz.
[mail]
activate_account=Lütfen hesabınızı aktifleştirin
@@ -184,6 +190,13 @@ TeamName=Takım ismi
AuthName=Yetkilendirme adı
AdminEmail=Yönetici e-postası
NewBranchName=New branch name
CommitSummary=Commit summary
CommitMessage=Commit message
CommitChoice=Commit choice
TreeName=Dosya yolu
Content=Content
require_error=` boş olamaz.`
alpha_dash_error=` sadece karakter, rakam veya çizgi(-_) içermelidir.`
alpha_dash_dot_error=` sadece karakter, rakam, çizgi(-_) veya nokta içermelidir.`
@@ -220,7 +233,7 @@ org_still_own_repo=Bu organizasyon hala bazı depoların sahibi durumunda. Önce
target_branch_not_exist=Hedef dal mevcut değil.
[user]
change_avatar=Change your avatar
change_avatar=Profil resmini değiştir
join_on=Şuna katıldınız
repositories=Depolar
activity=Genel Aktivite
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=Kullanıcı adında '%s' modeline izin verilmez.
[settings]
profile=Profil
password=Parola
avatar=Avatar
ssh_keys=SSH Anahtarları
social=Sosyal Medya Hesapları
applications=Uygulamalar
@@ -256,6 +270,8 @@ change_username_prompt=Bu değişiklik, hesabınızla ilişkili olan bağlantıl
continue=Devam Et
cancel=İptal
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=Özel Avatarı Etkinleştir
choose_new_avatar=Yeni Avatar Seç
update_avatar=Avatar Ayarlarını Güncelle
@@ -322,6 +338,10 @@ access_token_deletion=Kişisel Erişim Anahtarını Silme
access_token_deletion_desc=Bu kişisel erişim anahtarını silerseniz uygulamanıza ilişkin tüm erişimler de kaldırılacaktır. Devam etmek istiyor musunuz?
delete_token_success=Kişisel erişim anahtarı başarıyla kaldırıldı! Uygulamanızı güncellemeyi de unutmayın!
orgs.none=You are not a member of any organizations.
orgs.leave_title=Leave an organization
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account=Hesabınızı Silin
delete_prompt=Bu işlem hesabınızı kalıcı olarak silecektir ve <strong>GERİ ALINAMAZ</strong>!
confirm_delete_account=Silmeyi Onayla
@@ -342,7 +362,7 @@ fork_from=Buradan Çatalla
fork_visiblity_helper=Çatallanmış bir deponun görünürlüğünü değiştiremezsiniz.
repo_desc=ıklama
repo_lang=Dil
repo_lang_helper=.gitignore dosyalarını seçin
repo_gitignore_helper=Select .gitignore templates
license=Lisans
license_helper=Bir lisans dosyası seçin
readme=Benioku
@@ -350,11 +370,12 @@ readme_helper=Bir benioku şablonu seçin
auto_init=Bu depoyu seçilen dosya ve şablonlarla oluştur
create_repo=Depo Oluştur
default_branch=Varsayılan Dal
mirror_prune=Prune
mirror_prune_desc=Remove any remote-tracking references that no longer exist on the remote
mirror_prune=Buda
mirror_prune_desc=Uzakta olmayan bütün uzaktan-izleme referanslarını sil
mirror_interval=Yansı Aralığı (saat)
mirror_address=Yansı Adresi
mirror_address_desc=Lütfen gerekli kimlik bilgilerini adreste bulundurun.
mirror_last_synced=Last Synced
watchers=İzleyenler
stargazers=Yıldızlayanlar
forks=Çatallamalar
@@ -368,7 +389,8 @@ migrate_type=Göç Türü
migrate_type_helper=Bu depo bir <span class="text blue">yansı</span> olacaktır
migrate_repo=Depoyu Göç Ettir
migrate.clone_address=Klon Adresi
migrate.clone_address_desc=Bu bağlantı HTTP/HTTPS/GIT veya yerel bir sunucu yolu olabilir.
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=Yerel depoları içeri aktarma izniniz yok.
migrate.invalid_local_path=Geçersiz yerel dizin! Böyle bir yol yok ya da bir dizin değil.
migrate.failed=Göç başarısız: %v
@@ -393,7 +415,7 @@ create_new_repo_command=Komut satırında yeni bir depo oluştur
push_exist_repo=Var olan bir depoyu komut satırında gönder
repo_is_empty=Bu depo boş. Lütfen daha sonra tekrar gelin!
code=Kod
files=Files
branch=Dal
tree=Ağaç
filter_branch_and_tag=Dal veya biçim imini filtrele
@@ -409,6 +431,47 @@ file_raw=Ham
file_history=Geçmiş
file_view_raw=Ham Görünüm
file_permalink=Kalıcı Bağlantı
file_too_large=Bu dosya sergilenmek için çok büyük
video_not_supported_in_browser=Your browser doesn't support HTML5 video tag.
editor.new_file=New file
editor.upload_file=Upload file
editor.edit_file=Dosya düzenle
editor.preview_changes=Preview Changes
editor.cannot_edit_non_text_files=Metin dışı dosyalar düzenlenemez
editor.edit_this_file=Edit this file
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
editor.fork_before_edit=You must fork this repository before editing the file
editor.delete_this_file=Delete this file
editor.must_have_write_access=You must have write access to make or propose changes to this file
editor.file_delete_success=File '%s' has been deleted successfully!
editor.name_your_file=Name your file...
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
editor.or=or
editor.cancel_lower=iptal
editor.commit_changes=Commit Changes
editor.add_tmpl=Add '%s/<filename>'
editor.add=Add '%s'
editor.update=Update '%s'
editor.delete=Delete '%s'
editor.commit_message_desc=Add an optional extended description...
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
editor.new_branch_name_desc=New branch name...
editor.cancel=İptal
editor.filename_cannot_be_empty=Filename cannot be empty.
editor.branch_already_exists=Branch '%s' already exists in this repository.
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
editor.file_is_a_symlink=The file '%s' is a symlink that cannot be modified from the web editor.
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
editor.file_already_exists=A file with name '%s' already exists in this repository.
editor.no_changes_to_show=There are no changes to show.
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
editor.add_subdir=Add subdirectory...
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
editor.upload_files_to_dir=Upload files to '%s'
commits.commits=İşlemeler
commits.search=İşleme Arama
@@ -435,6 +498,11 @@ issues.create=Sorun Oluştur
issues.new_label=Yeni Etiket
issues.new_label_placeholder=Etiket adı...
issues.create_label=Etiket Oluştur
issues.label_templates.title=Load a predefined set of labels
issues.label_templates.info=There arent any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
issues.label_templates.helper=Select a label set
issues.label_templates.use=Use this label set
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
issues.open_tab=%d açık
issues.close_tab=%d kapanmış
issues.filter_label=Etiket
@@ -462,7 +530,8 @@ issues.next=Sonraki
issues.open_title=ık
issues.closed_title=Kapalı
issues.num_comments=%d yorum
issues.commented_at=`<a id="%[1]s" href="#%[1]s">%[2]s</a> yorum yaptı`
issues.commented_at=`<a href="#%s">%s</a> olarak yorumlandı`
issues.delete_comment_confirm=Bu yorumu silmek istediğinizden emin misiniz?
issues.no_content=Henüz bir içerik yok.
issues.close_issue=Kapat
issues.close_comment_issue=Yorum yap ve kapat
@@ -475,8 +544,7 @@ issues.commit_ref_at=`<a id="%[1]s" href="#%[1]s">%[2]s</a> işlemesinde bu soru
issues.poster=Poster
issues.collaborator=Katkıcı
issues.owner=Sahibi
issues.sign_up_for_free=Ücretsiz Kaydolun
issues.sign_in_require_desc=bu konuşmaya katılmak için. Zaten bir hesabınız var mı? <a href="%s">Yorum yapmak için giriş yapın</a>
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
issues.edit=Düzenle
issues.cancel=İptal
issues.save=Kaydet
@@ -491,6 +559,8 @@ issues.label_deletion=Etiket Silme
issues.label_deletion_desc=Bu etiketi silerseniz, bu etikete iliştirilmiş sorunlardaki tüm bilgiler de silinecektir. Devam etmek istiyor musunuz?
issues.label_deletion_success=Etiket başarıyla silindi!
issues.num_participants=%d Katılımcı
issues.attachment.open_tab=`Click to see "%s" in a new tab`
issues.attachment.download=`Click to download "%s"`
pulls.new=Yeni Değişiklik İsteği
pulls.compare_changes=Değişiklikleri Karşılaştır
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=Çakışmalardan dolayı bu değişiklik isteği ot
pulls.cannot_auto_merge_helper=Çakışmaları çözmek için lütfen elle birleştirin.
pulls.merge_pull_request=Değişiklik İsteğini Birleştir
pulls.open_unmerged_pull_exists=`Yeniden açma işlemini gerçekleştiremezsiniz. Çünkü zaten aynı depodan, aynı birleştirme bilgisiyle açık olan bir değişiklik isteği var (#%d) ve birleştirme bekliyor.`
pulls.delete_branch=Delete Branch
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence.
milestones.new=Yeni Kilometre Taşı
milestones.open_tab=%d Açık
@@ -563,27 +635,34 @@ wiki.last_updated=Son güncelleme %s
settings=Ayarlar
settings.options=Tercihler
settings.collaboration=İş birliği
settings.collaboration.admin=Admin
settings.collaboration.write=Write
settings.collaboration.read=Read
settings.collaboration.undefined=Undefined
settings.collaboration.admin=Yönetici
settings.collaboration.write=Yaz
settings.collaboration.read=Oku
settings.collaboration.undefined=Belirsiz
settings.hooks=Web İstekleri
settings.githooks=Git İstekleri
settings.basic_settings=Temel Ayarlar
settings.mirror_settings=Mirror Settings
settings.sync_mirror=Sync Now
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
settings.site=Resmi Web Sitesi
settings.update_settings=Ayarları Güncelle
settings.change_reponame_prompt=Bu değişiklik, bağlantıların depoyla olan ilişkisini etkileyecektir.
settings.advanced_settings=Gelişmiş Ayarlar
settings.wiki_desc=İnsanların belge yazması için Wiki'yi etkinleştir
settings.wiki_desc=Viki sıstemini etkinleştir
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=Harici Wiki kullan
settings.external_wiki_url=Harici Wiki bağlantısı
settings.external_wiki_url_desc=Ziyaretçiler, sekmeye tıkladıklarında bağlantıya yönlendirilecektir.
settings.issues_desc=Hazır gelen hafif sorun takipçisini etkinleştir
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=Harici sorun takipçisi kullan
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Harici Sorun Takipçisi Bağlantı Formatı
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style=Harici Hata İzleyicisi Adlandırma Stili:
settings.tracker_issue_style.numeric=Sayısal
settings.tracker_issue_style.alphanumeric=Alfanumerik
settings.tracker_url_format_desc=Kullanıcı adı, depo ismi ve hata indeksi için <code>{kullanıcı} {depo} {indeks}</code> tutucusunu kullanabilirsiniz.
settings.pulls_desc=Herkese açık katkıları kabul etmek için değişiklik isteklerini etkinleştirin
settings.danger_zone=Tehlike Alanı
@@ -606,7 +685,7 @@ settings.delete=Bu Depoyu Sil
settings.delete_desc=Bir depoyu bir kez sildiğiniz taktirde geri getiremezsiniz. Lütfen emin olun.
settings.delete_notices_1=- Bu işlem geri <strong>ALINAMAZ</strong>.
settings.delete_notices_2=- Bu işlem, bu depodaki her şeyi (Git verisini, sorunları, yorumları ve katkıcı erişimlerini) kalıcı olarak silecektir.
settings.delete_notices_fork_1=- All forks will become independent after deletion.
settings.delete_notices_fork_1=Silme işleminden sonra bütün çatallar bağımsız hale gelir.
settings.deletion_success=Depo başarıyla silindi!
settings.update_settings_success=Depo seçenekleri başarıyla güncellendi.
settings.transfer_owner=Yeni Sahip
@@ -653,6 +732,8 @@ settings.event_send_everything=<strong>Her şeye</strong> ihtiyacım var.
settings.event_choose=Neye ihtiyacım olduğunu seçtir.
settings.event_create=Oluştur
settings.event_create_desc=Dal veya biçim imi oluşturuldu
settings.event_pull_request=Pull Request
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
settings.event_push=Push
settings.event_push_desc=Bir depoya git push
settings.active=Aktif
@@ -690,8 +771,8 @@ diff.show_unified_view=Birleşik Görünüm
diff.stats_desc=<strong> %d değiştirilmiş dosya</strong> ile <strong>%d ekleme</strong> ve <strong>%d silme</strong>
diff.bin=BIN
diff.view_file=Dosyayı Görüntüle
diff.file_supressed=File diff supressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
diff.file_suppressed=Dosya farkı çok büyük olduğundan ihmal edildi
diff.too_many_files=Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor
release.releases=Sürümler
release.new_release=Yeni Sürüm
@@ -722,6 +803,7 @@ release.deletion=Sürüm Silme
release.deletion_desc=Bu sürümü silerseniz buna uyan tüm Git biçim imleri de silinecektir. Devam etmek istiyor musunuz?
release.deletion_success=Sürüm başarıyla silindi!
release.tag_name_already_exist=Bu biçim imi adıyla başka bir sürüm zaten var.
release.tag_name_invalid=Etiket adı geçerli değil.
release.downloads=İndirmeler
[org]
@@ -889,6 +971,7 @@ users.edit_account=Hesabı Düzenle
users.max_repo_creation=Maksimum Depo Oluşturma Limiti
users.max_repo_creation_desc=(Genel varsayılan limiti kullanmak için -1 yazın)
users.is_activated=Bu hesap aktivleştirildi
users.prohibit_login=Bu hesap oturum açmaya engellenmiş
users.is_admin=Bu hesap, yönetici izinlerine sahiptir
users.allow_git_hook=Bu hesap, Git istekleri oluşturmak için gereken yetkilere sahip
users.allow_import_local=Bu hesap, yerel depoları içeri aktarmak için gereken yetkilere sahip
@@ -919,7 +1002,7 @@ auths.enabled=Aktifleştirilmiş
auths.updated=Güncellendi
auths.auth_type=Yetki Türü
auths.auth_name=Yetki İsmi
auths.security_protocol=Security Protocol
auths.security_protocol=Güvenlik Protokolü
auths.domain=Alan Adı
auths.host=Sunucu
auths.port=Port
@@ -957,6 +1040,7 @@ auths.delete_auth_title=Yetkilendirme Silme
auths.delete_auth_desc=Bu yetkilendirme silinecek. Devam etmek istiyor musunuz?
auths.still_in_used=Bu yetkilendirme hala bazı kullanıcılar tarafından kullanılıyor. Lütfen öncelikle bunları silin ya da başka oturum açma türlerine çevirin.
auths.deletion_success=Yetkilendirme başarıyla silindi!
auths.login_source_exist=Login source '%s' already exists.
config.server_config=Sunucu Yapılandırması
config.app_name=Uygulama Adı
@@ -967,6 +1051,7 @@ config.offline_mode=Çevrim Dışı Modu
config.disable_router_log=Yönlendirici Log'larını Devre Dışı Bırak
config.run_user=Çalıştırma Kullanıcısı
config.run_mode=Çalıştırma Modu
config.git_version=Git Version
config.repo_root_path=Depo Kök Yolu
config.static_file_root_path=Sabit Dosya Kök Yolu
config.log_file_root_path=Log Dosyası Kök Yolu
@@ -994,6 +1079,7 @@ config.db_ssl_mode=SSL Biçimi
config.db_ssl_mode_helper=(sadece "postgres" için)
config.db_path=Yol
config.db_path_helper=("sqlite3" ve "tidb" için)
config.service_config=Servis Yapılandırması
config.register_email_confirm=E-posta Onayı Gerekli
config.disable_register=Kaydolma Hizmet Dışı
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=Minimum Anahtar Uzunluğu Kontrolünü Devre Dış
config.enable_captcha=Captcha'yı Aktifleştir
config.active_code_lives=Kod Yaşamlarını Aktifleştir
config.reset_password_code_lives=Kod Yaşamları Parolasını Yenile
config.webhook_config=Web İstekleri Yapılandırması
config.queue_length=Kuyruk Uzunluğu
config.deliver_timeout=Dağıtım Zaman Aşımı
config.skip_tls_verify=TLS Doğrulamasını Atla
config.mailer_config=Mailer Yapılandırması
config.mailer_enabled=Aktif
config.mailer_disable_helo=HELO'yu Devre Dışı Bırak
@@ -1017,12 +1105,15 @@ config.mailer_user=Kullanıcı
config.send_test_mail=Test E-Postası Gönder
config.test_mail_failed='%s' adresine test e-postası gönderimi başarısız: %v
config.test_mail_sent='%s' adresine test e-postası gönderildi.
config.oauth_config=OAuth Yapılandırması
config.oauth_enabled=Aktif
config.cache_config=Önbellek Yapılandırması
config.cache_adapter=Önbellek Uyarlayıcısı
config.cache_interval=Önbellek Aralığı
config.cache_conn=Önbellek Bağlantısı
config.session_config=Oturum Yapılandırması
config.session_provider=Oturum Sağlayıcı
config.provider_config=Sağlayıcı Yapılandırması
@@ -1032,9 +1123,24 @@ config.gc_interval_time=GC Aralık Zamanı
config.session_life_time=Oturum Yaşam Zamanı
config.https_only=Yalnız HTTPS
config.cookie_life_time=Çerez Yaşam Zamanı
config.picture_config=Resim Yapılandırması
config.picture_service=Resim Servisi
config.disable_gravatar=Gravatar Hizmet Dışı
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=Log Yapılandırması
config.log_mode=Log Modu

View File

@@ -96,6 +96,8 @@ offline_mode=启用离线模式
offline_mode_popup=在部署模式下也禁用从 CDN 获取文件,所以的资源都将从本地服务器获取。
disable_gravatar=禁用 Gravatar 服务
disable_gravatar_popup=禁用 Gravatar 和自定义源,仅使用由用户上传的或默认的头像。
federated_avatar_lookup=启用 Federated Avatars 查找
federated_avatar_lookup_popup=启用 Federated Avatars 查找以使用开源的 Libravatar 服务。
disable_registration=禁止用户自主注册
disable_registration_popup=禁止用户自行注册功能,只有管理员可以添加帐号。
enable_captcha=启用验证码服务
@@ -114,6 +116,7 @@ sqlite3_not_available=您所使用的发行版不支持 SQLite3请从 %s 下
invalid_db_setting=数据库设置不正确:%v
invalid_repo_path=仓库根目录设置不正确:%v
run_user_not_match=运行系统用户非当前用户:%s -> %s
invalid_smtp_from=SMTP From 字段不合法:%v
save_config_failed=应用配置保存失败:%v
invalid_admin_setting=管理员帐户设置不正确:%v
install_success=您好!我们很高兴您选择使用 Gogs祝您使用愉快代码从此无 BUG
@@ -124,6 +127,7 @@ uname_holder=用户名或邮箱
password_holder=密码
switch_dashboard_context=切换控制面板用户
my_repos=我的仓库
show_more_repos=显示更多仓库...
collaborative_repos=参与协作的仓库
my_orgs=我的组织
my_mirrors=我的镜像
@@ -134,6 +138,7 @@ issues.in_your_repos=属于该用户仓库的
[explore]
repos=仓库
users=用户
organizations=组织
search=搜索
[auth]
@@ -148,10 +153,11 @@ forget_password=忘记密码?
sign_up_now=还没帐户?马上注册。
confirmation_mail_sent_prompt=一封新的确认邮件已经被发送至 <b>%s</b>,请检查您的收件箱并在 %d 小时内完成确认注册操作。
active_your_account=激活您的帐户
prohibit_login=禁止登录
prohibit_login_desc=您的帐户被禁止登录,请联系网站管理员。
resent_limit_prompt=对不起,您请求发送激活邮件过于频繁,请等待 3 分钟后再试!
has_unconfirmed_mail=%s 您好,系统检测到您有一封发送至 <b>%s</b> 但未被确认的邮件。如果您未收到激活邮件,或需要重新发送,请单击下方的按钮。
resend_mail=单击此处重新发送确认邮件
email_not_associate=您输入的邮箱地址未被关联到任何帐号!
send_reset_mail=单击此处(重新)发送您的密码重置邮件
reset_password=重置密码
invalid_code=对不起,您的确认代码已过期或已失效。
@@ -184,6 +190,13 @@ TeamName=团队名称
AuthName=认证名称
AdminEmail=管理员邮箱
NewBranchName=新的分支名称
CommitSummary=提交小结
CommitMessage=提交消息
CommitChoice=提交选择
TreeName=文件路径
Content=内容
require_error=不能为空。
alpha_dash_error=必须为英文字母、阿拉伯数字或横线(-_
alpha_dash_dot_error=必须为英文字母、阿拉伯数字、横线(-_或点。
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=用户名不允许 '%s' 的格式。
[settings]
profile=个人信息
password=修改密码
avatar=头像设置
ssh_keys=管理 SSH 密钥
social=社交帐号绑定
applications=管理授权应用
@@ -256,6 +270,8 @@ change_username_prompt=该操作将会影响到所有与您帐户有关的链接
continue=继续操作
cancel=取消操作
lookup_avatar_by_mail=通过邮箱地址获取头像
federated_avatar_lookup=Federated Avatar 查找
enable_custom_avatar=启动自定义头像
choose_new_avatar=选择新的头像
update_avatar=更新头像设置
@@ -322,6 +338,10 @@ access_token_deletion=删除个人操作令牌操作
access_token_deletion_desc=删除该个人操作令牌将删除所有相关的应用程序的访问权限。是否继续?
delete_token_success=个人操作令牌删除成功!请更新与该令牌有关的所有应用。
orgs.none=您现在还不是任何组织的成员。
orgs.leave_title=离开组织
orgs.leave_desc=离开组织后,组织相关的所有仓库和团队权限将被收回。是否继续?
delete_account=删除当前帐户
delete_prompt=删除操作会永久清除您的帐户信息,并且 <strong>不可恢复</strong>
confirm_delete_account=确认删除帐户
@@ -342,7 +362,7 @@ fork_from=派生自
fork_visiblity_helper=派生仓库无法修改可见性
repo_desc=仓库描述
repo_lang=仓库语言
repo_lang_helper=选择 .gitignore 文件
repo_gitignore_helper=选择 .gitignore 模板
license=授权许可
license_helper=请选择授权许可文件
readme=自述文档
@@ -355,6 +375,7 @@ mirror_prune_desc=当远程追踪的引用被删除时本地也同步删除
mirror_interval=镜像同步周期(小时)
mirror_address=镜像地址
mirror_address_desc=请在镜像地址中写入必要的用户凭据信息。
mirror_last_synced=上次同步时间:
watchers=关注者
stargazers=称赞者
forks=派生仓库
@@ -368,7 +389,8 @@ migrate_type=迁移类型
migrate_type_helper=该仓库将是一个 <span class="text blue">镜像</span>
migrate_repo=迁移仓库
migrate.clone_address=克隆地址
migrate.clone_address_desc=该地址可以是 HTTP/HTTPS/GIT URL 或本地服务器路径
migrate.clone_address_desc=该地址可以是 HTTP/HTTPS/GIT 类型的 URL
migrate.clone_address_desc_import_local=您被允许使用服务器本地路径作为仓库的远程地址进行迁移。
migrate.permission_denied=您没有获得导入本地仓库的权限。
migrate.invalid_local_path=无效的本地路径,不存在或不是一个目录!
migrate.failed=迁移失败:%v
@@ -393,7 +415,7 @@ create_new_repo_command=从命令行创建一个新的仓库
push_exist_repo=从命令行推送已经创建的仓库
repo_is_empty=该仓库不包含任何内容,请稍后再进行访问!
code=代码
files=文件
branch=分支
tree=目录树
filter_branch_and_tag=过滤分支或标签
@@ -409,6 +431,47 @@ file_raw=原始文件
file_history=文件历史
file_view_raw=查看原始文件
file_permalink=永久链接
file_too_large=文件过大导致无法显示
video_not_supported_in_browser=您的浏览器不支持使用 HTML5 播放视频。
editor.new_file=新的文件
editor.upload_file=上传文件
editor.edit_file=编辑文件
editor.preview_changes=预览变更
editor.cannot_edit_non_text_files=无法编辑非文本文件
editor.edit_this_file=编辑此文件
editor.must_be_on_a_branch=您必须在某个分支上才能对此文件进行修改操作
editor.fork_before_edit=您必须派生此仓库才能对此文件进行修改操作
editor.delete_this_file=删除此文件
editor.must_have_write_access=您必须具有可写权限才能对此文件进行修改操作
editor.file_delete_success=文件 '%s' 删除成功!
editor.name_your_file=命名文件...
editor.filename_help=输入名称后按下 / 键即可添加目录,或将光标移至输入框最左侧按下退格键移除目录。
editor.or=
editor.cancel_lower=取消
editor.commit_changes=提交变更
editor.add_tmpl=添加 '%s/<文件名>'
editor.add=添加 '%s'
editor.update=更新 '%s'
editor.delete=删除 '%s'
editor.commit_message_desc=添加一个可选的扩展描述...
editor.commit_directly_to_this_branch=直接提交至 <strong class="branch-name">%s</strong> 分支。
editor.create_new_branch=为此提交创建一个 <strong>新的分支</strong> 并发起合并请求。
editor.new_branch_name_desc=新的分支名称...
editor.cancel=取消
editor.filename_cannot_be_empty=文件名不能为空。
editor.branch_already_exists=此仓库已存在名为 '%s' 的分支。
editor.directory_is_a_file=路径 '%s' 的父路径中包含此仓库已存在的文件名。
editor.file_is_a_symlink=文件 '%s' 为一个符号链接,无法通过 Web 编辑器编辑内容。
editor.filename_is_a_directory=文件名 '%s' 是此仓库中已存在的目录名。
editor.file_editing_no_longer_exists=您编辑的文件 '%s' 已经不存在于此仓库中。
editor.file_changed_while_editing=文件内容在您进行编辑时已经发生变动。<a target="_blank" href="%s">单击此处</a> 查看变动的具体内容,或者 <strong>再次提交</strong> 覆盖已发生的变动。
editor.file_already_exists=此仓库已经存在名为 '%s' 的文件。
editor.no_changes_to_show=没有可以显示的变更。
editor.fail_to_update_file=更新/创建文件 '%s' 时发生错误:%v
editor.add_subdir=添加子目录...
editor.unable_to_upload_files=上传文件至 '%s' 时发生错误:%v
editor.upload_files_to_dir=上传文件至 '%s'
commits.commits=次代码提交
commits.search=搜索提交历史
@@ -435,6 +498,11 @@ issues.create=创建工单
issues.new_label=创建标签
issues.new_label_placeholder=标签名称...
issues.create_label=创建标签
issues.label_templates.title=加载预定义的标签模板
issues.label_templates.info=此仓库还未创建任何标签,您可以通过上方的 "创建标签" 创建一个新的标签或加载一组预定义的标签。
issues.label_templates.helper=选择标签模板
issues.label_templates.use=加载标签模板
issues.label_templates.fail_to_load_file=加载标签模板文件 '%s' 时发生错误:%v
issues.open_tab=%d 个开启中
issues.close_tab=%d 个已关闭
issues.filter_label=标签筛选
@@ -462,7 +530,8 @@ issues.next=下一页
issues.open_title=开启中
issues.closed_title=已关闭
issues.num_comments=%d 条评论
issues.commented_at=`于 <a id="%[1]s" href="#%[1]s">%[2]s</a> 评论`
issues.commented_at=`评论于 <a href="#%s">%s</a>`
issues.delete_comment_confirm=您确定要删除该条评论吗?
issues.no_content=这个人很懒,什么都没留下。
issues.close_issue=关闭
issues.close_comment_issue=评论并关闭
@@ -475,8 +544,7 @@ issues.commit_ref_at=`在代码提交 <a id="%[1]s" href="#%[1]s">%[2]s</a> 中
issues.poster=发布者
issues.collaborator=协作者
issues.owner=所有者
issues.sign_up_for_free=免费注册
issues.sign_in_require_desc=并加入到对话中来。如果您已经注册,可以直接 <a href="%s">登录并评论</a>
issues.sign_in_require_desc=<a href="%s">登陆</a> 并参与到对话中。
issues.edit=编辑
issues.cancel=取消
issues.save=保存
@@ -491,6 +559,8 @@ issues.label_deletion=删除标签操作
issues.label_deletion_desc=删除该标签将会移除所有工单中相关的信息。是否继续?
issues.label_deletion_success=标签删除成功!
issues.num_participants=%d 名参与者
issues.attachment.open_tab=`在新的标签页中查看 '%s'`
issues.attachment.download=`点击下载 '%s'`
pulls.new=创建合并请求
pulls.compare_changes=对比文件变化
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=该合并请求存在冲突,无法进行自动合
pulls.cannot_auto_merge_helper=请手动拉取代码变更以解决冲突。
pulls.merge_pull_request=合并请求
pulls.open_unmerged_pull_exists=`由于已经存在来自相同仓库和合并信息的未合并请求(#%d您无法执行重新开启操作。`
pulls.delete_branch=删除分支
pulls.delete_branch_has_new_commits=该分支在完成合并后又推送了新的提交,无法进行删除操作。
milestones.new=新的里程碑
milestones.open_tab=%d 开启中
@@ -570,20 +642,27 @@ settings.collaboration.undefined=未定义
settings.hooks=管理 Web 钩子
settings.githooks=管理 Git 钩子
settings.basic_settings=基本设置
settings.mirror_settings=镜像设置
settings.sync_mirror=立即同步
settings.mirror_sync_in_progress=镜像同步请求已经生效,请稍后刷新页面。
settings.site=官方网站
settings.update_settings=更新仓库设置
settings.change_reponame_prompt=该操作将会影响到所有与该仓库有关的链接
settings.advanced_settings=高级设置
settings.wiki_desc=启用 Wiki 以允许用户协作文档
settings.wiki_desc=启用 Wiki 系统
settings.use_internal_wiki=使用内置 Wiki 系统
settings.use_external_wiki=使用外部 Wiki
settings.external_wiki_url=外部 Wiki 链接
settings.external_wiki_url_desc=当访问者单击分页标签时,将会被重定向到该链接。
settings.issues_desc=启用内置的轻量级工单管理系统
settings.issues_desc=启用工单管理系统
settings.use_internal_issue_tracker=使用内置的轻量级工单管理系统
settings.use_external_issue_tracker=使用外部的工单管理系统
settings.external_tracker_url=外部工单管理系统 URL
settings.external_tracker_url_desc=当访问者单击分页标签时,将会被重定向到该链接。
settings.tracker_url_format=外部工单管理系统的 URL 格式
settings.tracker_issue_style=外部工单管理系统命名风格:
settings.tracker_issue_style.numeric=纯数字 <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=字母数字结合 <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style.numeric=纯数字形式
settings.tracker_issue_style.alphanumeric=英文字母数字组合形式
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分别作为用户名、仓库名和工单索引的占位符。
settings.pulls_desc=启用合并请求以接受社区贡献
settings.danger_zone=危险操作区
@@ -653,6 +732,8 @@ settings.event_send_everything=请把 <strong>一切</strong> 都给我
settings.event_choose=我的命运自己主宰
settings.event_create=创建
settings.event_create_desc=创建分支或标签
settings.event_pull_request=合并请求
settings.event_pull_request_desc=开启、关闭、重新开启、编辑、指派、取消指派、更新标签、清除标签或同步合并请求
settings.event_push=推送
settings.event_push_desc=Git 仓库推送
settings.active=是否激活
@@ -690,7 +771,7 @@ diff.show_unified_view=合并视图
diff.stats_desc=共有 <strong> %d 个文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
diff.bin=二进制
diff.view_file=查看文件
diff.file_supressed=文件差异内容过多而无法显示
diff.file_suppressed=文件差异内容过多而无法显示
diff.too_many_files=部分文件因为文件数量过多而无法显示
release.releases=版本发布
@@ -722,6 +803,7 @@ release.deletion=删除版本发布操作
release.deletion_desc=删除该版本发布将会移除相应的 Git 标签。是否继续?
release.deletion_success=版本发布删除成功!
release.tag_name_already_exist=已经存在使用相同标签进行发布的版本。
release.tag_name_invalid=标签名称不是有效的名称。
release.downloads=下载附件
[org]
@@ -889,6 +971,7 @@ users.edit_account=编辑用户信息
users.max_repo_creation=最大允许创建仓库数量
users.max_repo_creation_desc=(设置为 -1 表示使用全局默认值)
users.is_activated=该用户已被激活
users.prohibit_login=该帐户被禁止登录
users.is_admin=该用户具有管理员权限
users.allow_git_hook=该用户具有创建 Git 钩子的权限
users.allow_import_local=该用户具有导入本地仓库的权限
@@ -957,6 +1040,7 @@ auths.delete_auth_title=删除认证操作
auths.delete_auth_desc=该认证将被删除。是否继续?
auths.still_in_used=此认证仍旧与一些用户有关联,请先删除或者将这些用户转换为其它登录类型。
auths.deletion_success=授权源删除成功!
auths.login_source_exist=登录源 '%s' 已存在。
config.server_config=服务器配置
config.app_name=应用名称
@@ -967,6 +1051,7 @@ config.offline_mode=离线模式
config.disable_router_log=关闭路由日志
config.run_user=运行用户
config.run_mode=运行模式
config.git_version=Git 版本
config.repo_root_path=仓库根目录
config.static_file_root_path=静态文件根目录
config.log_file_root_path=日志文件根目录
@@ -994,6 +1079,7 @@ config.db_ssl_mode=SSL 模式
config.db_ssl_mode_helper=(仅限 "postgres" 使用)
config.db_path=数据库路径
config.db_path_helper=(用于 "sqlite3" 和 "tidb"
config.service_config=服务配置
config.register_email_confirm=注册邮件确认
config.disable_register=关闭注册功能
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=禁用密钥最小长度检查
config.enable_captcha=启用验证码服务
config.active_code_lives=激活用户链接有效期
config.reset_password_code_lives=重置密码链接有效期
config.webhook_config=Web 钩子配置
config.queue_length=队列长度
config.deliver_timeout=推送超时
config.skip_tls_verify=忽略 TLS 验证
config.mailer_config=邮件配置
config.mailer_enabled=启用服务
config.mailer_disable_helo=禁用 HELO 操作
@@ -1017,12 +1105,15 @@ config.mailer_user=发送者帐号
config.send_test_mail=发送测试邮件
config.test_mail_failed=发送测试邮件至 '%s' 时失败:%v
config.test_mail_sent=测试邮件已经发送至 '%s'。
config.oauth_config=社交帐号配置
config.oauth_enabled=启用服务
config.cache_config=Cache 配置
config.cache_adapter=Cache 适配器
config.cache_interval=Cache 周期
config.cache_conn=Cache 连接字符串
config.session_config=Session 配置
config.session_provider=Session 提供者
config.provider_config=提供者配置
@@ -1032,9 +1123,24 @@ config.gc_interval_time=GC 周期
config.session_life_time=Session 生命周期
config.https_only=仅限 HTTPS
config.cookie_life_time=Cookie 生命周期
config.picture_config=图片配置
config.picture_service=图片服务
config.disable_gravatar=禁用 Gravatar 头像
config.enable_federated_avatar=启用 Federated Avatars
config.git_config=Git 配置
config.git_disable_diff_highlight=禁用差异对比语法高亮
config.git_max_diff_lines=差异对比显示的最大行数(单个文件)
config.git_max_diff_line_characters=差异对比显示的最大字符数(单行)
config.git_max_diff_files=差异对比显示的最大文件数
config.git_gc_args=GC 参数
config.git_migrate_timeout=迁移操作超时
config.git_mirror_timeout=镜像更新操作超时
config.git_clone_timeout=克隆操作超时
config.git_pull_timeout=拉取操作超时
config.git_gc_timeout=GC 操作超时
config.log_config=日志配置
config.log_mode=日志模式

View File

@@ -96,6 +96,8 @@ offline_mode=啓用離線模式
offline_mode_popup=在部署模式下也禁用從 CDN 獲取文件,所有的資源將從本地伺服器獲取。
disable_gravatar=禁用 Gravatar 服務
disable_gravatar_popup=禁用 Gravatar 和自定義源,僅使用由用戶上傳或默認的頭像。
federated_avatar_lookup=Enable Federated Avatars Lookup
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=禁止用戶自主註冊
disable_registration_popup=禁止用戶自主註冊功能,只有管理員可以添加帳號。
enable_captcha=啟用驗證碼服務
@@ -114,6 +116,7 @@ sqlite3_not_available=您所使用的發行版本不支持 SQLite3請從 %s
invalid_db_setting=數據庫設置不正確:%v
invalid_repo_path=倉庫根目錄設置不正確:%v
run_user_not_match=執行系統用戶非當前用戶:%s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=應用配置保存失敗:%v
invalid_admin_setting=管理員帳戶設置不正確:%v
install_success=您好!我們很高興您選擇使用 Gogs祝您使用愉快代碼從此無 BUG
@@ -124,6 +127,7 @@ uname_holder=用戶名或郵箱
password_holder=密碼
switch_dashboard_context=切換控制面版用戶
my_repos=我的倉庫
show_more_repos=Show more repositories...
collaborative_repos=參與協作的倉庫
my_orgs=我的組織
my_mirrors=我的鏡像
@@ -134,6 +138,7 @@ issues.in_your_repos=屬於該用戶倉庫的
[explore]
repos=探索倉庫
users=用戶
organizations=Organizations
search=搜索
[auth]
@@ -148,10 +153,11 @@ forget_password=忘記密碼?
sign_up_now=還沒帳戶?馬上註冊。
confirmation_mail_sent_prompt=一封新的確認郵件已經被發送至 <b>%s</b>,請檢查您的收件箱並在 %d 小時內完成確認註冊操作。
active_your_account=激活您的帳戶
prohibit_login=Login Prohibited
prohibit_login_desc=Your account is prohibited to login, please contact site admin.
resent_limit_prompt=對不起,您請求發送激活郵件過於頻繁,請等待 3 分鐘後再試!
has_unconfirmed_mail=%s 您好,您有一封發送至( <b>%s</b>) 但未被確認的郵件。如果您未收到激活郵件,或需要重新發送,請單擊下方的按鈕。
resend_mail=單擊此處重新發送確認郵件
email_not_associate=您輸入的郵箱地址未被關聯到任何帳號!
send_reset_mail=單擊此處(重新)發送您的密碼重置郵件
reset_password=重置密碼
invalid_code=對不起,您的確認代碼已過期或已失效。
@@ -184,6 +190,13 @@ TeamName=團隊名稱
AuthName=認證名稱
AdminEmail=管理員郵箱
NewBranchName=New branch name
CommitSummary=Commit summary
CommitMessage=Commit message
CommitChoice=Commit choice
TreeName=File path
Content=Content
require_error=不能為空。
alpha_dash_error=必須為英文字母、阿拉伯數字或橫線(-_
alpha_dash_dot_error=必須為英文字母、阿拉伯數字、橫線(-_或點。
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=用戶名不允許 '%s' 的格式。
[settings]
profile=個人信息
password=修改密碼
avatar=Avatar
ssh_keys=管理 SSH 密鑰
social=社交帳號綁定
applications=管理授權應用
@@ -256,6 +270,8 @@ change_username_prompt=該操作將會影響到所有與您帳戶有關的鏈接
continue=繼續操作
cancel=取消操作
lookup_avatar_by_mail=Lookup Avatar by mail
federated_avatar_lookup=Federated Avatar Lookup
enable_custom_avatar=啟動自定義頭像
choose_new_avatar=選擇新的頭像
update_avatar=更新頭像設置
@@ -322,6 +338,10 @@ access_token_deletion=刪除個人的連接token
access_token_deletion_desc=刪除此連接token將會刪除與相關應用程式的連結。您想要繼續嗎?
delete_token_success=您的連接token已成功刪除。請記得更新您的應用程式。
orgs.none=You are not a member of any organizations.
orgs.leave_title=Leave an organization
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue?
delete_account=刪除當前帳戶
delete_prompt=刪除操作會永久清除您的帳戶信息,並且 <strong>不可恢復</strong>
confirm_delete_account=確認刪除帳戶
@@ -342,7 +362,7 @@ fork_from=派生自
fork_visiblity_helper=派生倉庫無法修改可見性。
repo_desc=倉庫描述
repo_lang=倉庫語言
repo_lang_helper=請選擇 .gitignore 文件
repo_gitignore_helper=Select .gitignore templates
license=授權許可
license_helper=請選擇授權許可文件
readme=Readme
@@ -355,6 +375,7 @@ mirror_prune_desc=Remove any remote-tracking references that no longer exist on
mirror_interval=鏡像同步周期(小時)
mirror_address=鏡像地址
mirror_address_desc=請在位址中包括必要的使用者憑據。
mirror_last_synced=Last Synced
watchers=關注者
stargazers=稱讚者
forks=派生倉庫
@@ -368,7 +389,8 @@ migrate_type=遷移類型
migrate_type_helper=該倉庫將是一個 <span class="text blue">鏡像</span>
migrate_repo=遷移倉庫
migrate.clone_address=複製地址
migrate.clone_address_desc=該地址可以是 HTTP/HTTPS/GIT URL 或本地服務器路徑。
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=您並沒有導入本地倉庫的權限。
migrate.invalid_local_path=無效的本地路徑,該路徑不存在或不是一個目錄!
migrate.failed=遷移失敗:%v
@@ -393,7 +415,7 @@ create_new_repo_command=從命令行創建一個新的倉庫
push_exist_repo=從命令行推送已經創建的倉庫
repo_is_empty=這倉庫不包含任何內容,請稍後再訪問!
code=代碼
files=Files
branch=分支
tree=目錄樹
filter_branch_and_tag=過濾分支或標籤
@@ -409,6 +431,47 @@ file_raw=原始文件
file_history=文件歷史
file_view_raw=查看原始文件
file_permalink=永久連結
file_too_large=This file is too large to be shown
video_not_supported_in_browser=Your browser doesn't support HTML5 video tag.
editor.new_file=New file
editor.upload_file=Upload file
editor.edit_file=Edit file
editor.preview_changes=Preview Changes
editor.cannot_edit_non_text_files=Cannot edit non-text files
editor.edit_this_file=Edit this file
editor.must_be_on_a_branch=You must be on a branch to make or propose changes to this file
editor.fork_before_edit=You must fork this repository before editing the file
editor.delete_this_file=Delete this file
editor.must_have_write_access=You must have write access to make or propose changes to this file
editor.file_delete_success=File '%s' has been deleted successfully!
editor.name_your_file=Name your file...
editor.filename_help=To add directory, just type it and press /. To remove a directory, go to the beginning of the field and press backspace.
editor.or=or
editor.cancel_lower=cancel
editor.commit_changes=Commit Changes
editor.add_tmpl=Add '%s/<filename>'
editor.add=Add '%s'
editor.update=Update '%s'
editor.delete=Delete '%s'
editor.commit_message_desc=Add an optional extended description...
editor.commit_directly_to_this_branch=Commit directly to the <strong class="branch-name">%s</strong> branch.
editor.create_new_branch=Create a <strong>new branch</strong> for this commit and start a pull request.
editor.new_branch_name_desc=New branch name...
editor.cancel=Cancel
editor.filename_cannot_be_empty=Filename cannot be empty.
editor.branch_already_exists=Branch '%s' already exists in this repository.
editor.directory_is_a_file=Entry '%s' in the parent path is a file not a directory in this repository.
editor.file_is_a_symlink=The file '%s' is a symlink that cannot be modified from the web editor.
editor.filename_is_a_directory=The filename '%s' is an existing directory in this repository.
editor.file_editing_no_longer_exists=The file '%s' you are editing no longer exists in the repository.
editor.file_changed_while_editing=File content has been changed since you started editing. <a target="_blank" href="%s">Click here</a> to see what have been changed or <strong>press commit again</strong> to overwrite those changes.
editor.file_already_exists=A file with name '%s' already exists in this repository.
editor.no_changes_to_show=There are no changes to show.
editor.fail_to_update_file=Failed to update/create file '%s' with error: %v
editor.add_subdir=Add subdirectory...
editor.unable_to_upload_files=Failed to upload files to '%s' with error: %v
editor.upload_files_to_dir=Upload files to '%s'
commits.commits=次代碼提交
commits.search=搜索提交歷史
@@ -435,6 +498,11 @@ issues.create=創建問題
issues.new_label=創建標籤
issues.new_label_placeholder=標籤名稱...
issues.create_label=創建標籤
issues.label_templates.title=Load a predefined set of labels
issues.label_templates.info=There arent any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
issues.label_templates.helper=Select a label set
issues.label_templates.use=Use this label set
issues.label_templates.fail_to_load_file=Failed to load label template file '%s': %v
issues.open_tab=%d 個開啓中
issues.close_tab=%d 個已關閉
issues.filter_label=標籤篩選
@@ -462,7 +530,8 @@ issues.next=下一頁
issues.open_title=開啟中
issues.closed_title=已關閉
issues.num_comments=%d 條評論
issues.commented_at=`於 <a id="%[1]s" href="#%[1]s">%[2]s</a> 評論`
issues.commented_at=`commented <a href="#%s">%s</a>`
issues.delete_comment_confirm=Are you sure you want to delete this comment?
issues.no_content=尚未有任何內容
issues.close_issue=關閉
issues.close_comment_issue=關閉及評論
@@ -475,8 +544,7 @@ issues.commit_ref_at=`在代碼提交 <a id="%[1]s" href="#%[1]s">%[2]s</a> 中
issues.poster=發佈者
issues.collaborator=協同者
issues.owner=所有者
issues.sign_up_for_free=免費註冊
issues.sign_in_require_desc=及加入到對話當中。如果您已經註冊,可以直接 <a href="%s">登錄及評論</a>
issues.sign_in_require_desc=<a href="%s">Sign in</a> to join this conversation.
issues.edit=編輯
issues.cancel=取消
issues.save=保存
@@ -491,6 +559,8 @@ issues.label_deletion=刪除標籤
issues.label_deletion_desc=刪除該標籤將會移除所有問題中相關的訊息。是否繼續?
issues.label_deletion_success=標籤刪除成功!
issues.num_participants=%d 參與者
issues.attachment.open_tab=`Click to see "%s" in a new tab`
issues.attachment.download=`Click to download "%s"`
pulls.new=創建合併請求
pulls.compare_changes=對比文件變化
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=由於存在衝突,不能自動合併這推送請
pulls.cannot_auto_merge_helper=請手動合併來解決衝突。
pulls.merge_pull_request=合併請求
pulls.open_unmerged_pull_exists=`由於已經存在來自相同倉庫和合併信息的未合併請求(#%d您無法執行重新開啟操作。`
pulls.delete_branch=Delete Branch
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence.
milestones.new=新的里程碑
milestones.open_tab=%d 開啟中
@@ -570,20 +642,27 @@ settings.collaboration.undefined=Undefined
settings.hooks=管理 Web 鉤子
settings.githooks=管理 Git 鉤子
settings.basic_settings=基本設置
settings.mirror_settings=Mirror Settings
settings.sync_mirror=Sync Now
settings.mirror_sync_in_progress=Mirror syncing is in progress, please refresh page in about a minute.
settings.site=官方網站
settings.update_settings=更新倉庫設置
settings.change_reponame_prompt=該操作將會影響到所有與該倉庫有關的鏈接
settings.advanced_settings=高級設置
settings.wiki_desc=啟用 Wiki 以允許用戶協作文檔
settings.wiki_desc=Enable wiki system
settings.use_internal_wiki=Use builtin wiki
settings.use_external_wiki=使用外部 wiki
settings.external_wiki_url=外部 Wiki 連結
settings.external_wiki_url_desc=當分頁上按一下,訪客將會重新導到 URL。
settings.issues_desc=啟用內置的輕量級問題管理系統
settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=使用外部的問題管理系統
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=外部問題管理系統的 URL 格式
settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=Alphanumeric <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style.numeric=Numeric
settings.tracker_issue_style.alphanumeric=Alphanumeric
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分別作為用戶名、倉庫名和問題索引的占位符。
settings.pulls_desc=啟用合併請求以接受社區貢獻
settings.danger_zone=危險操作區
@@ -653,6 +732,8 @@ settings.event_send_everything=推送 <strong>所有</strong> 事件
settings.event_choose=讓我選擇我的需要
settings.event_create=創建
settings.event_create_desc=創建分支或標籤
settings.event_pull_request=Pull Request
settings.event_pull_request_desc=Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
settings.event_push=推送
settings.event_push_desc=Git 倉庫推送
settings.active=是否激活
@@ -690,7 +771,7 @@ diff.show_unified_view=統一視圖
diff.stats_desc=共有 <strong> %d 個文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
diff.bin=二進制
diff.view_file=查看文件
diff.file_supressed=File diff supressed because it is too large
diff.file_suppressed=File diff suppressed because it is too large
diff.too_many_files=Some files were not shown because too many files changed in this diff
release.releases=版本發佈
@@ -722,6 +803,7 @@ release.deletion=刪除版本發布操作
release.deletion_desc=刪除該版本發布將會移除相應的 Git 標籤。是否繼續?
release.deletion_success=版本發布刪除成功!
release.tag_name_already_exist=已經存在使用相同標籤的發佈版本。
release.tag_name_invalid=Tag name is not valid.
release.downloads=下載附件
[org]
@@ -889,6 +971,7 @@ users.edit_account=編輯用戶信息
users.max_repo_creation=最大儲存庫新增限制
users.max_repo_creation_desc=(設定 -1 使用全域預設限制)
users.is_activated=該用戶已被激活
users.prohibit_login=This account is prohibited to login
users.is_admin=該用戶具有管理員權限
users.allow_git_hook=該帳戶具有創建 Git 鉤子的權限
users.allow_import_local=該用戶具有導入本地倉庫的權限
@@ -957,6 +1040,7 @@ auths.delete_auth_title=刪除認證操作
auths.delete_auth_desc=該認證將被刪除。是否繼續?
auths.still_in_used=This authentication is still used by some users, please delete or convert these users to another login type first.
auths.deletion_success=認證源刪除成功!
auths.login_source_exist=Login source '%s' already exists.
config.server_config=服務器配置
config.app_name=應用名稱
@@ -967,6 +1051,7 @@ config.offline_mode=離線模式
config.disable_router_log=關閉路由日志
config.run_user=執行用戶
config.run_mode=執行模式
config.git_version=Git Version
config.repo_root_path=倉庫根目錄
config.static_file_root_path=靜態文件根目錄
config.log_file_root_path=日志文件根目錄
@@ -994,6 +1079,7 @@ config.db_ssl_mode=SSL 模式
config.db_ssl_mode_helper=(僅限 "postgres" 使用)
config.db_path=數據庫路徑
config.db_path_helper=(用於 "sqlite3" 和 "tidb"
config.service_config=服務配置
config.register_email_confirm=註冊電子郵件確認
config.disable_register=關閉註冊功能
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=禁用密鑰最小長度檢查
config.enable_captcha=啟用驗證碼服務
config.active_code_lives=激活用戶連結有效期
config.reset_password_code_lives=重置密碼連結有效期
config.webhook_config=Web 鉤子配置
config.queue_length=隊列長度
config.deliver_timeout=推送超時
config.skip_tls_verify=忽略 TLS 驗證
config.mailer_config=郵件配置
config.mailer_enabled=啟用服務
config.mailer_disable_helo=禁用 HELO 操作
@@ -1017,12 +1105,15 @@ config.mailer_user=發送者帳號
config.send_test_mail=發送測試郵件
config.test_mail_failed=無法向 '%s' 發送測試郵件: %v
config.test_mail_sent=測試電子郵件已發送到 '%s'。
config.oauth_config=社交帳號配置
config.oauth_enabled=啟用服務
config.cache_config=Cache 配置
config.cache_adapter=Cache 適配器
config.cache_interval=Cache 周期
config.cache_conn=Cache 連接字符串
config.session_config=Session 配置
config.session_provider=Session 提供者
config.provider_config=提供者配置
@@ -1032,9 +1123,24 @@ config.gc_interval_time=垃圾收集周期
config.session_life_time=Session 生命周期
config.https_only=僅限 HTTPS
config.cookie_life_time=Cookie 生命周期
config.picture_config=圖片配置
config.picture_service=圖片服務
config.disable_gravatar=禁用 Gravatar 頭像
config.enable_federated_avatar=Enable Federated Avatars
config.git_config=Git Configuration
config.git_disable_diff_highlight=Disable Diff Syntax Highlight
config.git_max_diff_lines=Max Diff Lines (for a single file)
config.git_max_diff_line_characters=Max Diff Characters (for a single line)
config.git_max_diff_files=Max Diff Files (to be shown)
config.git_gc_args=GC Arguments
config.git_migrate_timeout=Migration Timeout
config.git_mirror_timeout=Mirror Update Timeout
config.git_clone_timeout=Clone Operation Timeout
config.git_pull_timeout=Pull Operation Timeout
config.git_gc_timeout=GC Operation Timeout
config.log_config=日誌配置
config.log_mode=日誌模式

View File

@@ -96,6 +96,8 @@ offline_mode=啓用離線模式
offline_mode_popup=在部署模式下也禁用從 CDN 獲取文件,所有的資源將從本地伺服器獲取。
disable_gravatar=禁用 Gravatar 服務
disable_gravatar_popup=禁用 Gravatar 和自定義源,僅使用由用戶上傳或默認的頭像。
federated_avatar_lookup=開啟聯合頭像查詢
federated_avatar_lookup_popup=開啟聯合頭像查詢並使用基於開放源碼的 libravatar 服務
disable_registration=禁止用戶自主註冊
disable_registration_popup=禁止用戶自主註冊功能,只有管理員可以添加帳號。
enable_captcha=啟用驗證碼服務
@@ -114,6 +116,7 @@ sqlite3_not_available=您所使用的發行版本不支持 SQLite3請從 %s
invalid_db_setting=數據庫設置不正確:%v
invalid_repo_path=倉庫根目錄設置不正確:%v
run_user_not_match=執行系統用戶非當前用戶:%s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=應用配置保存失敗:%v
invalid_admin_setting=管理員帳戶設置不正確:%v
install_success=您好!我們很高興您選擇使用 Gogs祝您使用愉快代碼從此無 BUG
@@ -124,6 +127,7 @@ uname_holder=用戶名或郵箱
password_holder=密碼
switch_dashboard_context=切換控制面版用戶
my_repos=我的倉庫
show_more_repos=顯示更多倉庫...
collaborative_repos=參與協作的倉庫
my_orgs=我的組織
my_mirrors=我的鏡像
@@ -134,6 +138,7 @@ issues.in_your_repos=屬於該用戶倉庫的
[explore]
repos=探索倉庫
users=用戶
organizations=組織
search=搜索
[auth]
@@ -148,10 +153,11 @@ forget_password=忘記密碼?
sign_up_now=還沒帳戶?馬上註冊。
confirmation_mail_sent_prompt=一封新的確認郵件已經被發送至 <b>%s</b>,請檢查您的收件箱並在 %d 小時內完成確認註冊操作。
active_your_account=激活您的帳戶
prohibit_login=禁止登錄
prohibit_login_desc=您的帳戶被停用,請聯繫網站管理員。
resent_limit_prompt=對不起,您請求發送激活郵件過於頻繁,請等待 3 分鐘後再試!
has_unconfirmed_mail=%s 您好,您有一封發送至( <b>%s</b>) 但未被確認的郵件。如果您未收到激活郵件,或需要重新發送,請單擊下方的按鈕。
resend_mail=單擊此處重新發送確認郵件
email_not_associate=您輸入的郵箱地址未被關聯到任何帳號!
send_reset_mail=單擊此處(重新)發送您的密碼重置郵件
reset_password=重置密碼
invalid_code=對不起,您的確認代碼已過期或已失效。
@@ -184,6 +190,13 @@ TeamName=團隊名稱
AuthName=認證名稱
AdminEmail=管理員郵箱
NewBranchName=新的分支名稱
CommitSummary=提交摘要
CommitMessage=提交訊息
CommitChoice=提交選擇
TreeName=檔案路徑
Content=內容
require_error=不能為空。
alpha_dash_error=必須為英文字母、阿拉伯數字或橫線(-_
alpha_dash_dot_error=必須為英文字母、阿拉伯數字、橫線(-_或點。
@@ -236,6 +249,7 @@ form.name_pattern_not_allowed=用戶名不允許 '%s' 的格式。
[settings]
profile=個人信息
password=修改密碼
avatar=頭像
ssh_keys=管理 SSH 密鑰
social=社交帳號綁定
applications=管理授權應用
@@ -256,6 +270,8 @@ change_username_prompt=該操作將會影響到所有與您帳戶有關的鏈接
continue=繼續操作
cancel=取消操作
lookup_avatar_by_mail=通過信箱查找頭像
federated_avatar_lookup=Federated Avatar 查詢
enable_custom_avatar=啟動自定義頭像
choose_new_avatar=選擇新的頭像
update_avatar=更新頭像設置
@@ -322,6 +338,10 @@ access_token_deletion=刪除個人的連接token
access_token_deletion_desc=刪除此連接token將會刪除與相關應用程式的連結。您想要繼續嗎?
delete_token_success=您的連接token已成功刪除。請記得更新您的應用程式。
orgs.none=您現在還不是任何組織的成員。
orgs.leave_title=離開組織
orgs.leave_desc=離開組織後,所有與組織相關的倉庫和團隊權限將被取消。是否繼續?
delete_account=刪除當前帳戶
delete_prompt=刪除操作會永久清除您的帳戶信息,並且 <strong>不可恢復</strong>
confirm_delete_account=確認刪除帳戶
@@ -342,7 +362,7 @@ fork_from=派生自
fork_visiblity_helper=派生倉庫無法修改可見性。
repo_desc=倉庫描述
repo_lang=倉庫語言
repo_lang_helper=選擇 .gitignore 文件
repo_gitignore_helper=選擇 .gitignore 主題
license=授權許可
license_helper=請選擇授權許可文件
readme=Readme
@@ -355,6 +375,7 @@ mirror_prune_desc=當遠程追蹤的引用被刪除時本地也會同步刪除
mirror_interval=鏡像同步周期(小時)
mirror_address=鏡像地址
mirror_address_desc=請在位址中包括必要的使用者憑據。
mirror_last_synced=上次同步
watchers=關注者
stargazers=稱讚者
forks=派生倉庫
@@ -368,7 +389,8 @@ migrate_type=遷移類型
migrate_type_helper=該倉庫將是一個 <span class="text blue">鏡像</span>
migrate_repo=遷移倉庫
migrate.clone_address=複製地址
migrate.clone_address_desc=該地址可以是 HTTP/HTTPS/GIT URL 或本地服務器路徑
migrate.clone_address_desc=該地址可以是 HTTP/HTTPS/GIT 類型的 URL
migrate.clone_address_desc_import_local=您還可以用本地服務器路徑來遷移倉庫。
migrate.permission_denied=您並沒有導入本地倉庫的權限。
migrate.invalid_local_path=無效的本地路徑,該路徑不存在或不是一個目錄!
migrate.failed=遷移失敗:%v
@@ -393,7 +415,7 @@ create_new_repo_command=從命令行創建一個新的倉庫
push_exist_repo=從命令行推送已經創建的倉庫
repo_is_empty=這倉庫不包含任何內容,請稍後再訪問!
code=代碼
files=檔案
branch=分支
tree=目錄樹
filter_branch_and_tag=過濾分支或標籤
@@ -409,6 +431,47 @@ file_raw=原始文件
file_history=文件歷史
file_view_raw=查看原始文件
file_permalink=永久連結
file_too_large=檔案太大,無法顯示
video_not_supported_in_browser=您的瀏覽器不支援 HTML5 影片播放標籤。
editor.new_file=開新檔案
editor.upload_file=上傳檔案
editor.edit_file=編輯文件
editor.preview_changes=預覽更改
editor.cannot_edit_non_text_files=不能編輯非文字檔
editor.edit_this_file=編輯此文件
editor.must_be_on_a_branch=你必須在一個分支或提出對此檔的更改
editor.fork_before_edit=你必須在編輯檔案之前備份此檔案
editor.delete_this_file=刪除此文件
editor.must_have_write_access=您必須具有寫存取權限,或提出對此檔案的更改
editor.file_delete_success=已成功刪除 '%s'
editor.name_your_file=命名您的檔...
editor.filename_help=輸入名稱後按下 / 鍵即可新增資料夾或將滑鼠移至輸入格最左側按下Backspace移除資料夾。
editor.or=
editor.cancel_lower=取消
editor.commit_changes=提交更改嗎?
editor.add_tmpl=添加%s/<filename>'
editor.add=新增 '%s'
editor.update=更新 '%s'
editor.delete=刪除 '%s'
editor.commit_message_desc=添加一個可選的擴展描述...
editor.commit_directly_to_this_branch=直接提交到 <strong class="branch-name">%s</strong> 分支。
editor.create_new_branch=創建 <strong>新的分支</strong> 為此提交和開始合併請求。
editor.new_branch_name_desc=新的分支名稱...
editor.cancel=取消
editor.filename_cannot_be_empty=檔案名不能為空。
editor.branch_already_exists='%s' 已存在於此存儲庫。
editor.directory_is_a_file='%s' 在此倉庫中的路徑是檔案而不是目錄。
editor.file_is_a_symlink=檔案 '%s' 是一個符號連結,不能從 web 編輯器修改。
editor.filename_is_a_directory=檔案名 '%s' 是此資料庫中的現有目錄。
editor.file_editing_no_longer_exists=檔 '%s' 您正在編輯不再存在於資料庫。
editor.file_changed_while_editing=從您開始編輯已更改檔的內容。<a target="_blank"href="%s"> 按一下此處</a> 以查看什麼發生了更改或 <strong>按提交再</strong> 覆蓋這些更改。
editor.file_already_exists=帶有名稱 '%s' 的檔已經存在在這個資料庫中。
editor.no_changes_to_show=沒有可以顯示的變更。
editor.fail_to_update_file=上傳/創建檔案 '%s' 失敗, 錯誤訊息: %v
editor.add_subdir=新增子目錄...
editor.unable_to_upload_files=上傳檔案失敗到 '%s', 錯誤訊息: %v
editor.upload_files_to_dir=上傳檔案到 '%s'
commits.commits=次代碼提交
commits.search=搜索提交歷史
@@ -435,6 +498,11 @@ issues.create=創建問題
issues.new_label=創建標籤
issues.new_label_placeholder=標籤名稱...
issues.create_label=創建標籤
issues.label_templates.title=載入一組預定義的標籤
issues.label_templates.info=沒有任何標籤。你可以點選上面創建一個或按下面"新建標籤"按鈕來使用一組預定義。
issues.label_templates.helper=選擇一個標籤集
issues.label_templates.use=使用此標籤集
issues.label_templates.fail_to_load_file=載入標籤範本檔案 '%s' 失敗: %v
issues.open_tab=%d 個開啓中
issues.close_tab=%d 個已關閉
issues.filter_label=標籤篩選
@@ -462,7 +530,8 @@ issues.next=下一頁
issues.open_title=開啟中
issues.closed_title=已關閉
issues.num_comments=%d 條評論
issues.commented_at=` <a id="%[1]s" href="#%[1]s">%[2]s</a> 評論`
issues.commented_at=` 評論 <a href="#%s"> %s'</a>`
issues.delete_comment_confirm=您確定要刪除該條評論嗎?
issues.no_content=尚未有任何內容
issues.close_issue=關閉
issues.close_comment_issue=關閉及評論
@@ -475,8 +544,7 @@ issues.commit_ref_at=`在代碼提交 <a id="%[1]s" href="#%[1]s">%[2]s</a> 中
issues.poster=發佈者
issues.collaborator=協同者
issues.owner=所有者
issues.sign_up_for_free=免費註冊
issues.sign_in_require_desc=及加入到對話當中。如果您已經註冊,可以直接 <a href="%s">登錄及評論</a>
issues.sign_in_require_desc=<a href="%s"> 登入</a> 才能加入這對話。
issues.edit=編輯
issues.cancel=取消
issues.save=保存
@@ -491,6 +559,8 @@ issues.label_deletion=刪除標籤
issues.label_deletion_desc=刪除該標籤將會移除所有問題中相關的訊息。是否繼續?
issues.label_deletion_success=標籤刪除成功!
issues.num_participants=%d 參與者
issues.attachment.open_tab=`在新的標籤頁中查看 '%s'`
issues.attachment.download=`點擊下載 '%s'`
pulls.new=創建合併請求
pulls.compare_changes=對比文件變化
@@ -517,6 +587,8 @@ pulls.cannot_auto_merge_desc=由於存在衝突,不能自動合併這推送請
pulls.cannot_auto_merge_helper=請手動合併來解決衝突。
pulls.merge_pull_request=合併請求
pulls.open_unmerged_pull_exists=`由於已經存在來自相同倉庫和合併信息的未合併請求(#%d您無法執行重新開啟操作。`
pulls.delete_branch=刪除分支
pulls.delete_branch_has_new_commits=該分支在合併完成後又推送了新的提交,無法執行刪除。
milestones.new=新的里程碑
milestones.open_tab=%d 開啟中
@@ -570,20 +642,27 @@ settings.collaboration.undefined=未定義
settings.hooks=管理 Web 鉤子
settings.githooks=管理 Git 鉤子
settings.basic_settings=基本設置
settings.mirror_settings=鏡像設定
settings.sync_mirror=立即同步
settings.mirror_sync_in_progress=鏡像同步正在進行中,請大約一分鐘後刷新頁面。
settings.site=官方網站
settings.update_settings=更新倉庫設置
settings.change_reponame_prompt=該操作將會影響到所有與該倉庫有關的鏈接
settings.advanced_settings=高級設置
settings.wiki_desc=用 Wiki 以允許用戶協作文檔
settings.wiki_desc=用 Wiki 系統
settings.use_internal_wiki=使用內建 wiki
settings.use_external_wiki=使用外部 wiki
settings.external_wiki_url=外部 Wiki 連結
settings.external_wiki_url_desc=當分頁上按一下,訪客將會重新導到 URL。
settings.issues_desc=啟用內置的輕量級問題管理系統
settings.issues_desc=啟用問題追蹤
settings.use_internal_issue_tracker=使用內建輕量級問題追蹤
settings.use_external_issue_tracker=使用外部的問題管理系統
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=外部問題管理系統的 URL 格式
settings.tracker_issue_style=外部公單管理系統命名風格:
settings.tracker_issue_style.numeric=數字 <span class="ui light grey text">(1234)</span>
settings.tracker_issue_style.alphanumeric=數字與字母結合 <span class="ui light grey text">(ABC-123, DEFG-234, ...)</span>
settings.tracker_issue_style.numeric=數字
settings.tracker_issue_style.alphanumeric=字母及數字
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分別作為用戶名、倉庫名和問題索引的占位符。
settings.pulls_desc=啟用合併請求以接受社區貢獻
settings.danger_zone=危險操作區
@@ -653,6 +732,8 @@ settings.event_send_everything=推送 <strong>所有</strong> 事件
settings.event_choose=讓我選擇我的需要
settings.event_create=創建
settings.event_create_desc=創建分支或標籤
settings.event_pull_request=合併請求
settings.event_pull_request_desc=請求打開,關閉,重新打開,編輯,分配,未分配,標籤更新,標籤清除,或同步。
settings.event_push=推送
settings.event_push_desc=Git 倉庫推送
settings.active=是否激活
@@ -690,7 +771,7 @@ diff.show_unified_view=統一視圖
diff.stats_desc=共有 <strong> %d 個文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
diff.bin=二進制
diff.view_file=查看文件
diff.file_supressed=文件差異過大導致無法顯示
diff.file_suppressed=文件差異過大導致無法顯示
diff.too_many_files=部分文件因文件數量過多而無法顯示
release.releases=版本發佈
@@ -722,6 +803,7 @@ release.deletion=刪除版本發布操作
release.deletion_desc=刪除該版本發布將會移除相應的 Git 標籤。是否繼續?
release.deletion_success=版本發布刪除成功!
release.tag_name_already_exist=已經存在使用相同標籤的發佈版本。
release.tag_name_invalid=標記名稱不是有效的。
release.downloads=下載附件
[org]
@@ -889,6 +971,7 @@ users.edit_account=編輯用戶信息
users.max_repo_creation=最大儲存庫新增限制
users.max_repo_creation_desc=(設定 -1 使用全域預設限制)
users.is_activated=該用戶已被激活
users.prohibit_login=此帳戶禁止登錄
users.is_admin=該用戶具有管理員權限
users.allow_git_hook=該帳戶具有創建 Git 鉤子的權限
users.allow_import_local=該用戶具有導入本地倉庫的權限
@@ -957,6 +1040,7 @@ auths.delete_auth_title=刪除認證操作
auths.delete_auth_desc=該認證將被刪除。是否繼續?
auths.still_in_used=一些使用者仍然使用此驗證方式,請先刪除或轉換這些使用者到其它登入類型。
auths.deletion_success=認證源刪除成功!
auths.login_source_exist=登錄源 '%s' 已存在。
config.server_config=服務器配置
config.app_name=應用名稱
@@ -967,6 +1051,7 @@ config.offline_mode=離線模式
config.disable_router_log=關閉路由日志
config.run_user=執行用戶
config.run_mode=執行模式
config.git_version=Git Version
config.repo_root_path=倉庫根目錄
config.static_file_root_path=靜態文件根目錄
config.log_file_root_path=日志文件根目錄
@@ -994,6 +1079,7 @@ config.db_ssl_mode=SSL 模式
config.db_ssl_mode_helper=(僅限 "postgres" 使用)
config.db_path=數據庫路徑
config.db_path_helper=(用於 "sqlite3" 和 "tidb"
config.service_config=服務配置
config.register_email_confirm=註冊電子郵件確認
config.disable_register=關閉註冊功能
@@ -1004,10 +1090,12 @@ config.disable_key_size_check=禁用密鑰最小長度檢查
config.enable_captcha=啟用驗證碼服務
config.active_code_lives=激活用戶連結有效期
config.reset_password_code_lives=重置密碼連結有效期
config.webhook_config=Web 鉤子配置
config.queue_length=隊列長度
config.deliver_timeout=推送超時
config.skip_tls_verify=忽略 TLS 驗證
config.mailer_config=郵件配置
config.mailer_enabled=啟用服務
config.mailer_disable_helo=禁用 HELO 操作
@@ -1017,12 +1105,15 @@ config.mailer_user=發送者帳號
config.send_test_mail=發送測試郵件
config.test_mail_failed=無法向 '%s' 發送測試郵件: %v
config.test_mail_sent=測試電子郵件已發送到 '%s'。
config.oauth_config=社交帳號配置
config.oauth_enabled=啟用服務
config.cache_config=Cache 配置
config.cache_adapter=Cache 適配器
config.cache_interval=Cache 周期
config.cache_conn=Cache 連接字符串
config.session_config=Session 配置
config.session_provider=Session 提供者
config.provider_config=提供者配置
@@ -1032,9 +1123,24 @@ config.gc_interval_time=垃圾收集周期
config.session_life_time=Session 生命周期
config.https_only=僅限 HTTPS
config.cookie_life_time=Cookie 生命周期
config.picture_config=圖片配置
config.picture_service=圖片服務
config.disable_gravatar=禁用 Gravatar 頭像
config.enable_federated_avatar=開啟聯合頭像
config.git_config=Git 配置
config.git_disable_diff_highlight=禁用比較語法高亮
config.git_max_diff_lines=Max Diff 線 (對於單個檔)
config.git_max_diff_line_characters=最大比較的字元 (單行)
config.git_max_diff_files=Max Diff 檔 (顯示)
config.git_gc_args=GC 參數
config.git_migrate_timeout=移動超時
config.git_mirror_timeout=鏡像更新超時
config.git_clone_timeout=複製操作超時
config.git_pull_timeout=操作超時
config.git_gc_timeout=GC 操作超時
config.log_config=日誌配置
config.log_mode=日誌模式

View File

@@ -71,7 +71,7 @@ Most of settings are obvious and easy to understand, but there are some settings
- **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](http://gogs.io/docs/advanced/configuration_cheat_sheet.html).
Full documentation of application settings can be found [here](https://gogs.io/docs/advanced/configuration_cheat_sheet.html).
### Container options

View File

@@ -10,23 +10,15 @@ 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
go get -v -tags "sqlite cert pam" ./...
make build TAGS="sqlite cert pam"
# Cleanup GOPATH & vendoring dir
rm -r $GOPATH /app/gogs/vendor
# Cleanup GOPATH
rm -r $GOPATH
# Remove build deps
apk --no-progress del build-deps

148
glide.lock generated
View File

@@ -1,148 +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/codegangsta/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: 3654d25ec346ee8ce71a68431025458d52a38ac0
- name: github.com/go-xorm/core
version: bc1b7f81f0e369289078424064634a5ee7d21051
- name: github.com/go-xorm/xorm
version: b8b1711cde4d9c68da95cd0ff8de0de0cb491df3
- name: github.com/gogits/chardet
version: 2404f777256163ea3eadb273dada5dcb037993c0
- name: github.com/gogits/cron
version: 96040e4fab17baa0391ce571694e4ccb5fce5dac
- name: github.com/gogits/git-module
version: db93fa550116997bbe0b62baa653b8e6f4135258
- name: github.com/gogits/go-gogs-client
version: ee68cd9eefff11615f336e9965762f6736eeecc8
- 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: ee1442bda7bd1b6a84e913bdb421cb1874ec629d
subpackages:
- oid
- name: github.com/mattn/go-sqlite3
version: 38ee283dabf11c9cbdb968eebd79b1fa7acbabe6
- name: github.com/mcuadros/go-version
version: d52711f8d6bea8dc01efafdb68ad95a4e2606630
- name: github.com/microcosm-cc/bluemonday
version: 4ac6f27528d0a3f2a59e0b0a6f6b3ff0bb89fe20
- name: github.com/msteinert/pam
version: 02ccfbfaf0cc627aa3aec8ef7ed5cfeec5b43f63
- name: github.com/nfnt/resize
version: 4d93a29130b1b6aba503e2aa8b50f516213ea80e
- name: github.com/russross/blackfriday
version: 4e6f303e8d936855981ddcdbfc092b03d2b2b68e
- name: github.com/satori/go.uuid
version: 879c5887cd475cd7864858769793b2ceb0d44feb
- name: github.com/sergi/go-diff
version: ec7fdbb58eb3e300c8595ad5ac74a5aa50019cc7
subpackages:
- diffmatchpatch
- 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: 77f4136a99ffb5ecdbdd0226bd5cb146cf56bc0e
subpackages:
- ssh
- curve25519
- ed25519
- ed25519/internal/edwards25519
- name: golang.org/x/net
version: 3f122ce3dbbe488b7e6a8bdb26f41edec852a40b
subpackages:
- html
- html/charset
- html/atom
- name: golang.org/x/sys
version: 7f918dd405547ecb864d14a8ecbbfe205b5f930f
subpackages:
- windows/svc
- windows
- name: golang.org/x/text
version: e4775119bd79944a15a741ac4be61e43509a70d9
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/gomail.v2
version: 81ebce5c23dfd25c6c67194b37d3dd3f338c98b1
- name: gopkg.in/ini.v1
version: 72ba3e6b9e6b87e0c74c9a7a4dc86e8dd8ba4355
- name: gopkg.in/ldap.v2
version: 0e7db8eb77695b5a952f0e5d78df9ab160050c73
- name: gopkg.in/macaron.v1
version: 2133042f8d1022b8253e4e23f7940467941409ce
- name: gopkg.in/redis.v2
version: e6179049628164864e6e84e973cfb56335748dea
devImports: []

View File

@@ -1,57 +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/codegangsta/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: 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/gomail.v2
- package: gopkg.in/ini.v1
- package: gopkg.in/ldap.v2
- package: gopkg.in/macaron.v1

12
gogs.go
View File

@@ -1,4 +1,4 @@
// +build go1.4
// +build go1.5
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
@@ -9,25 +9,23 @@ package main
import (
"os"
"runtime"
"github.com/codegangsta/cli"
"github.com/urfave/cli"
"github.com/gogits/gogs/cmd"
"github.com/gogits/gogs/modules/setting"
)
const APP_VER = "0.9.46.0717"
const APP_VER = "0.9.141.0211"
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
setting.AppVer = APP_VER
}
func main() {
app := cli.NewApp()
app.Name = "Gogs"
app.Usage = "Go Git Service"
app.Usage = "Go Git Service: a painless self-hosted Git service"
app.Version = APP_VER
app.Commands = []cli.Command{
cmd.CmdWeb,
@@ -35,6 +33,8 @@ func main() {
cmd.CmdUpdate,
cmd.CmdDump,
cmd.CmdCert,
cmd.CmdAdmin,
cmd.CmdImport,
}
app.Flags = append(app.Flags, []cli.Flag{}...)
app.Run(os.Args)

View File

@@ -7,7 +7,7 @@ package models
import (
"fmt"
"github.com/gogits/gogs/modules/log"
log "gopkg.in/clog.v1"
)
type AccessMode int
@@ -67,11 +67,11 @@ func accessLevel(e Engine, u *User, repo *Repository) (AccessMode, error) {
return mode, nil
}
if u.Id == repo.OwnerID {
if u.ID == repo.OwnerID {
return ACCESS_MODE_OWNER, nil
}
a := &Access{UserID: u.Id, RepoID: repo.ID}
a := &Access{UserID: u.ID, RepoID: repo.ID}
if has, err := e.Get(a); !has || err != nil {
return mode, err
}
@@ -97,7 +97,7 @@ func HasAccess(u *User, repo *Repository, testMode AccessMode) (bool, error) {
// 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) {
accesses := make([]*Access, 0, 10)
if err := x.Find(&accesses, &Access{UserID: u.Id}); err != nil {
if err := x.Find(&accesses, &Access{UserID: u.ID}); err != nil {
return nil, err
}
@@ -113,7 +113,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 == u.ID {
continue
}
repos[repo] = access.Mode
@@ -121,23 +121,17 @@ func (u *User) GetRepositoryAccesses() (map[*Repository]AccessMode, error) {
return repos, nil
}
// GetAccessibleRepositories finds all repositories where a user has access but does not own.
func (u *User) GetAccessibleRepositories() ([]*Repository, error) {
accesses := make([]*Access, 0, 10)
if err := x.Find(&accesses, &Access{UserID: u.Id}); err != nil {
return nil, err
// 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")
if limit > 0 {
sess.Limit(limit)
repos = make([]*Repository, 0, limit)
} else {
repos = make([]*Repository, 0, 10)
}
if len(accesses) == 0 {
return []*Repository{}, nil
}
repoIDs := make([]int64, 0, len(accesses))
for _, access := range accesses {
repoIDs = append(repoIDs, access.RepoID)
}
repos := make([]*Repository, 0, len(repoIDs))
return repos, x.Where("owner_id != ?", u.Id).In("id", repoIDs).Desc("updated_unix").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 {
@@ -227,7 +221,7 @@ func (repo *Repository) recalculateTeamAccesses(e Engine, ignTeamID int64) (err
return fmt.Errorf("getMembers '%d': %v", t.ID, err)
}
for _, m := range t.Members {
accessMap[m.Id] = maxAccessMode(accessMap[m.Id], t.Authorize)
accessMap[m.ID] = maxAccessMode(accessMap[m.ID], t.Authorize)
}
}

View File

@@ -6,7 +6,6 @@ package models
import (
"encoding/json"
"errors"
"fmt"
"path"
"regexp"
@@ -16,12 +15,12 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
@@ -45,10 +44,6 @@ const (
ACTION_REOPEN_PULL_REQUEST // 15
)
var (
ErrNotImplemented = errors.New("Not implemented yet")
)
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"}
@@ -68,7 +63,7 @@ func init() {
IssueReferenceKeywordsPat = regexp.MustCompile(`(?i)(?:)(^| )\S+`)
}
// Action represents user operation type and other information to repository.,
// 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"`
@@ -76,7 +71,6 @@ type Action struct {
OpType ActionType
ActUserID int64 // Action user id.
ActUserName string // Action user name.
ActEmail string
ActAvatar string `xorm:"-"`
RepoID int64
RepoUserName string
@@ -89,7 +83,7 @@ type Action struct {
}
func (a *Action) BeforeInsert() {
a.CreatedUnix = time.Now().UTC().Unix()
a.CreatedUnix = time.Now().Unix()
}
func (a *Action) AfterSet(colName string, _ xorm.Cell) {
@@ -111,10 +105,6 @@ func (a *Action) ShortActUserName() string {
return base.EllipsisString(a.ActUserName, 20)
}
func (a *Action) GetActEmail() string {
return a.ActEmail
}
func (a *Action) GetRepoUserName() string {
return a.RepoUserName
}
@@ -169,7 +159,7 @@ func (a *Action) GetIssueTitle() string {
log.Error(4, "GetIssueByIndex: %v", err)
return "500 when get issue"
}
return issue.Name
return issue.Title
}
func (a *Action) GetIssueContent() string {
@@ -184,16 +174,15 @@ func (a *Action) GetIssueContent() string {
func newRepoAction(e Engine, u *User, repo *Repository) (err error) {
if err = notifyWatchers(e, &Action{
ActUserID: u.Id,
ActUserID: u.ID,
ActUserName: u.Name,
ActEmail: u.Email,
OpType: ACTION_CREATE_REPO,
RepoID: repo.ID,
RepoUserName: repo.Owner.Name,
RepoName: repo.Name,
IsPrivate: repo.IsPrivate,
}); err != nil {
return fmt.Errorf("notify watchers '%d/%d': %v", u.Id, repo.ID, err)
return fmt.Errorf("notify watchers '%d/%d': %v", u.ID, repo.ID, err)
}
log.Trace("action.newRepoAction: %s/%s", u.Name, repo.Name)
@@ -207,9 +196,8 @@ func NewRepoAction(u *User, repo *Repository) (err error) {
func renameRepoAction(e Engine, actUser *User, oldRepoName string, repo *Repository) (err error) {
if err = notifyWatchers(e, &Action{
ActUserID: actUser.Id,
ActUserID: actUser.ID,
ActUserName: actUser.Name,
ActEmail: actUser.Email,
OpType: ACTION_RENAME_REPO,
RepoID: repo.ID,
RepoUserName: repo.Owner.Name,
@@ -234,16 +222,19 @@ func issueIndexTrimRight(c rune) bool {
}
type PushCommit struct {
Sha1 string
Message string
AuthorEmail string
AuthorName string
Sha1 string
Message string
AuthorEmail string
AuthorName string
CommitterEmail string
CommitterName string
Timestamp time.Time
}
type PushCommits struct {
Len int
Commits []*PushCommit
CompareUrl string
CompareURL string
avatars map[string]string
}
@@ -256,21 +247,33 @@ func NewPushCommits() *PushCommits {
func (pc *PushCommits) ToApiPayloadCommits(repoLink string) []*api.PayloadCommit {
commits := make([]*api.PayloadCommit, len(pc.Commits))
for i, cmt := range pc.Commits {
author_username := ""
author, err := GetUserByEmail(cmt.AuthorEmail)
for i, commit := range pc.Commits {
authorUsername := ""
author, err := GetUserByEmail(commit.AuthorEmail)
if err == nil {
author_username = author.Name
authorUsername = author.Name
}
committerUsername := ""
committer, err := GetUserByEmail(commit.CommitterEmail)
if err == nil {
// TODO: check errors other than email not found.
committerUsername = committer.Name
}
commits[i] = &api.PayloadCommit{
ID: cmt.Sha1,
Message: cmt.Message,
URL: fmt.Sprintf("%s/commit/%s", repoLink, cmt.Sha1),
Author: &api.PayloadAuthor{
Name: cmt.AuthorName,
Email: cmt.AuthorEmail,
UserName: author_username,
ID: commit.Sha1,
Message: commit.Message,
URL: fmt.Sprintf("%s/commit/%s", repoLink, commit.Sha1),
Author: &api.PayloadUser{
Name: commit.AuthorName,
Email: commit.AuthorEmail,
UserName: authorUsername,
},
Committer: &api.PayloadUser{
Name: commit.CommitterName,
Email: commit.CommitterEmail,
UserName: committerUsername,
},
Timestamp: commit.Timestamp,
}
}
return commits
@@ -288,15 +291,15 @@ func (push *PushCommits) AvatarLink(email string) string {
log.Error(4, "GetUserByEmail: %v", err)
}
} else {
push.avatars[email] = u.AvatarLink()
push.avatars[email] = u.RelAvatarLink()
}
}
return push.avatars[email]
}
// updateIssuesCommit checks if issues are manipulated by commit message.
func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string, commits []*PushCommit) error {
// UpdateIssuesCommit checks if issues are manipulated by commit message.
func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) error {
// Commits are appended in the reverse order.
for i := len(commits) - 1; i >= 0; i-- {
c := commits[i]
@@ -312,7 +315,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
// Add repo name if missing
if ref[0] == '#' {
ref = fmt.Sprintf("%s/%s%s", repoUserName, repoName, ref)
ref = fmt.Sprintf("%s%s", repo.FullName(), ref)
} else if !strings.Contains(ref, "/") {
// FIXME: We don't support User#ID syntax yet
// return ErrNotImplemented
@@ -332,9 +335,8 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
}
refMarked[issue.ID] = true
url := fmt.Sprintf("%s/%s/%s/commit/%s", setting.AppSubUrl, repoUserName, repoName, c.Sha1)
message := fmt.Sprintf(`<a href="%s">%s</a>`, url, c.Message)
if err = CreateRefComment(u, repo, issue, message, c.Sha1); err != nil {
message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, repo.Link(), c.Sha1, c.Message)
if err = CreateRefComment(doer, repo, issue, message, c.Sha1); err != nil {
return err
}
}
@@ -351,7 +353,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
// Add repo name if missing
if ref[0] == '#' {
ref = fmt.Sprintf("%s/%s%s", repoUserName, repoName, ref)
ref = fmt.Sprintf("%s%s", repo.FullName(), ref)
} else if !strings.Contains(ref, "/") {
// We don't support User#ID syntax yet
// return ErrNotImplemented
@@ -375,7 +377,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
continue
}
if err = issue.ChangeStatus(u, repo, true); err != nil {
if err = issue.ChangeStatus(doer, repo, true); err != nil {
return err
}
}
@@ -391,7 +393,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
// Add repo name if missing
if ref[0] == '#' {
ref = fmt.Sprintf("%s/%s%s", repoUserName, repoName, ref)
ref = fmt.Sprintf("%s%s", repo.FullName(), ref)
} else if !strings.Contains(ref, "/") {
// We don't support User#ID syntax yet
// return ErrNotImplemented
@@ -415,7 +417,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
continue
}
if err = issue.ChangeStatus(u, repo, false); err != nil {
if err = issue.ChangeStatus(doer, repo, false); err != nil {
return err
}
}
@@ -423,26 +425,26 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string
return nil
}
// CommitRepoAction adds new action for committing repository.
func CommitRepoAction(
userID, repoUserID int64,
userName, actEmail string,
repoID int64,
repoUserName, repoName string,
refFullName string,
commit *PushCommits,
oldCommitID string, newCommitID string) error {
type CommitRepoActionOptions struct {
PusherName string
RepoOwnerID int64
RepoName string
RefFullName string
OldCommitID string
NewCommitID string
Commits *PushCommits
}
u, err := GetUserByID(userID)
// CommitRepoAction adds new commit actio to the repository, and prepare corresponding webhooks.
func CommitRepoAction(opts CommitRepoActionOptions) error {
pusher, err := GetUserByName(opts.PusherName)
if err != nil {
return fmt.Errorf("GetUserByID: %v", err)
return fmt.Errorf("GetUserByName [%s]: %v", opts.PusherName, err)
}
repo, err := GetRepositoryByName(repoUserID, repoName)
repo, err := GetRepositoryByName(opts.RepoOwnerID, opts.RepoName)
if err != nil {
return fmt.Errorf("GetRepositoryByName: %v", err)
} else if err = repo.GetOwner(); err != nil {
return fmt.Errorf("GetOwner: %v", err)
return fmt.Errorf("GetRepositoryByName [owner_id: %d, name: %s]: %v", opts.RepoOwnerID, opts.RepoName, err)
}
// Change repository bare status and update last updated time.
@@ -454,41 +456,39 @@ func CommitRepoAction(
isNewBranch := false
opType := ACTION_COMMIT_REPO
// Check it's tag push or branch.
if strings.HasPrefix(refFullName, "refs/tags/") {
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
opType = ACTION_PUSH_TAG
commit = &PushCommits{}
opts.Commits = &PushCommits{}
} else {
// if not the first commit, set the compareUrl
if !strings.HasPrefix(oldCommitID, "0000000") {
commit.CompareUrl = repo.ComposeCompareURL(oldCommitID, newCommitID)
} else {
// if not the first commit, set the compare URL.
if opts.OldCommitID == git.EMPTY_SHA {
isNewBranch = true
} else {
opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
}
if err = updateIssuesCommit(u, repo, repoUserName, repoName, commit.Commits); err != nil {
if err = UpdateIssuesCommit(pusher, repo, opts.Commits.Commits); err != nil {
log.Error(4, "updateIssuesCommit: %v", err)
}
}
if len(commit.Commits) > setting.FeedMaxCommitNum {
commit.Commits = commit.Commits[:setting.FeedMaxCommitNum]
if len(opts.Commits.Commits) > setting.UI.FeedMaxCommitNum {
opts.Commits.Commits = opts.Commits.Commits[:setting.UI.FeedMaxCommitNum]
}
bs, err := json.Marshal(commit)
data, err := json.Marshal(opts.Commits)
if err != nil {
return fmt.Errorf("Marshal: %v", err)
}
refName := git.RefEndName(refFullName)
refName := git.RefEndName(opts.RefFullName)
if err = NotifyWatchers(&Action{
ActUserID: u.Id,
ActUserName: userName,
ActEmail: actEmail,
ActUserID: pusher.ID,
ActUserName: pusher.Name,
OpType: opType,
Content: string(bs),
Content: string(data),
RepoID: repo.ID,
RepoUserName: repoUserName,
RepoUserName: repo.MustOwner().Name,
RepoName: repo.Name,
RefName: refName,
IsPrivate: repo.IsPrivate,
@@ -496,37 +496,24 @@ func CommitRepoAction(
return fmt.Errorf("NotifyWatchers: %v", err)
}
payloadRepo := repo.ComposePayload()
pusher_email, pusher_name := "", ""
pusher, err := GetUserByName(userName)
if err == nil {
pusher_email = pusher.Email
pusher_name = pusher.DisplayName()
}
payloadSender := &api.PayloadUser{
UserName: pusher.Name,
ID: pusher.Id,
AvatarUrl: pusher.AvatarLink(),
}
defer func() {
go HookQueue.Add(repo.ID)
}()
apiPusher := pusher.APIFormat()
apiRepo := repo.APIFormat(nil)
switch opType {
case ACTION_COMMIT_REPO: // Push
p := &api.PushPayload{
Ref: refFullName,
Before: oldCommitID,
After: newCommitID,
CompareUrl: setting.AppUrl + commit.CompareUrl,
Commits: commit.ToApiPayloadCommits(repo.FullLink()),
Repo: payloadRepo,
Pusher: &api.PayloadAuthor{
Name: pusher_name,
Email: pusher_email,
UserName: userName,
},
Sender: payloadSender,
}
if err = PrepareWebhooks(repo, HOOK_EVENT_PUSH, p); err != nil {
if err = PrepareWebhooks(repo, HOOK_EVENT_PUSH, &api.PushPayload{
Ref: opts.RefFullName,
Before: opts.OldCommitID,
After: opts.NewCommitID,
CompareURL: setting.AppUrl + opts.Commits.CompareURL,
Commits: opts.Commits.ToApiPayloadCommits(repo.HTMLURL()),
Repo: apiRepo,
Pusher: apiPusher,
Sender: apiPusher,
}); err != nil {
return fmt.Errorf("PrepareWebhooks: %v", err)
}
@@ -534,8 +521,8 @@ func CommitRepoAction(
return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
Ref: refName,
RefType: "branch",
Repo: payloadRepo,
Sender: payloadSender,
Repo: apiRepo,
Sender: apiPusher,
})
}
@@ -543,52 +530,50 @@ func CommitRepoAction(
return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
Ref: refName,
RefType: "tag",
Repo: payloadRepo,
Sender: payloadSender,
Repo: apiRepo,
Sender: apiPusher,
})
}
return nil
}
func transferRepoAction(e Engine, actUser, oldOwner, newOwner *User, repo *Repository) (err error) {
func transferRepoAction(e Engine, doer, oldOwner *User, repo *Repository) (err error) {
if err = notifyWatchers(e, &Action{
ActUserID: actUser.Id,
ActUserName: actUser.Name,
ActEmail: actUser.Email,
ActUserID: doer.ID,
ActUserName: doer.Name,
OpType: ACTION_TRANSFER_REPO,
RepoID: repo.ID,
RepoUserName: newOwner.Name,
RepoUserName: repo.Owner.Name,
RepoName: repo.Name,
IsPrivate: repo.IsPrivate,
Content: path.Join(oldOwner.Name, repo.Name),
}); err != nil {
return fmt.Errorf("notify watchers '%d/%d': %v", actUser.Id, repo.ID, err)
return fmt.Errorf("notifyWatchers: %v", err)
}
// Remove watch for organization.
if repo.Owner.IsOrganization() {
if err = watchRepo(e, repo.Owner.Id, repo.ID, false); err != nil {
return fmt.Errorf("watch repository: %v", err)
if oldOwner.IsOrganization() {
if err = watchRepo(e, oldOwner.ID, repo.ID, false); err != nil {
return fmt.Errorf("watchRepo [false]: %v", err)
}
}
log.Trace("action.transferRepoAction: %s/%s", actUser.Name, repo.Name)
return nil
}
// TransferRepoAction adds new action for transferring repository.
func TransferRepoAction(actUser, oldOwner, newOwner *User, repo *Repository) error {
return transferRepoAction(x, actUser, oldOwner, newOwner, repo)
// TransferRepoAction adds new action for transferring repository,
// the Owner field of repository is assumed to be new owner.
func TransferRepoAction(doer, oldOwner *User, repo *Repository) error {
return transferRepoAction(x, doer, oldOwner, repo)
}
func mergePullRequestAction(e Engine, actUser *User, repo *Repository, pull *Issue) error {
func mergePullRequestAction(e Engine, doer *User, repo *Repository, issue *Issue) error {
return notifyWatchers(e, &Action{
ActUserID: actUser.Id,
ActUserName: actUser.Name,
ActEmail: actUser.Email,
ActUserID: doer.ID,
ActUserName: doer.Name,
OpType: ACTION_MERGE_PULL_REQUEST,
Content: fmt.Sprintf("%d|%s", pull.Index, pull.Name),
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title),
RepoID: repo.ID,
RepoUserName: repo.Owner.Name,
RepoName: repo.Name,
@@ -602,21 +587,22 @@ func MergePullRequestAction(actUser *User, repo *Repository, pull *Issue) error
}
// GetFeeds returns action list of given user in given context.
// userID is the user who's requesting, ctxUserID is the user/org that is requested.
// userID can be -1, if isProfile is true or in order to skip the permission check.
func GetFeeds(ctxUserID, userID, offset int64, isProfile bool) ([]*Action, error) {
// actorID is the user who's requesting, ctxUserID is the user/org that is requested.
// 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=?", ctxUserID)
sess := x.Limit(20, int(offset)).Desc("id").Where("user_id = ?", ctxUser.ID)
if isProfile {
sess.And("is_private=?", false).And("act_user_id=?", ctxUserID)
} else if ctxUserID != -1 {
ctxUser := &User{Id: ctxUserID}
if err := ctxUser.GetUserRepositories(userID); err != nil {
return nil, err
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)
if err != nil {
return nil, fmt.Errorf("GetUserRepositories: %v", err)
}
var repoIDs []int64
for _, repo := range ctxUser.Repos {
for _, repo := range repos {
repoIDs = append(repoIDs, repo.ID)
}

View File

@@ -13,9 +13,9 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
@@ -35,7 +35,7 @@ type Notice struct {
}
func (n *Notice) BeforeInsert() {
n.CreatedUnix = time.Now().UTC().Unix()
n.CreatedUnix = time.Now().Unix()
}
func (n *Notice) AfterSet(colName string, _ xorm.Cell) {
@@ -77,7 +77,8 @@ func RemoveAllWithNotice(title, path string) {
// workaround for Go not being able to remove read-only files/folders: https://github.com/golang/go/issues/9606
// this bug should be fixed on Go 1.7, so the workaround should be removed when Gogs don't support Go 1.6 anymore:
// https://github.com/golang/go/commit/2ffb3e5d905b5622204d199128dec06cefd57790
if setting.IsWindows {
// Note: Windows complains when delete target does not exist, therefore we can skip deletion in such cases.
if setting.IsWindows && com.IsExist(path) {
// converting "/" to "\" in path on Windows
path = strings.Replace(path, "/", "\\", -1)
err = exec.Command("cmd", "/C", "rmdir", "/S", "/Q", path).Run()

175
models/attachment.go Normal file
View File

@@ -0,0 +1,175 @@
// Copyright 2017 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 models
import (
"fmt"
"io"
"mime/multipart"
"os"
"path"
"time"
"github.com/go-xorm/xorm"
gouuid "github.com/satori/go.uuid"
"github.com/gogits/gogs/modules/setting"
)
// Attachment represent a attachment of issue/comment/release.
type Attachment struct {
ID int64 `xorm:"pk autoincr"`
UUID string `xorm:"uuid UNIQUE"`
IssueID int64 `xorm:"INDEX"`
CommentID int64
ReleaseID int64 `xorm:"INDEX"`
Name string
Created time.Time `xorm:"-"`
CreatedUnix int64
}
func (a *Attachment) BeforeInsert() {
a.CreatedUnix = time.Now().Unix()
}
func (a *Attachment) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
a.Created = time.Unix(a.CreatedUnix, 0).Local()
}
}
// 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)
}
// NewAttachment creates a new attachment object.
func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment, err error) {
attach := &Attachment{
UUID: gouuid.NewV4().String(),
Name: name,
}
localPath := attach.LocalPath()
if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
return nil, fmt.Errorf("MkdirAll: %v", err)
}
fw, err := os.Create(localPath)
if err != nil {
return nil, fmt.Errorf("Create: %v", err)
}
defer fw.Close()
if _, err = fw.Write(buf); err != nil {
return nil, fmt.Errorf("Write: %v", err)
} else if _, err = io.Copy(fw, file); err != nil {
return nil, fmt.Errorf("Copy: %v", err)
}
if _, err := x.Insert(attach); err != nil {
return nil, err
}
return attach, nil
}
func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) {
attach := &Attachment{UUID: uuid}
has, err := x.Get(attach)
if err != nil {
return nil, err
} else if !has {
return nil, ErrAttachmentNotExist{0, uuid}
}
return attach, nil
}
func getAttachmentsByUUIDs(e Engine, uuids []string) ([]*Attachment, error) {
if len(uuids) == 0 {
return []*Attachment{}, nil
}
// Silently drop invalid uuids.
attachments := make([]*Attachment, 0, len(uuids))
return attachments, e.In("uuid", uuids).Find(&attachments)
}
// GetAttachmentByUUID returns attachment by given UUID.
func GetAttachmentByUUID(uuid string) (*Attachment, error) {
return getAttachmentByUUID(x, uuid)
}
func getAttachmentsByIssueID(e Engine, issueID int64) ([]*Attachment, error) {
attachments := make([]*Attachment, 0, 10)
return attachments, e.Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments)
}
// GetAttachmentsByIssueID returns all attachments of an issue.
func GetAttachmentsByIssueID(issueID int64) ([]*Attachment, error) {
return getAttachmentsByIssueID(x, issueID)
}
func getAttachmentsByCommentID(e Engine, commentID int64) ([]*Attachment, error) {
attachments := make([]*Attachment, 0, 10)
return attachments, e.Where("comment_id=?", commentID).Find(&attachments)
}
// GetAttachmentsByCommentID returns all attachments if comment by given ID.
func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) {
return getAttachmentsByCommentID(x, commentID)
}
// DeleteAttachment deletes the given attachment and optionally the associated file.
func DeleteAttachment(a *Attachment, remove bool) error {
_, err := DeleteAttachments([]*Attachment{a}, remove)
return err
}
// DeleteAttachments deletes the given attachments and optionally the associated files.
func DeleteAttachments(attachments []*Attachment, remove bool) (int, error) {
for i, a := range attachments {
if remove {
if err := os.Remove(a.LocalPath()); err != nil {
return i, err
}
}
if _, err := x.Delete(a); err != nil {
return i, err
}
}
return len(attachments), nil
}
// DeleteAttachmentsByIssue deletes all attachments associated with the given issue.
func DeleteAttachmentsByIssue(issueId int64, remove bool) (int, error) {
attachments, err := GetAttachmentsByIssueID(issueId)
if err != nil {
return 0, err
}
return DeleteAttachments(attachments, remove)
}
// DeleteAttachmentsByComment deletes all attachments associated with the given comment.
func DeleteAttachmentsByComment(commentId int64, remove bool) (int, error) {
attachments, err := GetAttachmentsByCommentID(commentId)
if err != nil {
return 0, err
}
return DeleteAttachments(attachments, remove)
}

View File

@@ -11,8 +11,10 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown"
)
@@ -49,8 +51,9 @@ type Comment struct {
ID int64 `xorm:"pk autoincr"`
Type CommentType
PosterID int64
Poster *User `xorm:"-"`
IssueID int64 `xorm:"INDEX"`
Poster *User `xorm:"-"`
IssueID int64 `xorm:"INDEX"`
Issue *Issue `xorm:"-"`
CommitID int64
Line int64
Content string `xorm:"TEXT"`
@@ -58,6 +61,8 @@ type Comment struct {
Created time.Time `xorm:"-"`
CreatedUnix int64
Updated time.Time `xorm:"-"`
UpdatedUnix int64
// Reference issue in commit message
CommitSHA string `xorm:"VARCHAR(40)"`
@@ -69,31 +74,55 @@ type Comment struct {
}
func (c *Comment) BeforeInsert() {
c.CreatedUnix = time.Now().UTC().Unix()
c.CreatedUnix = time.Now().Unix()
c.UpdatedUnix = c.CreatedUnix
}
func (c *Comment) BeforeUpdate() {
c.UpdatedUnix = time.Now().Unix()
}
func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
var err error
switch colName {
case "id":
c.Attachments, err = GetAttachmentsByCommentID(c.ID)
if err != nil {
log.Error(3, "GetAttachmentsByCommentID[%d]: %v", c.ID, err)
}
case "created_unix":
c.Created = time.Unix(c.CreatedUnix, 0).Local()
case "updated_unix":
c.Updated = time.Unix(c.UpdatedUnix, 0).Local()
}
}
case "poster_id":
func (c *Comment) loadAttributes(e Engine) (err error) {
if c.Poster == nil {
c.Poster, err = GetUserByID(c.PosterID)
if err != nil {
if IsErrUserNotExist(err) {
c.PosterID = -1
c.Poster = NewFakeUser()
c.Poster = NewGhostUser()
} else {
log.Error(3, "GetUserByID[%d]: %v", c.ID, err)
return fmt.Errorf("getUserByID.(Poster) [%d]: %v", c.PosterID, err)
}
}
case "created_unix":
c.Created = time.Unix(c.CreatedUnix, 0).Local()
}
if c.Issue == nil {
c.Issue, err = getRawIssueByID(e, c.IssueID)
if err != nil {
return fmt.Errorf("getIssueByID [%d]: %v", c.IssueID, err)
}
}
if c.Attachments == nil {
c.Attachments, err = getAttachmentsByCommentID(e, c.ID)
if err != nil {
return fmt.Errorf("getAttachmentsByCommentID [%d]: %v", c.ID, err)
}
}
return nil
}
func (c *Comment) LoadAttributes() error {
return c.loadAttributes(x)
}
func (c *Comment) AfterDelete() {
@@ -104,6 +133,23 @@ func (c *Comment) AfterDelete() {
}
}
func (c *Comment) HTMLURL() string {
return fmt.Sprintf("%s#issuecomment-%d", c.Issue.HTMLURL(), c.ID)
}
// This method assumes following fields have been assigned with valid values:
// Required - Poster, Issue
func (c *Comment) APIFormat() *api.Comment {
return &api.Comment{
ID: c.ID,
HTMLURL: c.HTMLURL(),
Poster: c.Poster.APIFormat(),
Body: c.Content,
Created: c.Created,
Updated: c.Updated,
}
}
// HashTag returns unique hash tag for comment.
func (c *Comment) HashTag() string {
return "issuecomment-" + com.ToStr(c.ID)
@@ -114,11 +160,11 @@ func (c *Comment) EventTag() string {
return "event-" + com.ToStr(c.ID)
}
// MailParticipants sends new comment emails to repository watchers
// mailParticipants sends new comment emails to repository watchers
// and mentioned people.
func (cmt *Comment) MailParticipants(opType ActionType, issue *Issue) (err error) {
func (cmt *Comment) mailParticipants(e Engine, opType ActionType, issue *Issue) (err error) {
mentions := markdown.FindAllMentions(cmt.Content)
if err = UpdateIssueMentions(cmt.IssueID, mentions); err != nil {
if err = updateIssueMentions(e, cmt.IssueID, mentions); err != nil {
return fmt.Errorf("UpdateIssueMentions [%d]: %v", cmt.IssueID, err)
}
@@ -140,7 +186,7 @@ func (cmt *Comment) MailParticipants(opType ActionType, issue *Issue) (err error
func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err error) {
comment := &Comment{
Type: opts.Type,
PosterID: opts.Doer.Id,
PosterID: opts.Doer.ID,
Poster: opts.Doer,
IssueID: opts.Issue.ID,
CommitID: opts.CommitID,
@@ -155,9 +201,8 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
// Compose comment action, could be plain comment, close or reopen issue/pull request.
// This object will be used to notify watchers in the end of function.
act := &Action{
ActUserID: opts.Doer.Id,
ActUserID: opts.Doer.ID,
ActUserName: opts.Doer.Name,
ActEmail: opts.Doer.Email,
Content: fmt.Sprintf("%d|%s", opts.Issue.Index, strings.Split(opts.Content, "\n")[0]),
RepoID: opts.Repo.ID,
RepoUserName: opts.Repo.Owner.Name,
@@ -233,10 +278,12 @@ 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
return comment, comment.loadAttributes(e)
}
func createStatusComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue) (*Comment, error) {
@@ -329,15 +376,64 @@ func GetCommentByID(id int64) (*Comment, error) {
if err != nil {
return nil, err
} else if !has {
return nil, ErrCommentNotExist{id}
return nil, ErrCommentNotExist{id, 0}
}
return c, nil
return c, c.LoadAttributes()
}
// GetCommentsByIssueID returns all comments of issue by given ID.
func GetCommentsByIssueID(issueID int64) ([]*Comment, error) {
// FIXME: use CommentList to improve performance.
func loadCommentsAttributes(e Engine, comments []*Comment) (err error) {
for i := range comments {
if err = comments[i].loadAttributes(e); err != nil {
return fmt.Errorf("loadAttributes [%d]: %v", comments[i].ID, err)
}
}
return nil
}
func getCommentsByIssueIDSince(e Engine, issueID, since int64) ([]*Comment, error) {
comments := make([]*Comment, 0, 10)
return comments, x.Where("issue_id=?", issueID).Asc("created_unix").Find(&comments)
sess := e.Where("issue_id = ?", issueID).Asc("created_unix")
if since > 0 {
sess.And("updated_unix >= ?", since)
}
if err := sess.Find(&comments); err != nil {
return nil, err
}
return comments, loadCommentsAttributes(e, 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)
}
if err := sess.Find(&comments); err != nil {
return nil, err
}
return comments, loadCommentsAttributes(e, comments)
}
func getCommentsByIssueID(e Engine, issueID int64) ([]*Comment, error) {
return getCommentsByIssueIDSince(e, issueID, -1)
}
// GetCommentsByIssueID returns all comments of an issue.
func GetCommentsByIssueID(issueID int64) ([]*Comment, error) {
return getCommentsByIssueID(x, issueID)
}
// 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.
@@ -345,3 +441,32 @@ func UpdateComment(c *Comment) error {
_, err := x.Id(c.ID).AllCols().Update(c)
return err
}
// DeleteCommentByID deletes the comment by given ID.
func DeleteCommentByID(id int64) error {
comment, err := GetCommentByID(id)
if err != nil {
if IsErrCommentNotExist(err) {
return nil
}
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Id(comment.ID).Delete(new(Comment)); err != nil {
return err
}
if comment.Type == COMMENT_TYPE_COMMENT {
if _, err = sess.Exec("UPDATE `issue` SET num_comments = num_comments - 1 WHERE id = ?", comment.IssueID); err != nil {
return err
}
}
return sess.Commit()
}

View File

@@ -387,7 +387,7 @@ func IsErrReleaseAlreadyExist(err error) bool {
}
func (err ErrReleaseAlreadyExist) Error() string {
return fmt.Sprintf("Release tag already exist [tag_name: %s]", err.TagName)
return fmt.Sprintf("release tag already exist [tag_name: %s]", err.TagName)
}
type ErrReleaseNotExist struct {
@@ -401,7 +401,33 @@ func IsErrReleaseNotExist(err error) bool {
}
func (err ErrReleaseNotExist) Error() string {
return fmt.Sprintf("Release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName)
return fmt.Sprintf("release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName)
}
type ErrInvalidTagName struct {
TagName string
}
func IsErrInvalidTagName(err error) bool {
_, ok := err.(ErrInvalidTagName)
return ok
}
func (err ErrInvalidTagName) Error() string {
return fmt.Sprintf("release tag name is not valid [tag_name: %s]", err.TagName)
}
type ErrRepoFileAlreadyExist struct {
FileName string
}
func IsErrRepoFileAlreadyExist(err error) bool {
_, ok := err.(ErrRepoFileAlreadyExist)
return ok
}
func (err ErrRepoFileAlreadyExist) Error() string {
return fmt.Sprintf("repository file already exists [file_name: %s]", err.FileName)
}
// __________ .__
@@ -421,7 +447,7 @@ func IsErrBranchNotExist(err error) bool {
}
func (err ErrBranchNotExist) Error() string {
return fmt.Sprintf("Branch does not exist [name: %s]", err.Name)
return fmt.Sprintf("branch does not exist [name: %s]", err.Name)
}
// __ __ ___. .__ __
@@ -500,7 +526,8 @@ func (err ErrPullRequestNotExist) Error() string {
// \/ \/ \/ \/ \/
type ErrCommentNotExist struct {
ID int64
ID int64
IssueID int64
}
func IsErrCommentNotExist(err error) bool {
@@ -509,7 +536,7 @@ func IsErrCommentNotExist(err error) bool {
}
func (err ErrCommentNotExist) Error() string {
return fmt.Sprintf("comment does not exist [id: %d]", err.ID)
return fmt.Sprintf("comment does not exist [id: %d, issue_id: %d]", err.ID, err.IssueID)
}
// .____ ___. .__
@@ -520,7 +547,8 @@ func (err ErrCommentNotExist) Error() string {
// \/ \/ \/ \/
type ErrLabelNotExist struct {
ID int64
LabelID int64
RepoID int64
}
func IsErrLabelNotExist(err error) bool {
@@ -529,7 +557,7 @@ func IsErrLabelNotExist(err error) bool {
}
func (err ErrLabelNotExist) Error() string {
return fmt.Sprintf("label does not exist [id: %d]", err.ID)
return fmt.Sprintf("label does not exist [label_id: %d, repo_id: %d]", err.LabelID, err.RepoID)
}
// _____ .__.__ __
@@ -574,24 +602,50 @@ func (err ErrAttachmentNotExist) Error() string {
return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
}
// _____ __ .__ __ .__ __ .__
// / _ \ __ ___/ |_| |__ ____ _____/ |_|__| ____ _____ _/ |_|__| ____ ____
// / /_\ \| | \ __\ | \_/ __ \ / \ __\ |/ ___\\__ \\ __\ |/ _ \ / \
// / | \ | /| | | Y \ ___/| | \ | | \ \___ / __ \| | | ( <_> ) | \
// \____|__ /____/ |__| |___| /\___ >___| /__| |__|\___ >____ /__| |__|\____/|___| /
// \/ \/ \/ \/ \/ \/ \/
// .____ .__ _________
// | | ____ ____ |__| ____ / _____/ ____ __ _________ ____ ____
// | | / _ \ / ___\| |/ \ \_____ \ / _ \| | \_ __ \_/ ___\/ __ \
// | |__( <_> ) /_/ > | | \ / ( <_> ) | /| | \/\ \__\ ___/
// |_______ \____/\___ /|__|___| / /_______ /\____/|____/ |__| \___ >___ >
// \/ /_____/ \/ \/ \/ \/
type ErrAuthenticationNotExist struct {
type ErrLoginSourceNotExist struct {
ID int64
}
func IsErrAuthenticationNotExist(err error) bool {
_, ok := err.(ErrAuthenticationNotExist)
func IsErrLoginSourceNotExist(err error) bool {
_, ok := err.(ErrLoginSourceNotExist)
return ok
}
func (err ErrAuthenticationNotExist) Error() string {
return fmt.Sprintf("authentication does not exist [id: %d]", err.ID)
func (err ErrLoginSourceNotExist) Error() string {
return fmt.Sprintf("login source does not exist [id: %d]", err.ID)
}
type ErrLoginSourceAlreadyExist struct {
Name string
}
func IsErrLoginSourceAlreadyExist(err error) bool {
_, ok := err.(ErrLoginSourceAlreadyExist)
return ok
}
func (err ErrLoginSourceAlreadyExist) Error() string {
return fmt.Sprintf("login source already exists [name: %s]", err.Name)
}
type ErrLoginSourceInUse struct {
ID int64
}
func IsErrLoginSourceInUse(err error) bool {
_, ok := err.(ErrLoginSourceInUse)
return ok
}
func (err ErrLoginSourceInUse) Error() string {
return fmt.Sprintf("login source is still used by some users [id: %d]", err.ID)
}
// ___________
@@ -614,3 +668,25 @@ func IsErrTeamAlreadyExist(err error) bool {
func (err ErrTeamAlreadyExist) Error() string {
return fmt.Sprintf("team already exists [org_id: %d, name: %s]", err.OrgID, err.Name)
}
// ____ ___ .__ .___
// | | \______ | | _________ __| _/
// | | /\____ \| | / _ \__ \ / __ |
// | | / | |_> > |_( <_> ) __ \_/ /_/ |
// |______/ | __/|____/\____(____ /\____ |
// |__| \/ \/
//
type ErrUploadNotExist struct {
ID int64
UUID string
}
func IsErrUploadNotExist(err error) bool {
_, ok := err.(ErrAttachmentNotExist)
return ok
}
func (err ErrUploadNotExist) Error() string {
return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
}

View File

@@ -20,12 +20,13 @@ import (
"github.com/sergi/go-diff/diffmatchpatch"
"golang.org/x/net/html/charset"
"golang.org/x/text/transform"
log "gopkg.in/clog.v1"
"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"
)
@@ -70,17 +71,27 @@ var (
)
func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML {
var buf bytes.Buffer
buf := bytes.NewBuffer(nil)
// Reproduce signs which are cutted for inline diff before.
switch lineType {
case DIFF_LINE_ADD:
buf.WriteByte('+')
case DIFF_LINE_DEL:
buf.WriteByte('-')
}
for i := range diffs {
if diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DIFF_LINE_ADD {
switch {
case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DIFF_LINE_ADD:
buf.Write(addedCodePrefix)
buf.WriteString(html.EscapeString(diffs[i].Text))
buf.Write(codeTagSuffix)
} else if diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DIFF_LINE_DEL {
case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DIFF_LINE_DEL:
buf.Write(removedCodePrefix)
buf.WriteString(html.EscapeString(diffs[i].Text))
buf.Write(codeTagSuffix)
} else if diffs[i].Type == diffmatchpatch.DiffEqual {
case diffs[i].Type == diffmatchpatch.DiffEqual:
buf.WriteString(html.EscapeString(diffs[i].Text))
}
}
@@ -90,62 +101,86 @@ func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTM
// get an specific line by type (add or del) and file line number
func (diffSection *DiffSection) GetLine(lineType DiffLineType, idx int) *DiffLine {
difference := 0
var (
difference = 0
addCount = 0
delCount = 0
matchDiffLine *DiffLine
)
LOOP:
for _, diffLine := range diffSection.Lines {
if diffLine.Type == DIFF_LINE_PLAIN {
// get the difference of line numbers between ADD and DEL versions
switch diffLine.Type {
case DIFF_LINE_ADD:
addCount++
case DIFF_LINE_DEL:
delCount++
default:
if matchDiffLine != nil {
break LOOP
}
difference = diffLine.RightIdx - diffLine.LeftIdx
continue
addCount = 0
delCount = 0
}
if lineType == DIFF_LINE_DEL {
switch lineType {
case DIFF_LINE_DEL:
if diffLine.RightIdx == 0 && diffLine.LeftIdx == idx-difference {
return diffLine
matchDiffLine = diffLine
}
} else if lineType == DIFF_LINE_ADD {
case DIFF_LINE_ADD:
if diffLine.LeftIdx == 0 && diffLine.RightIdx == idx+difference {
return diffLine
matchDiffLine = diffLine
}
}
}
if addCount == delCount {
return matchDiffLine
}
return nil
}
var diffMatchPatch = diffmatchpatch.New()
func init() {
diffMatchPatch.DiffEditCost = 100
}
// computes inline diff for the given line
func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) template.HTML {
var compareDiffLine *DiffLine
var diff1, diff2 string
getDefaultReturn := func() template.HTML {
if setting.Git.DisableDiffHighlight {
return template.HTML(html.EscapeString(diffLine.Content[1:]))
}
// just compute diff for adds and removes
if diffLine.Type != DIFF_LINE_ADD && diffLine.Type != DIFF_LINE_DEL {
return getDefaultReturn()
}
var (
compareDiffLine *DiffLine
diff1 string
diff2 string
)
// try to find equivalent diff line. ignore, otherwise
if diffLine.Type == DIFF_LINE_ADD {
switch diffLine.Type {
case DIFF_LINE_ADD:
compareDiffLine = diffSection.GetLine(DIFF_LINE_DEL, diffLine.RightIdx)
if compareDiffLine == nil {
return getDefaultReturn()
return template.HTML(html.EscapeString(diffLine.Content))
}
diff1 = compareDiffLine.Content
diff2 = diffLine.Content
} else {
case DIFF_LINE_DEL:
compareDiffLine = diffSection.GetLine(DIFF_LINE_ADD, diffLine.LeftIdx)
if compareDiffLine == nil {
return getDefaultReturn()
return template.HTML(html.EscapeString(diffLine.Content))
}
diff1 = diffLine.Content
diff2 = compareDiffLine.Content
default:
return template.HTML(html.EscapeString(diffLine.Content))
}
dmp := diffmatchpatch.New()
diffRecord := dmp.DiffMain(diff1[1:], diff2[1:], true)
diffRecord = dmp.DiffCleanupSemantic(diffRecord)
diffRecord := diffMatchPatch.DiffMain(diff1[1:], diff2[1:], true)
diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord)
return diffToHTML(diffRecord, diffLine.Type)
}
@@ -160,6 +195,7 @@ type DiffFile struct {
IsDeleted bool
IsBin bool
IsRenamed bool
IsSubmodule bool
Sections []*DiffSection
IsIncomplete bool
}
@@ -184,6 +220,7 @@ func (diff *Diff) NumFiles() int {
const DIFF_HEAD = "diff --git "
// TODO: move this function to gogits/git-module
func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*Diff, error) {
var (
diff = &Diff{Files: make([]*DiffFile, 0)}
@@ -306,7 +343,7 @@ func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*
}
curFileLinesCount = 0
// Check file diff type.
// Check file diff type and is submodule.
for {
line, err := input.ReadString('\n')
if err != nil {
@@ -333,6 +370,9 @@ func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*
curFile.Name = b
}
if curFile.Type > 0 {
if strings.HasSuffix(line, " 160000\n") {
curFile.IsSubmodule = true
}
break
}
}
@@ -367,13 +407,13 @@ func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*
return diff, nil
}
func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
repo, err := git.OpenRepository(repoPath)
func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
return nil, err
}
commit, err := repo.GetCommit(afterCommitID)
commit, err := gitRepo.GetCommit(afterCommitID)
if err != nil {
return nil, err
}
@@ -403,7 +443,7 @@ func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxLine
return nil, fmt.Errorf("Start: %v", err)
}
pid := process.Add(fmt.Sprintf("GetDiffRange (%s)", repoPath), cmd)
pid := process.Add(fmt.Sprintf("GetDiffRange [repo_path: %s]", repoPath), cmd)
defer process.Remove(pid)
diff, err := ParsePatch(maxLines, maxLineCharacteres, maxFiles, stdout)
@@ -418,6 +458,59 @@ func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxLine
return diff, nil
}
func GetDiffCommit(repoPath, commitId string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
return GetDiffRange(repoPath, "", commitId, maxLines, maxLineCharacteres, maxFiles)
type RawDiffType string
const (
RAW_DIFF_NORMAL RawDiffType = "diff"
RAW_DIFF_PATCH RawDiffType = "patch"
)
// GetRawDiff dumps diff results of repository in given commit ID to io.Writer.
// TODO: move this function to gogits/git-module
func GetRawDiff(repoPath, commitID string, diffType RawDiffType, writer io.Writer) error {
repo, err := git.OpenRepository(repoPath)
if err != nil {
return fmt.Errorf("OpenRepository: %v", err)
}
commit, err := repo.GetCommit(commitID)
if err != nil {
return fmt.Errorf("GetCommit: %v", err)
}
var cmd *exec.Cmd
switch diffType {
case RAW_DIFF_NORMAL:
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:
if commit.ParentCount() == 0 {
cmd = exec.Command("git", "format-patch", "--no-signature", "--stdout", "--root", commitID)
} else {
c, _ := commit.Parent(0)
query := fmt.Sprintf("%s...%s", commitID, c.ID.String())
cmd = exec.Command("git", "format-patch", "--no-signature", "--stdout", query)
}
default:
return fmt.Errorf("invalid diffType: %s", diffType)
}
stderr := new(bytes.Buffer)
cmd.Dir = repoPath
cmd.Stdout = writer
cmd.Stderr = stderr
if err = cmd.Run(); err != nil {
return fmt.Errorf("Run: %v - %s", err, stderr)
}
return nil
}
func GetDiffCommit(repoPath, commitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
return GetDiffRange(repoPath, "", commitID, maxLines, maxLineCharacteres, maxFiles)
}

View File

@@ -19,52 +19,17 @@ func assertLineEqual(t *testing.T, d1 *DiffLine, d2 *DiffLine) {
}
func TestDiffToHTML(t *testing.T) {
assertEqual(t, "foo <span class=\"added-code\">bar</span> biz", diffToHTML([]dmp.Diff{
assertEqual(t, "+foo <span class=\"added-code\">bar</span> biz", diffToHTML([]dmp.Diff{
dmp.Diff{dmp.DiffEqual, "foo "},
dmp.Diff{dmp.DiffInsert, "bar"},
dmp.Diff{dmp.DiffDelete, " baz"},
dmp.Diff{dmp.DiffEqual, " biz"},
}, DIFF_LINE_ADD))
assertEqual(t, "foo <span class=\"removed-code\">bar</span> biz", diffToHTML([]dmp.Diff{
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))
}
// test if GetLine is return the correct lines
func TestGetLine(t *testing.T) {
ds := DiffSection{Lines: []*DiffLine{
&DiffLine{LeftIdx: 28, RightIdx: 28, Type: DIFF_LINE_PLAIN},
&DiffLine{LeftIdx: 29, RightIdx: 29, Type: DIFF_LINE_PLAIN},
&DiffLine{LeftIdx: 30, RightIdx: 30, Type: DIFF_LINE_PLAIN},
&DiffLine{LeftIdx: 31, RightIdx: 0, Type: DIFF_LINE_DEL},
&DiffLine{LeftIdx: 0, RightIdx: 31, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 0, RightIdx: 32, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 32, RightIdx: 33, Type: DIFF_LINE_PLAIN},
&DiffLine{LeftIdx: 33, RightIdx: 0, Type: DIFF_LINE_DEL},
&DiffLine{LeftIdx: 34, RightIdx: 0, Type: DIFF_LINE_DEL},
&DiffLine{LeftIdx: 35, RightIdx: 0, Type: DIFF_LINE_DEL},
&DiffLine{LeftIdx: 36, RightIdx: 0, Type: DIFF_LINE_DEL},
&DiffLine{LeftIdx: 0, RightIdx: 34, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 0, RightIdx: 35, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 0, RightIdx: 36, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 0, RightIdx: 37, Type: DIFF_LINE_ADD},
&DiffLine{LeftIdx: 37, RightIdx: 38, Type: DIFF_LINE_PLAIN},
&DiffLine{LeftIdx: 38, RightIdx: 39, Type: DIFF_LINE_PLAIN},
}}
assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 31), ds.Lines[4])
assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 31), ds.Lines[3])
assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 33), ds.Lines[11])
assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 34), ds.Lines[12])
assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 35), ds.Lines[13])
assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 36), ds.Lines[14])
assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 34), ds.Lines[7])
assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 35), ds.Lines[8])
assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 36), ds.Lines[9])
assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 37), ds.Lines[10])
}

File diff suppressed because it is too large Load Diff

View File

@@ -7,12 +7,51 @@ package models
import (
"fmt"
"html/template"
"regexp"
"strconv"
"strings"
"github.com/go-xorm/xorm"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/base"
)
var labelColorPattern = regexp.MustCompile("#([a-fA-F0-9]{6})")
// GetLabelTemplateFile loads the label template file by given name,
// then parses and returns a list of name-color pairs.
func GetLabelTemplateFile(name string) ([][2]string, error) {
data, err := getRepoInitFile("label", name)
if err != nil {
return nil, fmt.Errorf("getRepoInitFile: %v", err)
}
lines := strings.Split(string(data), "\n")
list := make([][2]string, 0, len(lines))
for i := 0; i < len(lines); i++ {
line := strings.TrimSpace(lines[i])
if len(line) == 0 {
continue
}
fields := strings.SplitN(line, " ", 2)
if len(fields) != 2 {
return nil, fmt.Errorf("line is malformed: %s", line)
}
if !labelColorPattern.MatchString(fields[0]) {
return nil, fmt.Errorf("bad HTML color code in line: %s", line)
}
fields[1] = strings.TrimSpace(fields[1])
list = append(list, [2]string{fields[1], fields[0]})
}
return list, nil
}
// Label represents a label of repository for issues.
type Label struct {
ID int64 `xorm:"pk autoincr"`
@@ -25,9 +64,17 @@ type Label struct {
IsChecked bool `xorm:"-"`
}
func (label *Label) APIFormat() *api.Label {
return &api.Label{
ID: label.ID,
Name: label.Name,
Color: label.Color,
}
}
// CalOpenIssues calculates the open issues of label.
func (m *Label) CalOpenIssues() {
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
func (label *Label) CalOpenIssues() {
label.NumOpenIssues = label.NumIssues - label.NumClosedIssues
}
// ForegroundColor calculates the text color for labels based
@@ -40,7 +87,7 @@ func (l *Label) ForegroundColor() template.CSS {
b := float32(0xFF & color)
luminance := (0.2126*r + 0.7152*g + 0.0722*b) / 255
if luminance < 0.5 {
if luminance < 0.66 {
return template.CSS("#fff")
}
}
@@ -50,54 +97,71 @@ func (l *Label) ForegroundColor() template.CSS {
return template.CSS("#000")
}
// NewLabel creates new label of repository.
func NewLabel(l *Label) error {
_, err := x.Insert(l)
// NewLabels creates new label(s) for a repository.
func NewLabels(labels ...*Label) error {
_, err := x.Insert(labels)
return err
}
func getLabelByID(e Engine, id int64) (*Label, error) {
if id <= 0 {
return nil, ErrLabelNotExist{id}
// getLabelOfRepoByID 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.
func getLabelOfRepoByID(e Engine, repoID, labelID int64) (*Label, error) {
if labelID <= 0 {
return nil, ErrLabelNotExist{labelID, repoID}
}
l := &Label{ID: id}
l := &Label{
ID: labelID,
RepoID: repoID,
}
has, err := x.Get(l)
if err != nil {
return nil, err
} else if !has {
return nil, ErrLabelNotExist{l.ID}
return nil, ErrLabelNotExist{l.ID, l.RepoID}
}
return l, nil
}
// GetLabelByID returns a label by given ID.
func GetLabelByID(id int64) (*Label, error) {
return getLabelByID(x, id)
return getLabelOfRepoByID(x, 0, id)
}
// GetLabelOfRepoByID returns a label by ID in given repository.
func GetLabelOfRepoByID(repoID, labelID int64) (*Label, error) {
return getLabelOfRepoByID(x, repoID, labelID)
}
// GetLabelsInRepoByIDs returns a list of labels by IDs in given repository,
// 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)
}
// 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).Find(&labels)
return labels, x.Where("repo_id = ?", repoID).Asc("name").Find(&labels)
}
func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) {
issueLabels, err := getIssueLabels(e, issueID)
if err != nil {
return nil, fmt.Errorf("getIssueLabels: %v", err)
} else if len(issueLabels) == 0 {
return []*Label{}, nil
}
var label *Label
labels := make([]*Label, 0, len(issueLabels))
for idx := range issueLabels {
label, err = getLabelByID(e, issueLabels[idx].LabelID)
if err != nil && !IsErrLabelNotExist(err) {
return nil, fmt.Errorf("getLabelByID: %v", err)
}
labels = append(labels, label)
labelIDs := make([]int64, len(issueLabels))
for i := range issueLabels {
labelIDs[i] = issueLabels[i].LabelID
}
return labels, nil
labels := make([]*Label, 0, len(labelIDs))
return labels, e.Where("id > 0").In("id", base.Int64sToStrings(labelIDs)).Asc("name").Find(&labels)
}
// GetLabelsByIssueID returns all labels that belong to given issue by ID.
@@ -117,7 +181,7 @@ func UpdateLabel(l *Label) error {
// DeleteLabel delete a label of given repository.
func DeleteLabel(repoID, labelID int64) error {
l, err := GetLabelByID(labelID)
_, err := GetLabelOfRepoByID(repoID, labelID)
if err != nil {
if IsErrLabelNotExist(err) {
return nil
@@ -131,11 +195,12 @@ func DeleteLabel(repoID, labelID int64) error {
return err
}
if _, err = x.Where("label_id=?", labelID).Delete(new(IssueLabel)); err != nil {
if _, err = sess.Id(labelID).Delete(new(Label)); err != nil {
return err
} else if _, err = sess.Delete(l); err != nil {
} else if _, err = sess.Where("label_id = ?", labelID).Delete(new(IssueLabel)); err != nil {
return err
}
return sess.Commit()
}
@@ -154,7 +219,7 @@ type IssueLabel struct {
}
func hasIssueLabel(e Engine, issueID, labelID int64) bool {
has, _ := e.Where("issue_id=? AND label_id=?", issueID, labelID).Get(new(IssueLabel))
has, _ := e.Where("issue_id = ? AND label_id = ?", issueID, labelID).Get(new(IssueLabel))
return has
}
@@ -180,6 +245,10 @@ func newIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
// NewIssueLabel creates a new issue-label relation.
func NewIssueLabel(issue *Issue, label *Label) (err error) {
if HasIssueLabel(issue.ID, label.ID) {
return nil
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
@@ -193,6 +262,35 @@ func NewIssueLabel(issue *Issue, label *Label) (err error) {
return sess.Commit()
}
func newIssueLabels(e *xorm.Session, issue *Issue, labels []*Label) (err error) {
for i := range labels {
if hasIssueLabel(e, issue.ID, labels[i].ID) {
continue
}
if err = newIssueLabel(e, issue, labels[i]); err != nil {
return fmt.Errorf("newIssueLabel: %v", err)
}
}
return nil
}
// NewIssueLabels creates a list of issue-label relations.
func NewIssueLabels(issue *Issue, labels []*Label) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if err = newIssueLabels(sess, issue, labels); err != nil {
return err
}
return sess.Commit()
}
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)

View File

@@ -8,14 +8,86 @@ import (
"fmt"
"github.com/Unknwon/com"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/mailer"
"github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting"
)
func (issue *Issue) MailSubject() string {
return fmt.Sprintf("[%s] %s (#%d)", issue.Repo.Name, issue.Name, issue.Index)
return fmt.Sprintf("[%s] %s (#%d)", issue.Repo.Name, issue.Title, issue.Index)
}
// mailerUser is a wrapper for satisfying mailer.User interface.
type mailerUser struct {
user *User
}
func (this mailerUser) ID() int64 {
return this.user.ID
}
func (this mailerUser) DisplayName() string {
return this.user.DisplayName()
}
func (this mailerUser) Email() string {
return this.user.Email
}
func (this mailerUser) GenerateActivateCode() string {
return this.user.GenerateActivateCode()
}
func (this mailerUser) GenerateEmailActivateCode(email string) string {
return this.user.GenerateEmailActivateCode(email)
}
func NewMailerUser(u *User) mailer.User {
return mailerUser{u}
}
// mailerRepo is a wrapper for satisfying mailer.Repository interface.
type mailerRepo struct {
repo *Repository
}
func (this mailerRepo) FullName() string {
return this.repo.FullName()
}
func (this mailerRepo) HTMLURL() string {
return this.repo.HTMLURL()
}
func (this mailerRepo) ComposeMetas() map[string]string {
return this.repo.ComposeMetas()
}
func NewMailerRepo(repo *Repository) mailer.Repository {
return mailerRepo{repo}
}
// mailerIssue is a wrapper for satisfying mailer.Issue interface.
type mailerIssue struct {
issue *Issue
}
func (this mailerIssue) MailSubject() string {
return this.issue.MailSubject()
}
func (this mailerIssue) Content() string {
return this.issue.Content
}
func (this mailerIssue) HTMLURL() string {
return this.issue.HTMLURL()
}
func NewMailerIssue(issue *Issue) mailer.Issue {
return mailerIssue{issue}
}
// mailIssueCommentToParticipants can be used for both new issue creation and comment.
@@ -33,7 +105,7 @@ func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string)
tos := make([]string, 0, len(watchers)) // List of email addresses.
names := make([]string, 0, len(watchers))
for i := range watchers {
if watchers[i].UserID == doer.Id {
if watchers[i].UserID == doer.ID {
continue
}
@@ -48,7 +120,7 @@ func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string)
tos = append(tos, to.Email)
names = append(names, to.Name)
}
SendIssueCommentMail(issue, doer, tos)
mailer.SendIssueCommentMail(NewMailerIssue(issue), NewMailerRepo(issue.Repo), NewMailerUser(doer), tos)
// Mail mentioned people and exclude watchers.
names = append(names, doer.Name)
@@ -60,7 +132,7 @@ func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string)
tos = append(tos, mentions[i])
}
SendIssueMentionMail(issue, doer, GetUserEmailsByNames(tos))
mailer.SendIssueMentionMail(NewMailerIssue(issue), NewMailerRepo(issue.Repo), NewMailerUser(doer), GetUserEmailsByNames(tos))
return nil
}
@@ -69,7 +141,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

@@ -18,20 +18,15 @@ import (
"github.com/go-macaron/binding"
"github.com/go-xorm/core"
"github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/auth/ldap"
"github.com/gogits/gogs/modules/auth/pam"
"github.com/gogits/gogs/modules/log"
)
var (
ErrAuthenticationAlreadyExist = errors.New("Authentication already exist")
ErrAuthenticationUserUsed = errors.New("Authentication has been used by some users")
)
type LoginType int
// Note: new type must be added at the end of list to maintain compatibility.
// Note: new type must append to the end of list to maintain compatibility.
const (
LOGIN_NOTYPE LoginType = iota
LOGIN_PLAIN // 1
@@ -106,6 +101,7 @@ func (cfg *PAMConfig) ToDB() ([]byte, error) {
return json.Marshal(cfg)
}
// LoginSource represents an external way for authorizing users.
type LoginSource struct {
ID int64 `xorm:"pk autoincr"`
Type LoginType
@@ -120,12 +116,12 @@ type LoginSource struct {
}
func (s *LoginSource) BeforeInsert() {
s.CreatedUnix = time.Now().UTC().Unix()
s.CreatedUnix = time.Now().Unix()
s.UpdatedUnix = s.CreatedUnix
}
func (s *LoginSource) BeforeUpdate() {
s.UpdatedUnix = time.Now().UTC().Unix()
s.UpdatedUnix = time.Now().Unix()
}
// Cell2Int64 converts a xorm.Cell type to int64,
@@ -223,15 +219,15 @@ func (source *LoginSource) SMTP() *SMTPConfig {
func (source *LoginSource) PAM() *PAMConfig {
return source.Cfg.(*PAMConfig)
}
func CreateLoginSource(source *LoginSource) error {
has, err := x.Get(&LoginSource{Name: source.Name})
if err != nil {
return err
} else if has {
return ErrLoginSourceAlreadyExist{source.Name}
}
// CountLoginSources returns number of login sources.
func CountLoginSources() int64 {
count, _ := x.Count(new(LoginSource))
return count
}
func CreateSource(source *LoginSource) error {
_, err := x.Insert(source)
_, err = x.Insert(source)
return err
}
@@ -247,7 +243,7 @@ func GetLoginSourceByID(id int64) (*LoginSource, error) {
if err != nil {
return nil, err
} else if !has {
return nil, ErrAuthenticationNotExist{id}
return nil, ErrLoginSourceNotExist{id}
}
return source, nil
}
@@ -262,12 +258,18 @@ func DeleteSource(source *LoginSource) error {
if err != nil {
return err
} else if count > 0 {
return ErrAuthenticationUserUsed
return ErrLoginSourceInUse{source.ID}
}
_, err = x.Id(source.ID).Delete(new(LoginSource))
return err
}
// CountLoginSources returns number of login sources.
func CountLoginSources() int64 {
count, _ := x.Count(new(LoginSource))
return count
}
// .____ ________ _____ __________
// | | \______ \ / _ \\______ \
// | | | | \ / /_\ \| ___/
@@ -275,49 +277,6 @@ func DeleteSource(source *LoginSource) error {
// |_______ \/_______ /\____|__ /____|
// \/ \/ \/
// LoginUserLDAPSource queries if loginName/passwd can login against the LDAP directory pool,
// and create a local user if success when enabled.
// It returns the same LoginUserPlain semantic.
func LoginUserLDAPSource(u *User, loginName, passwd string, source *LoginSource, autoRegister bool) (*User, error) {
cfg := source.Cfg.(*LDAPConfig)
directBind := (source.Type == LOGIN_DLDAP)
username, fn, sn, mail, isAdmin, logged := cfg.SearchEntry(loginName, passwd, directBind)
if !logged {
// User not in LDAP, do nothing
return nil, ErrUserNotExist{0, loginName}
}
if !autoRegister {
return u, nil
}
// Fallback.
if len(username) == 0 {
username = loginName
}
// Validate username make sure it satisfies requirement.
if !binding.AlphaDashDotPattern.MatchString(username) {
return nil, fmt.Errorf("Invalid pattern for attribute 'username' [%s]: must be valid alpha or numeric or dash(-_) or dot characters", username)
}
if len(mail) == 0 {
mail = fmt.Sprintf("%s@localhost", username)
}
u = &User{
LowerName: strings.ToLower(username),
Name: username,
FullName: composeFullName(fn, sn, username),
LoginType: source.Type,
LoginSource: source.ID,
LoginName: loginName,
Email: mail,
IsAdmin: isAdmin,
IsActive: true,
}
return u, CreateUser(u)
}
func composeFullName(firstname, surname, username string) string {
switch {
case len(firstname) == 0 && len(surname) == 0:
@@ -331,6 +290,46 @@ 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, password string, source *LoginSource, autoRegister bool) (*User, error) {
username, fn, sn, mail, isAdmin, succeed := source.Cfg.(*LDAPConfig).SearchEntry(login, password, source.Type == LOGIN_DLDAP)
if !succeed {
// User not in LDAP, do nothing
return nil, ErrUserNotExist{0, login}
}
if !autoRegister {
return user, nil
}
// Fallback.
if len(username) == 0 {
username = login
}
// Validate username make sure it satisfies requirement.
if binding.AlphaDashDotPattern.MatchString(username) {
return nil, fmt.Errorf("Invalid pattern for attribute 'username' [%s]: must be valid alpha or numeric or dash(-_) or dot characters", username)
}
if len(mail) == 0 {
mail = fmt.Sprintf("%s@localhost", username)
}
user = &User{
LowerName: strings.ToLower(username),
Name: username,
FullName: composeFullName(fn, sn, username),
Email: mail,
LoginType: source.Type,
LoginSource: source.ID,
LoginName: login,
IsActive: true,
IsAdmin: isAdmin,
}
return user, CreateUser(user)
}
// _________ __________________________
// / _____/ / \__ ___/\______ \
// \_____ \ / \ / \| | | ___/
@@ -338,25 +337,21 @@ func composeFullName(firstname, surname, username string) string {
// /_______ /\____|__ /____| |____|
// \/ \/
type loginAuth struct {
type smtpLoginAuth struct {
username, password string
}
func LoginAuth(username, password string) smtp.Auth {
return &loginAuth{username, password}
func (auth *smtpLoginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
return "LOGIN", []byte(auth.username), nil
}
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
return "LOGIN", []byte(a.username), nil
}
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
func (auth *smtpLoginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
if more {
switch string(fromServer) {
case "Username:":
return []byte(a.username), nil
return []byte(auth.username), nil
case "Password:":
return []byte(a.password), nil
return []byte(auth.password), nil
}
}
return nil, nil
@@ -402,25 +397,24 @@ func SMTPAuth(a smtp.Auth, cfg *SMTPConfig) error {
return ErrUnsupportedLoginType
}
// Query if name/passwd can login against the LDAP directory pool
// Create a local user if success
// Return the same LoginUserPlain semantic
func LoginUserSMTPSource(u *User, name, passwd string, sourceID int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {
// LoginViaSMTP queries if login/password is valid against the SMTP,
// and create a local user if success when enabled.
func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {
// Verify allowed domains.
if len(cfg.AllowedDomains) > 0 {
idx := strings.Index(name, "@")
idx := strings.Index(login, "@")
if idx == -1 {
return nil, ErrUserNotExist{0, name}
} else if !com.IsSliceContainsStr(strings.Split(cfg.AllowedDomains, ","), name[idx+1:]) {
return nil, ErrUserNotExist{0, name}
return nil, ErrUserNotExist{0, login}
} else if !com.IsSliceContainsStr(strings.Split(cfg.AllowedDomains, ","), login[idx+1:]) {
return nil, ErrUserNotExist{0, login}
}
}
var auth smtp.Auth
if cfg.Auth == SMTP_PLAIN {
auth = smtp.PlainAuth("", name, passwd, cfg.Host)
auth = smtp.PlainAuth("", login, password, cfg.Host)
} else if cfg.Auth == SMTP_LOGIN {
auth = LoginAuth(name, passwd)
auth = &smtpLoginAuth{login, password}
} else {
return nil, errors.New("Unsupported SMTP auth type")
}
@@ -431,33 +425,32 @@ func LoginUserSMTPSource(u *User, name, passwd string, sourceID int64, cfg *SMTP
tperr, ok := err.(*textproto.Error)
if (ok && tperr.Code == 535) ||
strings.Contains(err.Error(), "Username and Password not accepted") {
return nil, ErrUserNotExist{0, name}
return nil, ErrUserNotExist{0, login}
}
return nil, err
}
if !autoRegister {
return u, nil
return user, nil
}
var loginName = name
idx := strings.Index(name, "@")
username := login
idx := strings.Index(login, "@")
if idx > -1 {
loginName = name[:idx]
username = login[:idx]
}
// fake a local user creation
u = &User{
LowerName: strings.ToLower(loginName),
Name: strings.ToLower(loginName),
user = &User{
LowerName: strings.ToLower(username),
Name: strings.ToLower(username),
Email: login,
Passwd: password,
LoginType: LOGIN_SMTP,
LoginSource: sourceID,
LoginName: name,
LoginName: login,
IsActive: true,
Passwd: passwd,
Email: name,
}
err := CreateUser(u)
return u, err
return user, CreateUser(user)
}
// __________ _____ _____
@@ -467,101 +460,99 @@ func LoginUserSMTPSource(u *User, name, passwd string, sourceID int64, cfg *SMTP
// |____| \____|__ /\____|__ /
// \/ \/
// Query if name/passwd can login against PAM
// Create a local user if success
// Return the same LoginUserPlain semantic
func LoginUserPAMSource(u *User, name, passwd string, sourceID int64, cfg *PAMConfig, autoRegister bool) (*User, error) {
if err := pam.PAMAuth(cfg.ServiceName, name, passwd); err != nil {
// 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 strings.Contains(err.Error(), "Authentication failure") {
return nil, ErrUserNotExist{0, name}
return nil, ErrUserNotExist{0, login}
}
return nil, err
}
if !autoRegister {
return u, nil
return user, nil
}
// fake a local user creation
u = &User{
LowerName: strings.ToLower(name),
Name: name,
user = &User{
LowerName: strings.ToLower(login),
Name: login,
Email: login,
Passwd: password,
LoginType: LOGIN_PAM,
LoginSource: sourceID,
LoginName: name,
LoginName: login,
IsActive: true,
Passwd: passwd,
Email: name,
}
return u, CreateUser(u)
return user, CreateUser(user)
}
func ExternalUserLogin(u *User, name, passwd string, source *LoginSource, autoRegister bool) (*User, error) {
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:
return LoginUserLDAPSource(u, name, passwd, source, autoRegister)
return LoginViaLDAP(user, login, password, source, autoRegister)
case LOGIN_SMTP:
return LoginUserSMTPSource(u, name, passwd, source.ID, source.Cfg.(*SMTPConfig), autoRegister)
return LoginViaSMTP(user, login, password, source.ID, source.Cfg.(*SMTPConfig), autoRegister)
case LOGIN_PAM:
return LoginUserPAMSource(u, name, passwd, source.ID, source.Cfg.(*PAMConfig), autoRegister)
return LoginViaPAM(user, login, password, source.ID, source.Cfg.(*PAMConfig), autoRegister)
}
return nil, ErrUnsupportedLoginType
}
// UserSignIn validates user name and password.
func UserSignIn(uname, passwd string) (*User, error) {
var u *User
if strings.Contains(uname, "@") {
u = &User{Email: strings.ToLower(uname)}
func UserSignIn(username, password string) (*User, error) {
var user *User
if strings.Contains(username, "@") {
user = &User{Email: strings.ToLower(username)}
} else {
u = &User{LowerName: strings.ToLower(uname)}
user = &User{LowerName: strings.ToLower(username)}
}
userExists, err := x.Get(u)
hasUser, err := x.Get(user)
if err != nil {
return nil, err
}
if userExists {
switch u.LoginType {
if hasUser {
switch user.LoginType {
case LOGIN_NOTYPE, LOGIN_PLAIN:
if u.ValidatePassword(passwd) {
return u, nil
if user.ValidatePassword(password) {
return user, nil
}
return nil, ErrUserNotExist{u.Id, u.Name}
return nil, ErrUserNotExist{user.ID, user.Name}
default:
var source LoginSource
hasSource, err := x.Id(u.LoginSource).Get(&source)
hasSource, err := x.Id(user.LoginSource).Get(&source)
if err != nil {
return nil, err
} else if !hasSource {
return nil, ErrLoginSourceNotExist
return nil, ErrLoginSourceNotExist{user.LoginSource}
}
return ExternalUserLogin(u, u.LoginName, passwd, &source, false)
return ExternalUserLogin(user, user.LoginName, password, &source, false)
}
}
var sources []LoginSource
sources := make([]*LoginSource, 0, 3)
if err = x.UseBool().Find(&sources, &LoginSource{IsActived: true}); err != nil {
return nil, err
}
for _, source := range sources {
u, err := ExternalUserLogin(nil, uname, passwd, &source, true)
authUser, err := ExternalUserLogin(nil, username, password, source, true)
if err == nil {
return u, nil
return authUser, nil
}
log.Warn("Failed to login '%s' via '%s': %v", uname, source.Name, err)
log.Warn("Failed to login '%s' via '%s': %v", username, source.Name, err)
}
return nil, ErrUserNotExist{u.Id, u.Name}
return nil, ErrUserNotExist{user.ID, user.Name}
}

View File

@@ -18,10 +18,10 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
gouuid "github.com/satori/go.uuid"
log "gopkg.in/clog.v1"
"gopkg.in/ini.v1"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
@@ -59,6 +59,7 @@ type Version struct {
// If you want to "retire" a migration, remove it from the top of the list and
// update _MIN_VER_DB 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("generate issue-label from issue", issueToIssueLabel), // V6 -> V7:v0.6.4
@@ -68,6 +69,9 @@ var migrations = []Migration{
NewMigration("generate rands and salt for organizations", generateOrgRandsAndSalt), // V10 -> V11:v0.8.5
NewMigration("convert date to unix timestamp", convertDateToUnix), // V11 -> V12:v0.9.2
NewMigration("convert LDAP UseSSL option to SecurityProtocol", ldapUseSSLToSecurityProtocol), // V12 -> V13:v0.9.37
// v13 -> v14:v0.9.87
NewMigration("set comment updated with created", setCommentUpdatedWithCreated),
}
// Migrate database to current version
@@ -242,7 +246,7 @@ func issueToIssueLabel(x *xorm.Engine) error {
}
if err = sess.Sync2(new(IssueLabel)); err != nil {
return fmt.Errorf("sync2: %v", err)
return fmt.Errorf("Sync2: %v", err)
} else if _, err = sess.Insert(issueLabels); err != nil {
return fmt.Errorf("insert issue-labels: %v", err)
}
@@ -447,8 +451,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
}
@@ -646,17 +654,17 @@ func convertDateToUnix(x *xorm.Engine) (err error) {
if bean.Deadline.IsZero() {
continue
}
fieldSQL += com.ToStr(bean.Deadline.UTC().Unix())
fieldSQL += com.ToStr(bean.Deadline.Unix())
case "created":
fieldSQL += com.ToStr(bean.Created.UTC().Unix())
fieldSQL += com.ToStr(bean.Created.Unix())
case "updated":
fieldSQL += com.ToStr(bean.Updated.UTC().Unix())
fieldSQL += com.ToStr(bean.Updated.Unix())
case "closed_date":
fieldSQL += com.ToStr(bean.ClosedDate.UTC().Unix())
fieldSQL += com.ToStr(bean.ClosedDate.Unix())
case "merged":
fieldSQL += com.ToStr(bean.Merged.UTC().Unix())
fieldSQL += com.ToStr(bean.Merged.Unix())
case "next_update":
fieldSQL += com.ToStr(bean.NextUpdate.UTC().Unix())
fieldSQL += com.ToStr(bean.NextUpdate.Unix())
}
valSQLs = append(valSQLs, fieldSQL)

24
models/migrations/v14.go Normal file
View File

@@ -0,0 +1,24 @@
// Copyright 2016 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 migrations
import (
"fmt"
"github.com/go-xorm/xorm"
)
func setCommentUpdatedWithCreated(x *xorm.Engine) (err error) {
type Comment struct {
UpdatedUnix int64
}
if err = x.Sync2(new(Comment)); err != nil {
return fmt.Errorf("Sync2: %v", err)
} else if _, err = x.Exec("UPDATE comment SET updated_unix = created_unix"); err != nil {
return fmt.Errorf("set update_unix: %v", err)
}
return nil
}

349
models/milestone.go Normal file
View File

@@ -0,0 +1,349 @@
// Copyright 2017 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 models
import (
"time"
"github.com/go-xorm/xorm"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/setting"
)
// Milestone represents a milestone of repository.
type Milestone struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"`
Name string
Content string `xorm:"TEXT"`
RenderedContent string `xorm:"-"`
IsClosed bool
NumIssues int
NumClosedIssues int
NumOpenIssues int `xorm:"-"`
Completeness int // Percentage(1-100).
IsOverDue bool `xorm:"-"`
DeadlineString string `xorm:"-"`
Deadline time.Time `xorm:"-"`
DeadlineUnix int64
ClosedDate time.Time `xorm:"-"`
ClosedDateUnix int64
}
func (m *Milestone) BeforeInsert() {
m.DeadlineUnix = m.Deadline.Unix()
}
func (m *Milestone) BeforeUpdate() {
if m.NumIssues > 0 {
m.Completeness = m.NumClosedIssues * 100 / m.NumIssues
} else {
m.Completeness = 0
}
m.DeadlineUnix = m.Deadline.Unix()
m.ClosedDateUnix = m.ClosedDate.Unix()
}
func (m *Milestone) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "num_closed_issues":
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
case "deadline_unix":
m.Deadline = time.Unix(m.DeadlineUnix, 0).Local()
if m.Deadline.Year() == 9999 {
return
}
m.DeadlineString = m.Deadline.Format("2006-01-02")
if time.Now().Local().After(m.Deadline) {
m.IsOverDue = true
}
case "closed_date_unix":
m.ClosedDate = time.Unix(m.ClosedDateUnix, 0).Local()
}
}
// State returns string representation of milestone status.
func (m *Milestone) State() api.StateType {
if m.IsClosed {
return api.STATE_CLOSED
}
return api.STATE_OPEN
}
func (m *Milestone) ChangeStatus(isClosed bool) error {
return ChangeMilestoneStatus(m, isClosed)
}
func (m *Milestone) APIFormat() *api.Milestone {
apiMilestone := &api.Milestone{
ID: m.ID,
State: m.State(),
Title: m.Name,
Description: m.Content,
OpenIssues: m.NumOpenIssues,
ClosedIssues: m.NumClosedIssues,
}
if m.IsClosed {
apiMilestone.Closed = &m.ClosedDate
}
if m.Deadline.Year() < 9999 {
apiMilestone.Deadline = &m.Deadline
}
return apiMilestone
}
// NewMilestone creates new milestone of repository.
func NewMilestone(m *Milestone) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Insert(m); err != nil {
return err
}
if _, err = sess.Exec("UPDATE `repository` SET num_milestones = num_milestones + 1 WHERE id = ?", m.RepoID); err != nil {
return err
}
return sess.Commit()
}
func getMilestoneByRepoID(e Engine, repoID, id int64) (*Milestone, error) {
m := &Milestone{
ID: id,
RepoID: repoID,
}
has, err := e.Get(m)
if err != nil {
return nil, err
} else if !has {
return nil, ErrMilestoneNotExist{id, repoID}
}
return m, nil
}
// GetWebhookByRepoID returns the milestone in a repository.
func GetMilestoneByRepoID(repoID, id int64) (*Milestone, error) {
return getMilestoneByRepoID(x, repoID, id)
}
// GetMilestonesByRepoID returns all milestones of a repository.
func GetMilestonesByRepoID(repoID int64) ([]*Milestone, error) {
miles := make([]*Milestone, 0, 10)
return miles, x.Where("repo_id = ?", repoID).Find(&miles)
}
// GetMilestones returns a list of milestones of given repository and status.
func GetMilestones(repoID int64, page int, isClosed bool) ([]*Milestone, error) {
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
sess := x.Where("repo_id = ? AND is_closed = ?", repoID, isClosed)
if page > 0 {
sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
}
return miles, sess.Find(&miles)
}
func updateMilestone(e Engine, m *Milestone) error {
_, err := e.Id(m.ID).AllCols().Update(m)
return err
}
// UpdateMilestone updates information of given milestone.
func UpdateMilestone(m *Milestone) error {
return updateMilestone(x, m)
}
func countRepoMilestones(e Engine, repoID int64) int64 {
count, _ := e.Where("repo_id=?", repoID).Count(new(Milestone))
return count
}
// CountRepoMilestones returns number of milestones in given repository.
func CountRepoMilestones(repoID int64) int64 {
return countRepoMilestones(x, repoID)
}
func countRepoClosedMilestones(e Engine, repoID int64) int64 {
closed, _ := e.Where("repo_id=? AND is_closed=?", repoID, true).Count(new(Milestone))
return closed
}
// CountRepoClosedMilestones returns number of closed milestones in given repository.
func CountRepoClosedMilestones(repoID int64) int64 {
return countRepoClosedMilestones(x, repoID)
}
// 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))
return open, CountRepoClosedMilestones(repoID)
}
// ChangeMilestoneStatus changes the milestone open/closed status.
// If milestone passes with changed values, those values will be
// updated to database as well.
func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) {
repo, err := GetRepositoryByID(m.RepoID)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
m.IsClosed = isClosed
if err = updateMilestone(sess, m); err != nil {
return err
}
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil {
return err
}
return sess.Commit()
}
func changeMilestoneIssueStats(e *xorm.Session, issue *Issue) error {
if issue.MilestoneID == 0 {
return nil
}
m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
if err != nil {
return err
}
if issue.IsClosed {
m.NumOpenIssues--
m.NumClosedIssues++
} else {
m.NumOpenIssues++
m.NumClosedIssues--
}
return updateMilestone(e, m)
}
// ChangeMilestoneIssueStats updates the open/closed issues counter and progress
// for the milestone associated with the given issue.
func ChangeMilestoneIssueStats(issue *Issue) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if err = changeMilestoneIssueStats(sess, issue); err != nil {
return err
}
return sess.Commit()
}
func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64) error {
if oldMilestoneID > 0 {
m, err := getMilestoneByRepoID(e, issue.RepoID, oldMilestoneID)
if err != nil {
return err
}
m.NumIssues--
if issue.IsClosed {
m.NumClosedIssues--
}
if err = updateMilestone(e, m); err != nil {
return err
} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?", issue.ID); err != nil {
return err
}
}
if issue.MilestoneID > 0 {
m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
if err != nil {
return err
}
m.NumIssues++
if issue.IsClosed {
m.NumClosedIssues++
}
if err = updateMilestone(e, m); err != nil {
return err
} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?", m.ID, issue.ID); err != nil {
return err
}
}
return updateIssue(e, issue)
}
// ChangeMilestoneAssign changes assignment of milestone for issue.
func ChangeMilestoneAssign(issue *Issue, oldMilestoneID int64) (err error) {
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
if err = changeMilestoneAssign(sess, issue, oldMilestoneID); err != nil {
return err
}
return sess.Commit()
}
// DeleteMilestoneOfRepoByID deletes a milestone from a repository.
func DeleteMilestoneOfRepoByID(repoID, id int64) error {
m, err := GetMilestoneByRepoID(repoID, id)
if err != nil {
if IsErrMilestoneNotExist(err) {
return nil
}
return err
}
repo, err := GetRepositoryByID(m.RepoID)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Id(m.ID).Delete(new(Milestone)); err != nil {
return err
}
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil {
return err
}
if _, err = sess.Exec("UPDATE `issue` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
return err
} else if _, err = sess.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
return err
}
return sess.Commit()
}

264
models/mirror.go Normal file
View File

@@ -0,0 +1,264 @@
// Copyright 2016 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 models
import (
"fmt"
"strings"
"time"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"gopkg.in/ini.v1"
"github.com/gogits/git-module"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/sync"
)
var MirrorQueue = sync.NewUniqueQueue(setting.Repository.MirrorQueueLength)
// Mirror represents mirror information of a repository.
type Mirror struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64
Repo *Repository `xorm:"-"`
Interval int // Hour.
EnablePrune bool `xorm:"NOT NULL DEFAULT true"`
Updated time.Time `xorm:"-"`
UpdatedUnix int64
NextUpdate time.Time `xorm:"-"`
NextUpdateUnix int64
address string `xorm:"-"`
}
func (m *Mirror) BeforeInsert() {
m.UpdatedUnix = time.Now().Unix()
m.NextUpdateUnix = m.NextUpdate.Unix()
}
func (m *Mirror) BeforeUpdate() {
m.UpdatedUnix = time.Now().Unix()
m.NextUpdateUnix = m.NextUpdate.Unix()
}
func (m *Mirror) AfterSet(colName string, _ xorm.Cell) {
var err error
switch colName {
case "repo_id":
m.Repo, err = GetRepositoryByID(m.RepoID)
if err != nil {
log.Error(3, "GetRepositoryByID[%d]: %v", m.ID, err)
}
case "updated_unix":
m.Updated = time.Unix(m.UpdatedUnix, 0).Local()
case "next_updated_unix":
m.NextUpdate = time.Unix(m.NextUpdateUnix, 0).Local()
}
}
// ScheduleNextUpdate calculates and sets next update time.
func (m *Mirror) ScheduleNextUpdate() {
m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour)
}
func (m *Mirror) readAddress() {
if len(m.address) > 0 {
return
}
cfg, err := ini.Load(m.Repo.GitConfigPath())
if err != nil {
log.Error(4, "Load: %v", err)
return
}
m.address = cfg.Section("remote \"origin\"").Key("url").Value()
}
// HandleCloneUserCredentials replaces user credentials from HTTP/HTTPS URL
// with placeholder <credentials>.
// It will fail for any other forms of clone addresses.
func HandleCloneUserCredentials(url string, mosaics bool) string {
i := strings.Index(url, "@")
if i == -1 {
return url
}
start := strings.Index(url, "://")
if start == -1 {
return url
}
if mosaics {
return url[:start+3] + "<credentials>" + url[i:]
}
return url[:start+3] + url[i+1:]
}
// Address returns mirror address from Git repository config without credentials.
func (m *Mirror) Address() string {
m.readAddress()
return HandleCloneUserCredentials(m.address, false)
}
// MosaicsAddress returns mirror address from Git repository config with credentials under mosaics.
func (m *Mirror) MosaicsAddress() string {
m.readAddress()
return HandleCloneUserCredentials(m.address, true)
}
// FullAddress returns mirror address from Git repository config.
func (m *Mirror) FullAddress() string {
m.readAddress()
return m.address
}
// SaveAddress writes new address to Git repository config.
func (m *Mirror) SaveAddress(addr string) error {
configPath := m.Repo.GitConfigPath()
cfg, err := ini.Load(configPath)
if err != nil {
return fmt.Errorf("Load: %v", err)
}
cfg.Section("remote \"origin\"").Key("url").SetValue(addr)
return cfg.SaveToIndent(configPath, "\t")
}
// runSync returns true if sync finished without error.
func (m *Mirror) runSync() bool {
repoPath := m.Repo.RepoPath()
wikiPath := m.Repo.WikiPath()
timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second
// Do a fast-fail testing against on repository URL to ensure it is accessible under
// good condition to prevent long blocking on URL resolution without syncing anything.
if !git.IsRepoURLAccessible(git.NetworkOptions{
URL: m.FullAddress(),
Timeout: 10 * time.Second,
}) {
desc := fmt.Sprintf("Mirror repository URL is not accessible: %s", m.MosaicsAddress())
if err := CreateRepositoryNotice(desc); err != nil {
log.Error(4, "CreateRepositoryNotice: %v", err)
}
return false
}
gitArgs := []string{"remote", "update"}
if m.EnablePrune {
gitArgs = append(gitArgs, "--prune")
}
if _, stderr, err := process.ExecDir(
timeout, repoPath, fmt.Sprintf("Mirror.runSync: %s", repoPath),
"git", gitArgs...); err != nil {
desc := fmt.Sprintf("Fail to update mirror repository '%s': %s", repoPath, stderr)
log.Error(4, desc)
if err = CreateRepositoryNotice(desc); err != nil {
log.Error(4, "CreateRepositoryNotice: %v", err)
}
return false
}
if m.Repo.HasWiki() {
if _, stderr, err := process.ExecDir(
timeout, wikiPath, fmt.Sprintf("Mirror.runSync: %s", wikiPath),
"git", "remote", "update", "--prune"); err != nil {
desc := fmt.Sprintf("Fail to update mirror wiki repository '%s': %s", wikiPath, stderr)
log.Error(4, desc)
if err = CreateRepositoryNotice(desc); err != nil {
log.Error(4, "CreateRepositoryNotice: %v", err)
}
return false
}
}
return true
}
func getMirrorByRepoID(e Engine, repoID int64) (*Mirror, error) {
m := &Mirror{RepoID: repoID}
has, err := e.Get(m)
if err != nil {
return nil, err
} else if !has {
return nil, ErrMirrorNotExist
}
return m, nil
}
// GetMirrorByRepoID returns mirror information of a repository.
func GetMirrorByRepoID(repoID int64) (*Mirror, error) {
return getMirrorByRepoID(x, repoID)
}
func updateMirror(e Engine, m *Mirror) error {
_, err := e.Id(m.ID).AllCols().Update(m)
return err
}
func UpdateMirror(m *Mirror) error {
return updateMirror(x, m)
}
func DeleteMirrorByRepoID(repoID int64) error {
_, err := x.Delete(&Mirror{RepoID: repoID})
return err
}
// MirrorUpdate checks and updates mirror repositories.
func MirrorUpdate() {
if taskStatusTable.IsRunning(_MIRROR_UPDATE) {
return
}
taskStatusTable.Start(_MIRROR_UPDATE)
defer taskStatusTable.Stop(_MIRROR_UPDATE)
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
}
MirrorQueue.Add(m.RepoID)
return nil
}); err != nil {
log.Error(4, "MirrorUpdate: %v", err)
}
}
// SyncMirrors checks and syncs mirrors.
// TODO: sync more mirrors at same time.
func SyncMirrors() {
// Start listening on new sync requests.
for repoID := range MirrorQueue.Queue() {
log.Trace("SyncMirrors [repo_id: %v]", repoID)
MirrorQueue.Remove(repoID)
m, err := GetMirrorByRepoID(com.StrTo(repoID).MustInt64())
if err != nil {
log.Error(4, "GetMirrorByRepoID [%s]: %v", repoID, err)
continue
}
if !m.runSync() {
continue
}
m.ScheduleNextUpdate()
if err = UpdateMirror(m); err != nil {
log.Error(4, "UpdateMirror [%s]: %v", repoID, err)
continue
}
}
}
func InitSyncMirrors() {
go SyncMirrors()
}

View File

@@ -6,6 +6,7 @@ package models
import (
"database/sql"
"errors"
"fmt"
"net/url"
"os"
@@ -27,11 +28,14 @@ type Engine interface {
Exec(string, ...interface{}) (sql.Result, error)
Find(interface{}, ...interface{}) error
Get(interface{}) (bool, error)
Id(interface{}) *xorm.Session
In(string, ...interface{}) *xorm.Session
Insert(...interface{}) (int64, error)
InsertOne(interface{}) (int64, error)
Id(interface{}) *xorm.Session
Iterate(interface{}, xorm.IterFunc) error
Sql(string, ...interface{}) *xorm.Session
Where(string, ...interface{}) *xorm.Session
Table(interface{}) *xorm.Session
Where(interface{}, ...interface{}) *xorm.Session
}
func sessionRelease(sess *xorm.Session) {
@@ -51,13 +55,12 @@ var (
}
EnableSQLite3 bool
EnableTidb bool
)
func init() {
tables = append(tables,
new(User), new(PublicKey), new(AccessToken),
new(Repository), new(DeployKey), new(Collaboration), new(Access),
new(Repository), new(DeployKey), new(Collaboration), new(Access), new(Upload),
new(Watch), new(Star), new(Follow), new(Action),
new(Issue), new(PullRequest), new(Comment), new(Attachment), new(IssueUser),
new(Label), new(IssueLabel), new(Milestone),
@@ -95,52 +98,57 @@ func LoadConfigs() {
DbCfg.Path = sec.Key("PATH").MustString("data/gogs.db")
}
// parsePostgreSQLHostPort parses given input in various forms defined in
// https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
// and returns proper host and port number.
func parsePostgreSQLHostPort(info string) (string, string) {
host, port := "127.0.0.1", "5432"
if strings.Contains(info, ":") && !strings.HasSuffix(info, "]") {
idx := strings.LastIndex(info, ":")
host = info[:idx]
port = info[idx+1:]
} else if len(info) > 0 {
host = info
}
return host, port
}
func getEngine() (*xorm.Engine, error) {
cnnstr := ""
connStr := ""
var Param string = "?"
if strings.Contains(DbCfg.Name,Param) {
Param="&"
if strings.Contains(DbCfg.Name, Param) {
Param = "&"
}
switch DbCfg.Type {
case "mysql":
if DbCfg.Host[0] == '/' { // looks like a unix socket
cnnstr = fmt.Sprintf("%s:%s@unix(%s)/%s%scharset=utf8&parseTime=true",
connStr = fmt.Sprintf("%s:%s@unix(%s)/%s%scharset=utf8&parseTime=true",
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name, Param)
} else {
cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s%scharset=utf8&parseTime=true",
connStr = fmt.Sprintf("%s:%s@tcp(%s)/%s%scharset=utf8&parseTime=true",
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name, Param)
}
case "postgres":
var host, port = "127.0.0.1", "5432"
fields := strings.Split(DbCfg.Host, ":")
if len(fields) > 0 && len(strings.TrimSpace(fields[0])) > 0 {
host = fields[0]
host, port := parsePostgreSQLHostPort(DbCfg.Host)
if host[0] == '/' { // looks like a unix socket
connStr = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s",
url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), port, DbCfg.Name, Param, DbCfg.SSLMode, host)
} else {
connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), host, port, DbCfg.Name, Param, DbCfg.SSLMode)
}
if len(fields) > 1 && len(strings.TrimSpace(fields[1])) > 0 {
port = fields[1]
}
cnnstr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), host, port, DbCfg.Name, Param, DbCfg.SSLMode)
case "sqlite3":
if !EnableSQLite3 {
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
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)
}
cnnstr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc"
case "tidb":
if !EnableTidb {
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
}
if err := os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm); err != nil {
return nil, fmt.Errorf("Fail to create directories: %v", err)
}
cnnstr = "goleveldb://" + DbCfg.Path
connStr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc"
default:
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
}
return xorm.NewEngine(DbCfg.Type, cnnstr)
return xorm.NewEngine(DbCfg.Type, connStr)
}
func NewTestEngine(x *xorm.Engine) (err error) {
@@ -170,7 +178,12 @@ func SetEngine() (err error) {
if err != nil {
return fmt.Errorf("Fail to create xorm.log: %v", err)
}
x.SetLogger(xorm.NewSimpleLogger(f))
if setting.ProdMode {
x.SetLogger(xorm.NewSimpleLogger3(f, xorm.DEFAULT_LOG_PREFIX, xorm.DEFAULT_LOG_FLAG, core.LOG_WARNING))
} else {
x.SetLogger(xorm.NewSimpleLogger(f))
}
x.ShowSQL(true)
return nil
}
@@ -206,7 +219,7 @@ func GetStatistic() (stats Statistic) {
stats.Counter.User = CountUsers()
stats.Counter.Org = CountOrganizations()
stats.Counter.PublicKey, _ = x.Count(new(PublicKey))
stats.Counter.Repo = CountRepositories()
stats.Counter.Repo = CountRepositories(true)
stats.Counter.Watch, _ = x.Count(new(Watch))
stats.Counter.Star, _ = x.Count(new(Star))
stats.Counter.Action, _ = x.Count(new(Action))

33
models/models_test.go Normal file
View File

@@ -0,0 +1,33 @@
// Copyright 2016 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 models
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_parsePostgreSQLHostPort(t *testing.T) {
testSuites := []struct {
input string
host, port string
}{
{"127.0.0.1:1234", "127.0.0.1", "1234"},
{"127.0.0.1", "127.0.0.1", "5432"},
{"[::1]:1234", "[::1]", "1234"},
{"[::1]", "[::1]", "5432"},
{"/tmp/pg.sock:1234", "/tmp/pg.sock", "1234"},
{"/tmp/pg.sock", "/tmp/pg.sock", "5432"},
}
Convey("Parse PostgreSQL host and port", t, func() {
for _, suite := range testSuites {
host, port := parsePostgreSQLHostPort(suite.input)
So(host, ShouldEqual, suite.host)
So(port, ShouldEqual, suite.port)
}
})
}

View File

@@ -1,18 +0,0 @@
// +build tidb go1.4.2
// 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 models
import (
_ "github.com/go-xorm/tidb"
"github.com/ngaut/log"
_ "github.com/pingcap/tidb"
)
func init() {
EnableTidb = true
log.SetLevelByString("error")
}

View File

@@ -10,8 +10,10 @@ import (
"os"
"strings"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/base"
)
var (
@@ -21,16 +23,16 @@ var (
// IsOwnedBy returns true if given user is in the owner team.
func (org *User) IsOwnedBy(uid int64) bool {
return IsOrganizationOwner(org.Id, uid)
return IsOrganizationOwner(org.ID, uid)
}
// IsOrgMember returns true if given user is member of organization.
func (org *User) IsOrgMember(uid int64) bool {
return org.IsOrganization() && IsOrganizationMember(org.Id, uid)
return org.IsOrganization() && IsOrganizationMember(org.ID, uid)
}
func (org *User) getTeam(e Engine, name string) (*Team, error) {
return getTeam(e, org.Id, name)
return getTeam(e, org.ID, name)
}
// GetTeam returns named team of organization.
@@ -48,7 +50,7 @@ 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).Find(&org.Teams)
}
// GetTeams returns all teams that belong to organization.
@@ -58,7 +60,7 @@ func (org *User) GetTeams() error {
// GetMembers returns all members of organization.
func (org *User) GetMembers() error {
ous, err := GetOrgUsersByOrgID(org.Id)
ous, err := GetOrgUsersByOrgID(org.ID)
if err != nil {
return err
}
@@ -75,16 +77,16 @@ func (org *User) GetMembers() error {
// AddMember adds new member to organization.
func (org *User) AddMember(uid int64) error {
return AddOrgUser(org.Id, uid)
return AddOrgUser(org.ID, uid)
}
// RemoveMember removes member from organization.
func (org *User) RemoveMember(uid int64) error {
return RemoveOrgUser(org.Id, uid)
return RemoveOrgUser(org.ID, uid)
}
func (org *User) removeOrgRepo(e Engine, repoID int64) error {
return removeOrgRepo(e, org.Id, repoID)
return removeOrgRepo(e, org.ID, repoID)
}
// RemoveOrgRepo removes all team-repository relations of organization.
@@ -94,7 +96,7 @@ func (org *User) RemoveOrgRepo(repoID int64) error {
// CreateOrganization creates record of a new organization.
func CreateOrganization(org, owner *User) (err error) {
if err = IsUsableName(org.Name); err != nil {
if err = IsUsableUsername(org.Name); err != nil {
return err
}
@@ -106,9 +108,12 @@ func CreateOrganization(org, owner *User) (err error) {
}
org.LowerName = strings.ToLower(org.Name)
org.FullName = 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
@@ -127,8 +132,8 @@ func CreateOrganization(org, owner *User) (err error) {
// Add initial creator to organization and owner team.
if _, err = sess.Insert(&OrgUser{
Uid: owner.Id,
OrgID: org.Id,
Uid: owner.ID,
OrgID: org.ID,
IsOwner: true,
NumTeams: 1,
}); err != nil {
@@ -137,7 +142,7 @@ func CreateOrganization(org, owner *User) (err error) {
// Create default owner team.
t := &Team{
OrgID: org.Id,
OrgID: org.ID,
LowerName: strings.ToLower(OWNER_TEAM),
Name: OWNER_TEAM,
Authorize: ACCESS_MODE_OWNER,
@@ -148,8 +153,8 @@ func CreateOrganization(org, owner *User) (err error) {
}
if _, err = sess.Insert(&TeamUser{
Uid: owner.Id,
OrgID: org.Id,
UID: owner.ID,
OrgID: org.ID,
TeamID: t.ID,
}); err != nil {
return fmt.Errorf("insert team-user relation: %v", err)
@@ -205,9 +210,9 @@ func DeleteOrganization(org *User) (err error) {
}
if err = deleteBeans(sess,
&Team{OrgID: org.Id},
&OrgUser{OrgID: org.Id},
&TeamUser{OrgID: org.Id},
&Team{OrgID: org.ID},
&OrgUser{OrgID: org.ID},
&TeamUser{OrgID: org.ID},
); err != nil {
return fmt.Errorf("deleteBeans: %v", err)
}
@@ -306,17 +311,20 @@ func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
return ous, err
}
func getOrgUsersByOrgID(e Engine, orgID int64) ([]*OrgUser, error) {
orgUsers := make([]*OrgUser, 0, 10)
return orgUsers, e.Where("org_id=?", orgID).Find(&orgUsers)
}
// 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)
return ous, err
return getOrgUsersByOrgID(x, orgID)
}
// ChangeOrgUserStatus changes public or private membership status.
func ChangeOrgUserStatus(orgId, uid int64, public bool) error {
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 {
@@ -329,8 +337,8 @@ func ChangeOrgUserStatus(orgId, uid int64, public bool) error {
}
// AddOrgUser adds new user to given organization.
func AddOrgUser(orgId, uid int64) error {
if IsOrganizationMember(orgId, uid) {
func AddOrgUser(orgID, uid int64) error {
if IsOrganizationMember(orgID, uid) {
return nil
}
@@ -342,13 +350,13 @@ func AddOrgUser(orgId, uid int64) error {
ou := &OrgUser{
Uid: uid,
OrgID: orgId,
OrgID: orgID,
}
if _, err := sess.Insert(ou); err != nil {
sess.Rollback()
return err
} else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgId); err != nil {
} else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID); err != nil {
sess.Rollback()
return err
}
@@ -357,35 +365,39 @@ func AddOrgUser(orgId, uid int64) error {
}
// RemoveOrgUser removes user from given organization.
func RemoveOrgUser(orgId, uid int64) error {
func RemoveOrgUser(orgID, userID int64) error {
ou := new(OrgUser)
has, err := x.Where("uid=?", uid).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 {
return nil
}
u, err := GetUserByID(uid)
user, err := GetUserByID(userID)
if err != nil {
return fmt.Errorf("GetUserById: %v", err)
return fmt.Errorf("GetUserByID [%d]: %v", userID, err)
}
org, err := GetUserByID(orgId)
org, err := GetUserByID(orgID)
if err != nil {
return fmt.Errorf("get organization: %v", err)
} else if err = org.GetRepositories(); err != nil {
return fmt.Errorf("GetRepositories: %v", err)
return fmt.Errorf("GetUserByID [%d]: %v", orgID, err)
}
// FIXME: only need to get IDs here, not all fields of repository.
repos, _, err := org.GetUserRepositories(user.ID, 1, org.NumRepos)
if err != nil {
return fmt.Errorf("GetUserRepositories [%d]: %v", user.ID, err)
}
// Check if the user to delete is the last member in owner team.
if IsOrganizationOwner(orgId, uid) {
if IsOrganizationOwner(orgID, userID) {
t, err := org.GetOwnerTeam()
if err != nil {
return err
}
if t.NumMembers == 1 {
return ErrLastOrgOwner{UID: uid}
return ErrLastOrgOwner{UID: userID}
}
}
@@ -397,28 +409,32 @@ func RemoveOrgUser(orgId, uid int64) error {
if _, err := sess.Id(ou.ID).Delete(ou); err != nil {
return err
} else if _, err = sess.Exec("UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgId); err != nil {
} else if _, err = sess.Exec("UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgID); err != nil {
return err
}
// Delete all repository accesses.
access := &Access{UserID: u.Id}
for _, repo := range org.Repos {
access.RepoID = repo.ID
if _, err = sess.Delete(access); err != nil {
// Delete all repository accesses and unwatch them.
repoIDs := make([]int64, len(repos))
for i := range repos {
repoIDs = append(repoIDs, repos[i].ID)
if err = watchRepo(sess, user.ID, repos[i].ID, false); err != nil {
return err
} else if err = watchRepo(sess, u.Id, repo.ID, false); err != nil {
}
}
if len(repoIDs) > 0 {
if _, err = sess.Where("user_id = ?", user.ID).In("repo_id", repoIDs).Delete(new(Access)); err != nil {
return err
}
}
// Delete member in his/her teams.
teams, err := getUserTeams(sess, org.Id, u.Id)
teams, err := getUserTeams(sess, org.ID, user.ID)
if err != nil {
return err
}
for _, t := range teams {
if err = removeTeamMember(sess, org.Id, t.ID, u.Id); err != nil {
if err = removeTeamMember(sess, org.ID, t.ID, user.ID); err != nil {
return err
}
}
@@ -439,55 +455,100 @@ func RemoveOrgRepo(orgID, repoID int64) error {
return removeOrgRepo(x, orgID, repoID)
}
// GetUserRepositories gets all repositories of an organization,
// that the user with the given userID has access to.
func (org *User) GetUserRepositories(userID int64) (err error) {
func (org *User) getUserTeams(e Engine, userID int64, cols ...string) ([]*Team, error) {
teams := make([]*Team, 0, org.NumTeams)
if err = x.Sql(`SELECT team.id FROM team
INNER JOIN team_user ON team_user.team_id = team.id
WHERE team_user.org_id = ? AND team_user.uid = ?`, org.Id, userID).Find(&teams); err != nil {
return fmt.Errorf("get teams: %v", err)
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)
}
// GetUserTeamIDs returns of all team IDs of the organization that user is memeber of.
func (org *User) GetUserTeamIDs(userID int64) ([]int64, error) {
teams, err := org.getUserTeams(x, userID, "team.id")
if err != nil {
return nil, fmt.Errorf("getUserTeams [%d]: %v", userID, err)
}
teamIDs := make([]string, len(teams))
teamIDs := make([]int64, len(teams))
for i := range teams {
teamIDs[i] = com.ToStr(teams[i].ID)
teamIDs[i] = teams[i].ID
}
if len(teamIDs) == 0 {
// user has no team but "IN ()" is invalid SQL
teamIDs = append(teamIDs, "-1") // there is no repo with id=-1
}
repos := make([]*Repository, 0, 5)
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`, strings.Join(teamIDs, ",")), org.Id, false).Find(&repos); err != nil {
return fmt.Errorf("get repositories: %v", err)
}
org.Repos = repos
// FIXME: should I change this value inside method,
// or only in location of caller where it's really needed?
org.NumRepos = len(org.Repos)
return nil
return teamIDs, nil
}
// GetTeams returns all teams that belong to organization,
// and that the user has joined.
func (org *User) GetUserTeams(userID int64) error {
teams := make([]*Team, 0, 5)
if err := x.Sql(`SELECT team.* FROM team
INNER JOIN team_user ON team_user.team_id = team.id
WHERE team_user.org_id = ? AND team_user.uid = ?`,
org.Id, userID).Find(&teams); err != nil {
return fmt.Errorf("get teams: %v", err)
func (org *User) GetUserTeams(userID int64) ([]*Team, error) {
return org.getUserTeams(x, userID)
}
// GetUserRepositories returns a range of repositories in organization
// that the user with the given userID has access to,
// and total number of records based on given condition.
func (org *User) GetUserRepositories(userID int64, page, pageSize int) ([]*Repository, int64, error) {
teamIDs, err := org.GetUserTeamIDs(userID)
if err != nil {
return nil, 0, fmt.Errorf("GetUserTeamIDs: %v", err)
}
if len(teamIDs) == 0 {
// user has no team but "IN ()" is invalid SQL
teamIDs = []int64{-1} // there is no repo with id=-1
}
org.Teams = teams
if page <= 0 {
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 {
return nil, 0, fmt.Errorf("get repositories: %v", err)
}
// FIXME: should I change this value inside method,
// or only in location of caller where it's really needed?
org.NumTeams = len(org.Teams)
return nil
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)
if err != nil {
log.Error(4, "count user repositories in organization: %v", err)
}
return repos, int64(len(results)), nil
}
// GetUserRepositories returns mirror repositories of the organization
// that the user with the given userID has access to.
func (org *User) GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
teamIDs, err := org.GetUserTeamIDs(userID)
if err != nil {
return nil, fmt.Errorf("GetUserTeamIDs: %v", err)
}
if len(teamIDs) == 0 {
teamIDs = []int64{-1}
}
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
}

View File

@@ -8,6 +8,8 @@ import (
"errors"
"fmt"
"strings"
"github.com/go-xorm/xorm"
)
const OWNER_TEAM = "Owners"
@@ -26,6 +28,16 @@ type Team struct {
NumMembers int
}
func (t *Team) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "num_repos":
// LEGACY [0.11]: this is backward compatibility bug fix for https://github.com/gogits/gogs/issues/3671
if t.NumRepos < 0 {
t.NumRepos = 0
}
}
}
// IsOwnerTeam returns true if team is owner team.
func (t *Team) IsOwnerTeam() bool {
return t.Name == OWNER_TEAM
@@ -106,7 +118,7 @@ func (t *Team) addRepository(e Engine, repo *Repository) (err error) {
return fmt.Errorf("getMembers: %v", err)
}
for _, u := range t.Members {
if err = watchRepo(e, u.Id, repo.ID, true); err != nil {
if err = watchRepo(e, u.ID, repo.ID, true); err != nil {
return fmt.Errorf("watchRepo: %v", err)
}
}
@@ -162,7 +174,7 @@ func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (e
continue
}
if err = watchRepo(e, u.Id, repo.ID, false); err != nil {
if err = watchRepo(e, u.ID, repo.ID, false); err != nil {
return err
}
}
@@ -341,7 +353,7 @@ 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,7 +381,7 @@ 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 {
@@ -384,14 +396,15 @@ func IsTeamMember(orgID, teamID, uid int64) bool {
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.Sql("SELECT `id`, `org_id`, `team_id`, `uid` FROM `team_user` 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)
}
@@ -457,7 +470,7 @@ func AddTeamMember(orgID, teamID, uid int64) error {
}
tu := &TeamUser{
Uid: uid,
UID: uid,
OrgID: orgID,
TeamID: teamID,
}
@@ -519,7 +532,7 @@ func removeTeamMember(e Engine, orgID, teamID, uid int64) error {
}
tu := &TeamUser{
Uid: uid,
UID: uid,
OrgID: orgID,
TeamID: teamID,
}
@@ -538,7 +551,7 @@ 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 = ?", uid).And("org_id = ?", org.ID).Get(ou)
if err != nil {
return err
}

View File

@@ -13,15 +13,18 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"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)
type PullRequestType int
const (
@@ -65,10 +68,10 @@ type PullRequest struct {
}
func (pr *PullRequest) BeforeUpdate() {
pr.MergedUnix = pr.Merged.UTC().Unix()
pr.MergedUnix = pr.Merged.Unix()
}
// Note: don't try to get Pull because will end up recursive querying.
// Note: don't try to get Issue because will end up recursive querying.
func (pr *PullRequest) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "merged_unix":
@@ -80,43 +83,93 @@ func (pr *PullRequest) AfterSet(colName string, _ xorm.Cell) {
}
}
func (pr *PullRequest) getHeadRepo(e Engine) (err error) {
pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
if err != nil && !IsErrRepoNotExist(err) {
return fmt.Errorf("getRepositoryByID(head): %v", err)
// Note: don't try to get Issue because will end up recursive querying.
func (pr *PullRequest) loadAttributes(e Engine) (err error) {
if pr.HeadRepo == nil {
pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
if err != nil && !IsErrRepoNotExist(err) {
return fmt.Errorf("getRepositoryByID.(HeadRepo) [%d]: %v", pr.HeadRepoID, err)
}
}
if pr.BaseRepo == nil {
pr.BaseRepo, err = getRepositoryByID(e, pr.BaseRepoID)
if err != nil {
return fmt.Errorf("getRepositoryByID.(BaseRepo) [%d]: %v", pr.BaseRepoID, err)
}
}
if pr.HasMerged && pr.Merger == nil {
pr.Merger, err = getUserByID(e, pr.MergerID)
if IsErrUserNotExist(err) {
pr.MergerID = -1
pr.Merger = NewGhostUser()
} else if err != nil {
return fmt.Errorf("getUserByID [%d]: %v", pr.MergerID, err)
}
}
return nil
}
func (pr *PullRequest) GetHeadRepo() (err error) {
return pr.getHeadRepo(x)
func (pr *PullRequest) LoadAttributes() error {
return pr.loadAttributes(x)
}
func (pr *PullRequest) GetBaseRepo() (err error) {
if pr.BaseRepo != nil {
func (pr *PullRequest) LoadIssue() (err error) {
if pr.Issue != nil {
return nil
}
pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID)
if err != nil {
return fmt.Errorf("GetRepositoryByID(base): %v", err)
}
return nil
pr.Issue, err = GetIssueByID(pr.IssueID)
return err
}
func (pr *PullRequest) GetMerger() (err error) {
if !pr.HasMerged || pr.Merger != nil {
return nil
// This method assumes following fields have been assigned with valid values:
// Required - Issue, BaseRepo
// Optional - HeadRepo, Merger
func (pr *PullRequest) APIFormat() *api.PullRequest {
// In case of head repo has been deleted.
var apiHeadRepo *api.Repository
if pr.HeadRepo == nil {
apiHeadRepo = &api.Repository{
Name: "deleted",
}
} else {
apiHeadRepo = pr.HeadRepo.APIFormat(nil)
}
pr.Merger, err = GetUserByID(pr.MergerID)
if IsErrUserNotExist(err) {
pr.MergerID = -1
pr.Merger = NewFakeUser()
} else if err != nil {
return fmt.Errorf("GetUserByID: %v", err)
apiIssue := pr.Issue.APIFormat()
apiPullRequest := &api.PullRequest{
ID: pr.ID,
Index: pr.Index,
Poster: apiIssue.Poster,
Title: apiIssue.Title,
Body: apiIssue.Body,
Labels: apiIssue.Labels,
Milestone: apiIssue.Milestone,
Assignee: apiIssue.Assignee,
State: apiIssue.State,
Comments: apiIssue.Comments,
HeadBranch: pr.HeadBranch,
HeadRepo: apiHeadRepo,
BaseBranch: pr.BaseBranch,
BaseRepo: pr.BaseRepo.APIFormat(nil),
HTMLURL: pr.Issue.HTMLURL(),
HasMerged: pr.HasMerged,
}
return nil
if pr.Status != PULL_REQUEST_STATUS_CHECKING {
mergeable := pr.Status != PULL_REQUEST_STATUS_CONFLICT
apiPullRequest.Mergeable = &mergeable
}
if pr.HasMerged {
apiPullRequest.Merged = &pr.Merged
apiPullRequest.MergedCommitID = &pr.MergedCommitID
apiPullRequest.MergedBy = pr.Merger.APIFormat()
}
return apiPullRequest
}
// IsChecking returns true if this pull request is still checking conflict.
@@ -130,12 +183,12 @@ func (pr *PullRequest) CanAutoMerge() bool {
}
// Merge merges pull request to base repository.
// FIXME: add repoWorkingPull make sure two merges does not happen at same time.
func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error) {
if err = pr.GetHeadRepo(); err != nil {
return fmt.Errorf("GetHeadRepo: %v", err)
} else if err = pr.GetBaseRepo(); err != nil {
return fmt.Errorf("GetBaseRepo: %v", err)
}
defer func() {
go HookQueue.Add(pr.BaseRepo.ID)
go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
}()
sess := x.NewSession()
defer sessionRelease(sess)
@@ -152,21 +205,6 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
if err != nil {
return fmt.Errorf("OpenRepository: %v", err)
}
pr.MergedCommitID, err = headGitRepo.GetBranchCommitID(pr.HeadBranch)
if err != nil {
return fmt.Errorf("GetBranchCommitID: %v", err)
}
if err = mergePullRequestAction(sess, doer, pr.Issue.Repo, pr.Issue); err != nil {
return fmt.Errorf("mergePullRequestAction: %v", err)
}
pr.HasMerged = true
pr.Merged = time.Now()
pr.MergerID = doer.Id
if _, err = sess.Id(pr.ID).AllCols().Update(pr); err != nil {
return fmt.Errorf("update pull request: %v", err)
}
// Clone base repo.
tmpBasePath := path.Join(setting.AppDataPath, "tmp/repos", com.ToStr(time.Now().Nanosecond())+".git")
@@ -222,37 +260,72 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
return fmt.Errorf("git push: %s", stderr)
}
pr.MergedCommitID, err = headGitRepo.GetBranchCommitID(pr.HeadBranch)
if err != nil {
return fmt.Errorf("GetBranchCommit: %v", err)
}
pr.HasMerged = true
pr.Merged = time.Now()
pr.MergerID = doer.ID
if _, err = sess.Id(pr.ID).AllCols().Update(pr); err != nil {
return fmt.Errorf("update pull request: %v", err)
}
if err = sess.Commit(); err != nil {
return fmt.Errorf("Commit: %v", err)
}
// Compose commit repository action
if err = MergePullRequestAction(doer, pr.Issue.Repo, pr.Issue); err != nil {
log.Error(4, "MergePullRequestAction [%d]: %v", pr.ID, err)
}
// Reload pull request information.
if err = pr.LoadAttributes(); err != nil {
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,
Index: pr.Index,
PullRequest: pr.APIFormat(),
Repository: pr.Issue.Repo.APIFormat(nil),
Sender: doer.APIFormat(),
}); err != nil {
log.Error(4, "PrepareWebhooks: %v", err)
return nil
}
l, err := headGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase)
if err != nil {
return fmt.Errorf("CommitsBetween: %v", err)
log.Error(4, "CommitsBetweenIDs: %v", err)
return nil
}
// TODO: when squash commits, no need to append merge commit.
// It is possible that head branch is not fully sync with base branch for merge commits,
// so we need to get latest head commit and append merge commit manully
// to avoid strange diff commits produced.
mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch)
if err != nil {
log.Error(4, "GetBranchCommit: %v", err)
return nil
}
l.PushFront(mergeCommit)
p := &api.PushPayload{
Ref: "refs/heads/" + pr.BaseBranch,
Ref: git.BRANCH_PREFIX + pr.BaseBranch,
Before: pr.MergeBase,
After: pr.MergedCommitID,
CompareUrl: setting.AppUrl + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
Commits: ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.FullLink()),
Repo: pr.BaseRepo.ComposePayload(),
Pusher: &api.PayloadAuthor{
Name: pr.HeadRepo.MustOwner().DisplayName(),
Email: pr.HeadRepo.MustOwner().Email,
UserName: pr.HeadRepo.MustOwner().Name,
},
Sender: &api.PayloadUser{
UserName: doer.Name,
ID: doer.Id,
AvatarUrl: setting.AppUrl + doer.RelAvatarLink(),
},
CompareURL: setting.AppUrl + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
Commits: ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.HTMLURL()),
Repo: pr.BaseRepo.APIFormat(nil),
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
Sender: doer.APIFormat(),
}
if err = PrepareWebhooks(pr.BaseRepo, HOOK_EVENT_PUSH, p); err != nil {
return fmt.Errorf("PrepareWebhooks: %v", err)
}
go HookQueue.Add(pr.BaseRepo.ID)
return nil
}
@@ -285,22 +358,17 @@ func (pr *PullRequest) testPatch() (err error) {
return nil
}
repoWorkingPool.CheckIn(com.ToStr(pr.BaseRepoID))
defer repoWorkingPool.CheckOut(com.ToStr(pr.BaseRepoID))
log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)
if err := pr.BaseRepo.UpdateLocalCopy(); err != nil {
return fmt.Errorf("UpdateLocalCopy: %v", err)
}
// Checkout base branch.
_, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
fmt.Sprintf("PullRequest.Merge (git checkout): %v", pr.BaseRepo.ID),
"git", "checkout", pr.BaseBranch)
if err != nil {
return fmt.Errorf("git checkout: %s", stderr)
if err := pr.BaseRepo.UpdateLocalCopyBranch(pr.BaseBranch); err != nil {
return fmt.Errorf("UpdateLocalCopy [%d]: %v", pr.BaseRepoID, err)
}
pr.Status = PULL_REQUEST_STATUS_CHECKING
_, stderr, err = process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
_, 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 {
@@ -326,23 +394,16 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
return err
}
if err = newIssue(sess, repo, pull, labelIDs, uuids, true); err != nil {
if err = newIssue(sess, NewIssueOptions{
Repo: repo,
Issue: pull,
LableIDs: labelIDs,
Attachments: uuids,
IsPull: true,
}); err != nil {
return fmt.Errorf("newIssue: %v", err)
}
// Notify watchers.
act := &Action{
ActUserID: pull.Poster.Id,
ActUserName: pull.Poster.Name,
ActEmail: pull.Poster.Email,
OpType: ACTION_CREATE_PULL_REQUEST,
Content: fmt.Sprintf("%d|%s", pull.Index, pull.Name),
RepoID: repo.ID,
RepoUserName: repo.Owner.Name,
RepoName: repo.Name,
IsPrivate: repo.IsPrivate,
}
pr.Index = pull.Index
if err = repo.SavePatch(pr.Index, patch); err != nil {
return fmt.Errorf("SavePatch: %v", err)
@@ -352,6 +413,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
if err = pr.testPatch(); err != nil {
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
}
@@ -365,12 +427,34 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
return fmt.Errorf("Commit: %v", err)
}
if err = NotifyWatchers(act); err != nil {
if err = NotifyWatchers(&Action{
ActUserID: pull.Poster.ID,
ActUserName: pull.Poster.Name,
OpType: ACTION_CREATE_PULL_REQUEST,
Content: fmt.Sprintf("%d|%s", pull.Index, pull.Title),
RepoID: repo.ID,
RepoUserName: repo.Owner.Name,
RepoName: repo.Name,
IsPrivate: repo.IsPrivate,
}); err != nil {
log.Error(4, "NotifyWatchers: %v", err)
} else if err = pull.MailParticipants(); err != nil {
log.Error(4, "MailParticipants: %v", err)
}
pr.Issue = pull
pull.PullRequest = pr
if err = PrepareWebhooks(repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
Action: api.HOOK_ISSUE_OPENED,
Index: pull.Index,
PullRequest: pr.APIFormat(),
Repository: repo.APIFormat(nil),
Sender: pull.Poster.APIFormat(),
}); err != nil {
log.Error(4, "PrepareWebhooks: %v", err)
}
go HookQueue.Add(repo.ID)
return nil
}
@@ -394,9 +478,9 @@ 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=?",
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)
Join("INNER", "issue", "issue.id = pull_request.issue_id").Find(&prs)
}
// GetUnmergedPullRequestsByBaseInfo returnss all pull requests that are open and has not been merged
@@ -408,30 +492,38 @@ func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequ
Join("INNER", "issue", "issue.id=pull_request.issue_id").Find(&prs)
}
// GetPullRequestByID returns a pull request by given ID.
func GetPullRequestByID(id int64) (*PullRequest, error) {
func getPullRequestByID(e Engine, id int64) (*PullRequest, error) {
pr := new(PullRequest)
has, err := x.Id(id).Get(pr)
has, err := e.Id(id).Get(pr)
if err != nil {
return nil, err
} else if !has {
return nil, ErrPullRequestNotExist{id, 0, 0, 0, "", ""}
}
return pr, nil
return pr, pr.loadAttributes(e)
}
// GetPullRequestByIssueID returns pull request by given issue ID.
func GetPullRequestByIssueID(issueID int64) (*PullRequest, error) {
// GetPullRequestByID returns a pull request by given ID.
func GetPullRequestByID(id int64) (*PullRequest, error) {
return getPullRequestByID(x, id)
}
func getPullRequestByIssueID(e Engine, issueID int64) (*PullRequest, error) {
pr := &PullRequest{
IssueID: issueID,
}
has, err := x.Get(pr)
has, err := e.Get(pr)
if err != nil {
return nil, err
} else if !has {
return nil, ErrPullRequestNotExist{0, issueID, 0, 0, "", ""}
}
return pr, nil
return pr, pr.loadAttributes(e)
}
// GetPullRequestByIssueID returns pull request by given issue ID.
func GetPullRequestByIssueID(issueID int64) (*PullRequest, error) {
return getPullRequestByIssueID(x, issueID)
}
// Update updates all fields of pull request.
@@ -446,21 +538,13 @@ func (pr *PullRequest) UpdateCols(cols ...string) error {
return err
}
var PullRequestQueue = NewUniqueQueue(setting.Repository.PullRequestQueueLength)
// UpdatePatch generates and saves a new patch.
func (pr *PullRequest) UpdatePatch() (err error) {
if err = pr.GetHeadRepo(); err != nil {
return fmt.Errorf("GetHeadRepo: %v", err)
} else if pr.HeadRepo == nil {
if pr.HeadRepo == nil {
log.Trace("PullRequest[%d].UpdatePatch: ignored cruppted data", pr.ID)
return nil
}
if err = pr.GetBaseRepo(); err != nil {
return fmt.Errorf("GetBaseRepo: %v", err)
}
headGitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath())
if err != nil {
return fmt.Errorf("OpenRepository: %v", err)
@@ -535,6 +619,45 @@ func (pr *PullRequest) AddToTaskQueue() {
})
}
type PullRequestList []*PullRequest
func (prs PullRequestList) loadAttributes(e Engine) (err error) {
if len(prs) == 0 {
return nil
}
// Load issues
issueIDs := make([]int64, 0, len(prs))
for i := range prs {
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 {
return fmt.Errorf("find issues: %v", err)
}
set := make(map[int64]*Issue)
for i := range issues {
set[issues[i].ID] = issues[i]
}
for i := range prs {
prs[i].Issue = set[prs[i].IssueID]
}
// Load attributes
for i := range prs {
if err = prs[i].loadAttributes(e); err != nil {
return fmt.Errorf("loadAttributes [%d]: %v", prs[i].ID, err)
}
}
return nil
}
func (prs PullRequestList) LoadAttributes() error {
return prs.loadAttributes(x)
}
func addHeadRepoTasks(prs []*PullRequest) {
for _, pr := range prs {
log.Trace("addHeadRepoTasks[%d]: composing new test task", pr.ID)
@@ -552,19 +675,47 @@ func addHeadRepoTasks(prs []*PullRequest) {
// AddTestPullRequestTask adds new test tasks by given head/base repository and head/base branch,
// and generate new patch for testing as needed.
func AddTestPullRequestTask(repoID int64, branch string) {
log.Trace("AddTestPullRequestTask[head_repo_id: %d, head_branch: %s]: finding pull requests", repoID, branch)
func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool) {
log.Trace("AddTestPullRequestTask [head_repo_id: %d, head_branch: %s]: finding pull requests", repoID, branch)
prs, err := GetUnmergedPullRequestsByHeadInfo(repoID, branch)
if err != nil {
log.Error(4, "Find pull requests[head_repo_id: %d, head_branch: %s]: %v", repoID, branch, err)
log.Error(4, "Find pull requests [head_repo_id: %d, head_branch: %s]: %v", repoID, branch, err)
return
}
if isSync {
if err = PullRequestList(prs).LoadAttributes(); err != nil {
log.Error(4, "PullRequestList.LoadAttributes: %v", err)
}
if err == nil {
for _, pr := range prs {
pr.Issue.PullRequest = pr
if err = pr.Issue.LoadAttributes(); err != nil {
log.Error(4, "LoadAttributes: %v", err)
continue
}
if err = PrepareWebhooks(pr.Issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
Action: api.HOOK_ISSUE_SYNCHRONIZED,
Index: pr.Issue.Index,
PullRequest: pr.Issue.PullRequest.APIFormat(),
Repository: pr.Issue.Repo.APIFormat(nil),
Sender: doer.APIFormat(),
}); err != nil {
log.Error(4, "PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
continue
}
go HookQueue.Add(pr.Issue.Repo.ID)
}
}
}
addHeadRepoTasks(prs)
log.Trace("AddTestPullRequestTask[base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch)
log.Trace("AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch)
prs, err = GetUnmergedPullRequestsByBaseInfo(repoID, branch)
if err != nil {
log.Error(4, "Find pull requests[base_repo_id: %d, base_branch: %s]: %v", repoID, branch, err)
log.Error(4, "Find pull requests [base_repo_id: %d, base_branch: %s]: %v", repoID, branch, err)
return
}
for _, pr := range prs {
@@ -606,8 +757,8 @@ func TestPullRequests() {
func(idx int, bean interface{}) error {
pr := bean.(*PullRequest)
if err := pr.GetBaseRepo(); err != nil {
log.Error(3, "GetBaseRepo: %v", err)
if err := pr.LoadAttributes(); err != nil {
log.Error(3, "LoadAttributes: %v", err)
return nil
}
@@ -631,7 +782,7 @@ func TestPullRequests() {
pr, err := GetPullRequestByID(com.StrTo(prID).MustInt64())
if err != nil {
log.Error(4, "GetPullRequestByID[%d]: %v", prID, err)
log.Error(4, "GetPullRequestByID[%s]: %v", prID, err)
continue
} else if err = pr.testPatch(); err != nil {
log.Error(4, "testPatch[%d]: %v", pr.ID, err)

View File

@@ -39,7 +39,9 @@ type Release struct {
}
func (r *Release) BeforeInsert() {
r.CreatedUnix = time.Now().UTC().Unix()
if r.CreatedUnix == 0 {
r.CreatedUnix = time.Now().Unix()
}
}
func (r *Release) AfterSet(colName string, _ xorm.Cell) {
@@ -67,9 +69,12 @@ func createTag(gitRepo *git.Repository, rel *Release) error {
return fmt.Errorf("GetBranchCommit: %v", err)
}
// Trim '--' prefix to prevent command line argument vulnerability
// Trim '--' prefix to prevent command line argument vulnerability.
rel.TagName = strings.TrimPrefix(rel.TagName, "--")
if err = gitRepo.CreateTag(rel.TagName, commit.ID.String()); err != nil {
if strings.Contains(err.Error(), "is not a valid tag name") {
return ErrInvalidTagName{rel.TagName}
}
return err
}
} else {
@@ -78,6 +83,7 @@ func createTag(gitRepo *git.Repository, rel *Release) error {
return fmt.Errorf("GetTagCommit: %v", err)
}
rel.Sha1 = commit.ID.String()
rel.NumCommits, err = commit.CommitsCount()
if err != nil {
return fmt.Errorf("CommitsCount: %v", err)
@@ -172,13 +178,18 @@ func UpdateRelease(gitRepo *git.Repository, rel *Release) (err error) {
return err
}
// DeleteReleaseByID deletes a release and corresponding Git tag by given ID.
func DeleteReleaseByID(id int64) error {
// DeleteReleaseOfRepoByID deletes a release and corresponding Git tag by given ID.
func DeleteReleaseOfRepoByID(repoID, id int64) error {
rel, err := GetReleaseByID(id)
if err != nil {
return fmt.Errorf("GetReleaseByID: %v", err)
}
// Mark sure the delete operation againsts same repository.
if repoID != rel.RepoID {
return nil
}
repo, err := GetRepositoryByID(rel.RepoID)
if err != nil {
return fmt.Errorf("GetRepositoryByID: %v", err)

File diff suppressed because it is too large Load Diff

View File

@@ -29,11 +29,11 @@ func (c *Collaboration) ModeI18nKey() string {
}
}
// AddCollaborator adds new collaboration relation between an individual and a repository.
// AddCollaborator adds new collaboration to a repository with default access mode.
func (repo *Repository) AddCollaborator(u *User) error {
collaboration := &Collaboration{
RepoID: repo.ID,
UserID: u.Id,
UserID: u.ID,
}
has, err := x.Get(collaboration)
@@ -120,6 +120,9 @@ func (repo *Repository) ChangeCollaborationAccessMode(uid int64, mode AccessMode
return nil
}
if collaboration.Mode == mode {
return nil
}
collaboration.Mode = mode
sess := x.NewSession()

520
models/repo_editor.go Normal file
View File

@@ -0,0 +1,520 @@
// Copyright 2016 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 models
import (
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"os"
"os/exec"
"path"
"path/filepath"
"time"
"github.com/Unknwon/com"
gouuid "github.com/satori/go.uuid"
log "gopkg.in/clog.v1"
git "github.com/gogits/git-module"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
)
// ___________ .___.__ __ ___________.__.__
// \_ _____/ __| _/|__|/ |_ \_ _____/|__| | ____
// | __)_ / __ | | \ __\ | __) | | | _/ __ \
// | \/ /_/ | | || | | \ | | |_\ ___/
// /_______ /\____ | |__||__| \___ / |__|____/\___ >
// \/ \/ \/ \/
// discardLocalRepoBranchChanges discards local commits/changes of
// given branch to make sure it is even to remote branch.
func discardLocalRepoBranchChanges(localPath, branch string) error {
if !com.IsExist(localPath) {
return nil
}
// No need to check if nothing in the repository.
if !git.IsBranchExist(localPath, branch) {
return nil
}
refName := "origin/" + branch
if err := git.ResetHEAD(localPath, true, refName); err != nil {
return fmt.Errorf("git reset --hard %s: %v", refName, err)
}
return nil
}
func (repo *Repository) DiscardLocalRepoBranchChanges(branch string) error {
return discardLocalRepoBranchChanges(repo.LocalCopyPath(), branch)
}
// checkoutNewBranch checks out to a new branch from the a branch name.
func checkoutNewBranch(repoPath, localPath, oldBranch, newBranch string) error {
if err := git.Checkout(localPath, git.CheckoutOptions{
Timeout: time.Duration(setting.Git.Timeout.Pull) * time.Second,
Branch: newBranch,
OldBranch: oldBranch,
}); err != nil {
return fmt.Errorf("git checkout -b %s %s: %v", newBranch, oldBranch, err)
}
return nil
}
func (repo *Repository) CheckoutNewBranch(oldBranch, newBranch string) error {
return checkoutNewBranch(repo.RepoPath(), repo.LocalCopyPath(), oldBranch, newBranch)
}
type UpdateRepoFileOptions struct {
LastCommitID string
OldBranch string
NewBranch string
OldTreeName string
NewTreeName string
Message string
Content string
IsNewFile bool
}
// UpdateRepoFile adds or updates a file in repository.
func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (err error) {
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
if err = repo.DiscardLocalRepoBranchChanges(opts.OldBranch); err != nil {
return fmt.Errorf("DiscardLocalRepoBranchChanges [branch: %s]: %v", opts.OldBranch, err)
} else if err = repo.UpdateLocalCopyBranch(opts.OldBranch); err != nil {
return fmt.Errorf("UpdateLocalCopyBranch [branch: %s]: %v", opts.OldBranch, err)
}
if opts.OldBranch != opts.NewBranch {
if err := repo.CheckoutNewBranch(opts.OldBranch, opts.NewBranch); err != nil {
return fmt.Errorf("CheckoutNewBranch [old_branch: %s, new_branch: %s]: %v", opts.OldBranch, opts.NewBranch, err)
}
}
localPath := repo.LocalCopyPath()
oldFilePath := path.Join(localPath, opts.OldTreeName)
filePath := path.Join(localPath, opts.NewTreeName)
os.MkdirAll(path.Dir(filePath), os.ModePerm)
// If it's meant to be a new file, make sure it doesn't exist.
if opts.IsNewFile {
if com.IsExist(filePath) {
return ErrRepoFileAlreadyExist{filePath}
}
}
// Ignore move step if it's a new file under a directory.
// Otherwise, move the file when name changed.
if com.IsFile(oldFilePath) && opts.OldTreeName != opts.NewTreeName {
if err = git.MoveFile(localPath, opts.OldTreeName, opts.NewTreeName); err != nil {
return fmt.Errorf("git mv %s %s: %v", opts.OldTreeName, opts.NewTreeName, err)
}
}
if err = ioutil.WriteFile(filePath, []byte(opts.Content), 0666); err != nil {
return fmt.Errorf("WriteFile: %v", err)
}
if err = git.AddChanges(localPath, true); err != nil {
return fmt.Errorf("git add --all: %v", err)
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
Committer: doer.NewGitSig(),
Message: opts.Message,
}); err != nil {
return fmt.Errorf("CommitChanges: %v", err)
} else if err = git.Push(localPath, "origin", opts.NewBranch); err != nil {
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
}
gitRepo, err := git.OpenRepository(repo.RepoPath())
if err != nil {
log.Error(4, "OpenRepository: %v", err)
return nil
}
commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
if err != nil {
log.Error(4, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
return nil
}
// Simulate push event.
pushCommits := &PushCommits{
Len: 1,
Commits: []*PushCommit{CommitToPushCommit(commit)},
}
oldCommitID := opts.LastCommitID
if opts.NewBranch != opts.OldBranch {
oldCommitID = git.EMPTY_SHA
}
if err := CommitRepoAction(CommitRepoActionOptions{
PusherName: doer.Name,
RepoOwnerID: repo.MustOwner().ID,
RepoName: repo.Name,
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
OldCommitID: oldCommitID,
NewCommitID: commit.ID.String(),
Commits: pushCommits,
}); err != nil {
log.Error(4, "CommitRepoAction: %v", err)
return nil
}
return nil
}
// GetDiffPreview produces and returns diff result of a file which is not yet committed.
func (repo *Repository) GetDiffPreview(branch, treePath, content string) (diff *Diff, err error) {
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
if err = repo.DiscardLocalRepoBranchChanges(branch); err != nil {
return nil, fmt.Errorf("DiscardLocalRepoBranchChanges [branch: %s]: %v", branch, err)
} else if err = repo.UpdateLocalCopyBranch(branch); err != nil {
return nil, fmt.Errorf("UpdateLocalCopyBranch [branch: %s]: %v", branch, err)
}
localPath := repo.LocalCopyPath()
filePath := path.Join(localPath, treePath)
os.MkdirAll(filepath.Dir(filePath), os.ModePerm)
if err = ioutil.WriteFile(filePath, []byte(content), 0666); err != nil {
return nil, fmt.Errorf("WriteFile: %v", err)
}
cmd := exec.Command("git", "diff", treePath)
cmd.Dir = localPath
cmd.Stderr = os.Stderr
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("StdoutPipe: %v", err)
}
if err = cmd.Start(); err != nil {
return nil, fmt.Errorf("Start: %v", err)
}
pid := process.Add(fmt.Sprintf("GetDiffPreview [repo_path: %s]", repo.RepoPath()), cmd)
defer process.Remove(pid)
diff, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdout)
if err != nil {
return nil, fmt.Errorf("ParsePatch: %v", err)
}
if err = cmd.Wait(); err != nil {
return nil, fmt.Errorf("Wait: %v", err)
}
return diff, nil
}
// ________ .__ __ ___________.__.__
// \______ \ ____ | | _____/ |_ ____ \_ _____/|__| | ____
// | | \_/ __ \| | _/ __ \ __\/ __ \ | __) | | | _/ __ \
// | ` \ ___/| |_\ ___/| | \ ___/ | \ | | |_\ ___/
// /_______ /\___ >____/\___ >__| \___ > \___ / |__|____/\___ >
// \/ \/ \/ \/ \/ \/
//
type DeleteRepoFileOptions struct {
LastCommitID string
OldBranch string
NewBranch string
TreePath string
Message string
}
func (repo *Repository) DeleteRepoFile(doer *User, opts DeleteRepoFileOptions) (err error) {
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
if err = repo.DiscardLocalRepoBranchChanges(opts.OldBranch); err != nil {
return fmt.Errorf("DiscardLocalRepoBranchChanges [branch: %s]: %v", opts.OldBranch, err)
} else if err = repo.UpdateLocalCopyBranch(opts.OldBranch); err != nil {
return fmt.Errorf("UpdateLocalCopyBranch [branch: %s]: %v", opts.OldBranch, err)
}
if opts.OldBranch != opts.NewBranch {
if err := repo.CheckoutNewBranch(opts.OldBranch, opts.NewBranch); err != nil {
return fmt.Errorf("CheckoutNewBranch [old_branch: %s, new_branch: %s]: %v", opts.OldBranch, opts.NewBranch, err)
}
}
localPath := repo.LocalCopyPath()
if err = os.Remove(path.Join(localPath, opts.TreePath)); err != nil {
return fmt.Errorf("Remove: %v", err)
}
if err = git.AddChanges(localPath, true); err != nil {
return fmt.Errorf("git add --all: %v", err)
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
Committer: doer.NewGitSig(),
Message: opts.Message,
}); err != nil {
return fmt.Errorf("CommitChanges: %v", err)
} else if err = git.Push(localPath, "origin", opts.NewBranch); err != nil {
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
}
gitRepo, err := git.OpenRepository(repo.RepoPath())
if err != nil {
log.Error(4, "OpenRepository: %v", err)
return nil
}
commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
if err != nil {
log.Error(4, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
return nil
}
// Simulate push event.
pushCommits := &PushCommits{
Len: 1,
Commits: []*PushCommit{CommitToPushCommit(commit)},
}
if err := CommitRepoAction(CommitRepoActionOptions{
PusherName: doer.Name,
RepoOwnerID: repo.MustOwner().ID,
RepoName: repo.Name,
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
OldCommitID: opts.LastCommitID,
NewCommitID: commit.ID.String(),
Commits: pushCommits,
}); err != nil {
log.Error(4, "CommitRepoAction: %v", err)
return nil
}
return nil
}
// ____ ___ .__ .___ ___________.___.__
// | | \______ | | _________ __| _/ \_ _____/| | | ____ ______
// | | /\____ \| | / _ \__ \ / __ | | __) | | | _/ __ \ / ___/
// | | / | |_> > |_( <_> ) __ \_/ /_/ | | \ | | |_\ ___/ \___ \
// |______/ | __/|____/\____(____ /\____ | \___ / |___|____/\___ >____ >
// |__| \/ \/ \/ \/ \/
//
// Upload represent a uploaded file to a repo to be deleted when moved
type Upload struct {
ID int64 `xorm:"pk autoincr"`
UUID string `xorm:"uuid UNIQUE"`
Name string
}
// UploadLocalPath returns where uploads is stored in local file system based on given UUID.
func UploadLocalPath(uuid string) string {
return path.Join(setting.Repository.Upload.TempPath, uuid[0:1], uuid[1:2], uuid)
}
// LocalPath returns where uploads are temporarily stored in local file system.
func (upload *Upload) LocalPath() string {
return UploadLocalPath(upload.UUID)
}
// NewUpload creates a new upload object.
func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err error) {
upload := &Upload{
UUID: gouuid.NewV4().String(),
Name: name,
}
localPath := upload.LocalPath()
if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
return nil, fmt.Errorf("MkdirAll: %v", err)
}
fw, err := os.Create(localPath)
if err != nil {
return nil, fmt.Errorf("Create: %v", err)
}
defer fw.Close()
if _, err = fw.Write(buf); err != nil {
return nil, fmt.Errorf("Write: %v", err)
} else if _, err = io.Copy(fw, file); err != nil {
return nil, fmt.Errorf("Copy: %v", err)
}
if _, err := x.Insert(upload); err != nil {
return nil, err
}
return upload, nil
}
func GetUploadByUUID(uuid string) (*Upload, error) {
upload := &Upload{UUID: uuid}
has, err := x.Get(upload)
if err != nil {
return nil, err
} else if !has {
return nil, ErrUploadNotExist{0, uuid}
}
return upload, nil
}
func GetUploadsByUUIDs(uuids []string) ([]*Upload, error) {
if len(uuids) == 0 {
return []*Upload{}, nil
}
// Silently drop invalid uuids.
uploads := make([]*Upload, 0, len(uuids))
return uploads, x.In("uuid", uuids).Find(&uploads)
}
func DeleteUploads(uploads ...*Upload) (err error) {
if len(uploads) == 0 {
return nil
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
ids := make([]int64, len(uploads))
for i := 0; i < len(uploads); i++ {
ids[i] = uploads[i].ID
}
if _, err = sess.In("id", ids).Delete(new(Upload)); err != nil {
return fmt.Errorf("delete uploads: %v", err)
}
for _, upload := range uploads {
localPath := upload.LocalPath()
if !com.IsFile(localPath) {
continue
}
if err := os.Remove(localPath); err != nil {
return fmt.Errorf("remove upload: %v", err)
}
}
return sess.Commit()
}
func DeleteUpload(u *Upload) error {
return DeleteUploads(u)
}
func DeleteUploadByUUID(uuid string) error {
upload, err := GetUploadByUUID(uuid)
if err != nil {
if IsErrUploadNotExist(err) {
return nil
}
return fmt.Errorf("GetUploadByUUID: %v", err)
}
if err := DeleteUpload(upload); err != nil {
return fmt.Errorf("DeleteUpload: %v", err)
}
return nil
}
type UploadRepoFileOptions struct {
LastCommitID string
OldBranch string
NewBranch string
TreePath string
Message string
Files []string // In UUID format.
}
func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions) (err error) {
if len(opts.Files) == 0 {
return nil
}
uploads, err := GetUploadsByUUIDs(opts.Files)
if err != nil {
return fmt.Errorf("GetUploadsByUUIDs [uuids: %v]: %v", opts.Files, err)
}
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
if err = repo.DiscardLocalRepoBranchChanges(opts.OldBranch); err != nil {
return fmt.Errorf("DiscardLocalRepoBranchChanges [branch: %s]: %v", opts.OldBranch, err)
} else if err = repo.UpdateLocalCopyBranch(opts.OldBranch); err != nil {
return fmt.Errorf("UpdateLocalCopyBranch [branch: %s]: %v", opts.OldBranch, err)
}
if opts.OldBranch != opts.NewBranch {
if err = repo.CheckoutNewBranch(opts.OldBranch, opts.NewBranch); err != nil {
return fmt.Errorf("CheckoutNewBranch [old_branch: %s, new_branch: %s]: %v", opts.OldBranch, opts.NewBranch, err)
}
}
localPath := repo.LocalCopyPath()
dirPath := path.Join(localPath, opts.TreePath)
os.MkdirAll(dirPath, os.ModePerm)
// Copy uploaded files into repository.
for _, upload := range uploads {
tmpPath := upload.LocalPath()
targetPath := path.Join(dirPath, upload.Name)
if !com.IsFile(tmpPath) {
continue
}
if err = com.Copy(tmpPath, targetPath); err != nil {
return fmt.Errorf("Copy: %v", err)
}
}
if err = git.AddChanges(localPath, true); err != nil {
return fmt.Errorf("git add --all: %v", err)
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
Committer: doer.NewGitSig(),
Message: opts.Message,
}); err != nil {
return fmt.Errorf("CommitChanges: %v", err)
} else if err = git.Push(localPath, "origin", opts.NewBranch); err != nil {
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
}
gitRepo, err := git.OpenRepository(repo.RepoPath())
if err != nil {
log.Error(4, "OpenRepository: %v", err)
return nil
}
commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
if err != nil {
log.Error(4, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
return nil
}
// Simulate push event.
pushCommits := &PushCommits{
Len: 1,
Commits: []*PushCommit{CommitToPushCommit(commit)},
}
if err := CommitRepoAction(CommitRepoActionOptions{
PusherName: doer.Name,
RepoOwnerID: repo.MustOwner().ID,
RepoName: repo.Name,
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
OldCommitID: opts.LastCommitID,
NewCommitID: commit.ID.String(),
Commits: pushCommits,
}); err != nil {
log.Error(4, "CommitRepoAction: %v", err)
return nil
}
return DeleteUploads(uploads...)
}

View File

@@ -5,12 +5,10 @@
package models
import (
"bufio"
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
"math/big"
"os"
@@ -23,18 +21,18 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"golang.org/x/crypto/ssh"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
)
const (
// "### autogenerated by gitgos, DO NOT EDIT\n"
_TPL_PUBLICK_KEY = `command="%s serv key-%d --config='%s'",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n"
)
var sshOpLocker = sync.Mutex{}
var sshOpLocker sync.Mutex
type KeyType int
@@ -43,7 +41,7 @@ const (
KEY_TYPE_DEPLOY
)
// PublicKey represents a SSH or deploy key.
// PublicKey represents a user or deploy SSH public key.
type PublicKey struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"INDEX NOT NULL"`
@@ -62,11 +60,11 @@ type PublicKey struct {
}
func (k *PublicKey) BeforeInsert() {
k.CreatedUnix = time.Now().UTC().Unix()
k.CreatedUnix = time.Now().Unix()
}
func (k *PublicKey) BeforeUpdate() {
k.UpdatedUnix = time.Now().UTC().Unix()
k.UpdatedUnix = time.Now().Unix()
}
func (k *PublicKey) AfterSet(colName string, _ xorm.Cell) {
@@ -80,45 +78,59 @@ func (k *PublicKey) AfterSet(colName string, _ xorm.Cell) {
}
}
// OmitEmail returns content of public key but without e-mail address.
// OmitEmail returns content of public key without email address.
func (k *PublicKey) OmitEmail() string {
return strings.Join(strings.Split(k.Content, " ")[:2], " ")
}
// GetAuthorizedString generates and returns formatted public key string for authorized_keys file.
func (key *PublicKey) GetAuthorizedString() string {
return fmt.Sprintf(_TPL_PUBLICK_KEY, setting.AppPath, key.ID, setting.CustomConf, key.Content)
// AuthorizedString returns formatted public key string for authorized_keys file.
func (k *PublicKey) AuthorizedString() string {
return fmt.Sprintf(_TPL_PUBLICK_KEY, setting.AppPath, k.ID, setting.CustomConf, k.Content)
}
// IsDeployKey returns true if the public key is used as deploy key.
func (k *PublicKey) IsDeployKey() bool {
return k.Type == KEY_TYPE_DEPLOY
}
func extractTypeFromBase64Key(key string) (string, error) {
b, err := base64.StdEncoding.DecodeString(key)
if err != nil || len(b) < 4 {
return "", fmt.Errorf("Invalid key format: %v", err)
return "", fmt.Errorf("invalid key format: %v", err)
}
keyLength := int(binary.BigEndian.Uint32(b))
if len(b) < 4+keyLength {
return "", fmt.Errorf("Invalid key format: not enough length")
return "", fmt.Errorf("invalid key format: not enough length %d", keyLength)
}
return string(b[4 : 4+keyLength]), nil
}
// parseKeyString parses any key string in OpenSSH or SSH2 format to clean OpenSSH string (RFC4253)
// parseKeyString parses any key string in OpenSSH or SSH2 format to clean OpenSSH string (RFC4253).
func parseKeyString(content string) (string, error) {
// Transform all legal line endings to a single "\n"
s := strings.Replace(strings.Replace(strings.TrimSpace(content), "\r\n", "\n", -1), "\r", "\n", -1)
lines := strings.Split(s, "\n")
// Replace all windows full new lines ("\r\n")
content = strings.Replace(content, "\r\n", "\n", -1)
// Replace all windows half new lines ("\r"), if it happen not to match replace above
content = strings.Replace(content, "\r", "\n", -1)
// Replace ending new line as its may cause unwanted behaviour (extra line means not a single line key | OpenSSH key)
content = strings.TrimRight(content, "\n")
// split lines
lines := strings.Split(content, "\n")
var keyType, keyContent, keyComment string
if len(lines) == 1 {
// Parse openssh format
// Parse OpenSSH format.
parts := strings.SplitN(lines[0], " ", 3)
switch len(parts) {
case 0:
return "", errors.New("Empty key")
return "", errors.New("empty key")
case 1:
keyContent = parts[0]
case 2:
@@ -130,17 +142,15 @@ func parseKeyString(content string) (string, error) {
keyComment = parts[2]
}
// If keyType is not given, extract it from content. If given, validate it
// If keyType is not given, extract it from content. If given, validate it.
t, err := extractTypeFromBase64Key(keyContent)
if err != nil {
return "", fmt.Errorf("extractTypeFromBase64Key: %v", err)
}
if len(keyType) == 0 {
if t, err := extractTypeFromBase64Key(keyContent); err == nil {
keyType = t
} else {
return "", err
}
} else {
if t, err := extractTypeFromBase64Key(keyContent); err != nil || keyType != t {
return "", err
}
keyType = t
} else if keyType != t {
return "", fmt.Errorf("key type and content does not match: %s - %s", keyType, t)
}
} else {
// Parse SSH2 file format.
@@ -158,11 +168,11 @@ func parseKeyString(content string) (string, error) {
}
}
if t, err := extractTypeFromBase64Key(keyContent); err == nil {
keyType = t
} else {
return "", err
t, err := extractTypeFromBase64Key(keyContent)
if err != nil {
return "", fmt.Errorf("extractTypeFromBase64Key: %v", err)
}
keyType = t
}
return keyType + " " + keyContent + " " + keyComment, nil
}
@@ -177,7 +187,7 @@ func writeTmpKeyFile(content string) (string, error) {
defer tmpFile.Close()
if _, err = tmpFile.WriteString(content); err != nil {
return "", fmt.Errorf("tmpFile.WriteString: %v", err)
return "", fmt.Errorf("WriteString: %v", err)
}
return tmpFile.Name(), nil
}
@@ -197,7 +207,7 @@ func SSHKeyGenParsePublicKey(key string) (string, int, error) {
stdout, stderr, err := process.Exec("SSHKeyGenParsePublicKey", setting.SSH.KeygenPath, "-lf", tmpName)
if err != nil {
return "", 0, fmt.Errorf("Fail to parse public key: %s - %s", err, stderr)
return "", 0, fmt.Errorf("fail to parse public key: %s - %s", err, stderr)
}
if strings.Contains(stdout, "is not a public key file") {
return "", 0, ErrKeyUnableVerify{stdout}
@@ -205,7 +215,7 @@ func SSHKeyGenParsePublicKey(key string) (string, int, error) {
fields := strings.Split(stdout, " ")
if len(fields) < 4 {
return "", 0, fmt.Errorf("Invalid public key line: %s", stdout)
return "", 0, fmt.Errorf("invalid public key line: %s", stdout)
}
keyType := strings.Trim(fields[len(fields)-1], "()\r\n")
@@ -230,7 +240,7 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
if strings.Contains(err.Error(), "ssh: unknown key algorithm") {
return "", 0, ErrKeyUnableVerify{err.Error()}
}
return "", 0, fmt.Errorf("ssh.ParsePublicKey: %v", err)
return "", 0, fmt.Errorf("ParsePublicKey: %v", err)
}
// The ssh library can parse the key, so next we find out what key exactly we have.
@@ -262,15 +272,14 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
return "ecdsa", 384, nil
case ssh.KeyAlgoECDSA521:
return "ecdsa", 521, nil
case "ssh-ed25519": // TODO replace with ssh constant when available
case "ssh-ed25519": // TODO: replace with ssh constant when available
return "ed25519", 256, nil
}
return "", 0, fmt.Errorf("Unsupported key length detection for type: %s", pkey.Type())
return "", 0, fmt.Errorf("unsupported key length detection for type: %s", pkey.Type())
}
// CheckPublicKeyString checks if the given public key string is recognized by SSH.
//
// The function returns the actual public key line on success.
// It returns the actual public key line on success.
func CheckPublicKeyString(content string) (_ string, err error) {
if setting.SSH.Disabled {
return "", errors.New("SSH is disabled")
@@ -290,16 +299,19 @@ func CheckPublicKeyString(content string) (_ string, err error) {
content = strings.TrimSpace(content)
var (
fnName string
keyType string
length int
)
if setting.SSH.StartBuiltinServer {
fnName = "SSHNativeParsePublicKey"
keyType, length, err = SSHNativeParsePublicKey(content)
} else {
fnName = "SSHKeyGenParsePublicKey"
keyType, length, err = SSHKeyGenParsePublicKey(content)
}
if err != nil {
return "", fmt.Errorf("ParsePublicKey: %v", err)
return "", fmt.Errorf("%s: %v", fnName, err)
}
log.Trace("Key info [native: %v]: %s-%d", setting.SSH.StartBuiltinServer, keyType, length)
@@ -309,13 +321,13 @@ func CheckPublicKeyString(content string) (_ string, err error) {
if minLen, found := setting.SSH.MinimumKeySizes[keyType]; found && length >= minLen {
return content, nil
} else if found && length < minLen {
return "", fmt.Errorf("Key length is not enough: got %d, needs %d", length, minLen)
return "", fmt.Errorf("key length is not enough: got %d, needs %d", length, minLen)
}
return "", fmt.Errorf("Key type is not allowed: %s", keyType)
return "", fmt.Errorf("key type is not allowed: %s", keyType)
}
// saveAuthorizedKeyFile writes SSH key content to authorized_keys file.
func saveAuthorizedKeyFile(keys ...*PublicKey) error {
// appendAuthorizedKeysToFile appends new SSH keys' content to authorized_keys file.
func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
@@ -326,13 +338,13 @@ func saveAuthorizedKeyFile(keys ...*PublicKey) error {
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return err
}
// FIXME: following command does not support in Windows.
// Note: chmod command does not support in Windows.
if !setting.IsWindows {
fi, err := f.Stat()
if err != nil {
return err
}
// .ssh directory should have mode 700, and authorized_keys file should have mode 600.
if fi.Mode().Perm() > 0600 {
log.Error(4, "authorized_keys file has unusual permission flags: %s - setting to -rw-------", fi.Mode().Perm().String())
@@ -343,7 +355,7 @@ func saveAuthorizedKeyFile(keys ...*PublicKey) error {
}
for _, key := range keys {
if _, err = f.WriteString(key.GetAuthorizedString()); err != nil {
if _, err = f.WriteString(key.AuthorizedString()); err != nil {
return err
}
}
@@ -373,9 +385,10 @@ func addKey(e Engine, key *PublicKey) (err error) {
if err = ioutil.WriteFile(tmpPath, []byte(key.Content), 0644); err != nil {
return err
}
stdout, stderr, err := process.Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
stdout, stderr, err := process.Exec("AddPublicKey", setting.SSH.KeygenPath, "-lf", tmpPath)
if err != nil {
return fmt.Errorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
return fmt.Errorf("fail to parse public key: %s - %s", err, stderr)
} else if len(stdout) < 2 {
return errors.New("not enough output for calculating fingerprint: " + stdout)
}
@@ -390,7 +403,7 @@ func addKey(e Engine, key *PublicKey) (err error) {
if setting.SSH.StartBuiltinServer {
return nil
}
return saveAuthorizedKeyFile(key)
return appendAuthorizedKeysToFile(key)
}
// AddPublicKey adds new public key to database and authorized_keys file.
@@ -401,7 +414,7 @@ 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 {
@@ -456,62 +469,7 @@ 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)
}
// rewriteAuthorizedKeys finds and deletes corresponding line in authorized_keys file.
func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error {
fr, err := os.Open(p)
if err != nil {
return err
}
defer fr.Close()
fw, err := os.OpenFile(tmpP, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return err
}
defer fw.Close()
isFound := false
keyword := fmt.Sprintf("key-%d", key.ID)
buf := bufio.NewReader(fr)
for {
line, errRead := buf.ReadString('\n')
line = strings.TrimSpace(line)
if errRead != nil {
if errRead != io.EOF {
return errRead
}
// Reached end of file, if nothing to read then break,
// otherwise handle the last line.
if len(line) == 0 {
break
}
}
// Found the line and copy rest of file.
if !isFound && strings.Contains(line, keyword) && strings.Contains(line, key.Content) {
isFound = true
continue
}
// Still finding the line, copy the line that currently read.
if _, err = fw.WriteString(line + "\n"); err != nil {
return err
}
if errRead == io.EOF {
break
}
}
if !isFound {
log.Warn("SSH key %d not found in authorized_keys file for deletion", key.ID)
}
return nil
return keys, x.Where("owner_id = ?", uid).Find(&keys)
}
// UpdatePublicKey updates given public key.
@@ -520,35 +478,14 @@ func UpdatePublicKey(key *PublicKey) error {
return err
}
func deletePublicKey(e *xorm.Session, keyID int64) error {
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
key := &PublicKey{ID: keyID}
has, err := e.Get(key)
if err != nil {
return err
} else if !has {
// deletePublicKeys does the actual key deletion but does not update authorized_keys file.
func deletePublicKeys(e *xorm.Session, keyIDs ...int64) error {
if len(keyIDs) == 0 {
return nil
}
if _, err = e.Id(key.ID).Delete(new(PublicKey)); err != nil {
return err
}
// Don't need to rewrite this file if builtin SSH server is enabled.
if setting.SSH.StartBuiltinServer {
return nil
}
fpath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
tmpPath := fpath + ".tmp"
if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil {
return err
} else if err = os.Remove(fpath); err != nil {
return err
}
return os.Rename(tmpPath, fpath)
_, err := e.In("id", strings.Join(base.Int64sToStrings(keyIDs), ",")).Delete(new(PublicKey))
return err
}
// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
@@ -562,8 +499,8 @@ func DeletePublicKey(doer *User, id int64) (err error) {
}
// Check if user has access to delete this key.
if !doer.IsAdmin && doer.Id != key.OwnerID {
return ErrKeyAccessDenied{doer.Id, key.ID, "public"}
if !doer.IsAdmin && doer.ID != key.OwnerID {
return ErrKeyAccessDenied{doer.ID, key.ID, "public"}
}
sess := x.NewSession()
@@ -572,14 +509,20 @@ func DeletePublicKey(doer *User, id int64) (err error) {
return err
}
if err = deletePublicKey(sess, id); err != nil {
if err = deletePublicKeys(sess, id); err != nil {
return err
}
return sess.Commit()
if err = sess.Commit(); err != nil {
return err
}
return RewriteAllPublicKeys()
}
// RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again.
// Note: x.Iterate does not get latest data after insert/delete, so we have to call this function
// outsite any session scope independently.
func RewriteAllPublicKeys() error {
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
@@ -593,7 +536,7 @@ func RewriteAllPublicKeys() error {
defer os.Remove(tmpPath)
err = x.Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) {
_, err = f.WriteString((bean.(*PublicKey)).GetAuthorizedString())
_, err = f.WriteString((bean.(*PublicKey)).AuthorizedString())
return err
})
f.Close()
@@ -638,11 +581,11 @@ type DeployKey struct {
}
func (k *DeployKey) BeforeInsert() {
k.CreatedUnix = time.Now().UTC().Unix()
k.CreatedUnix = time.Now().Unix()
}
func (k *DeployKey) BeforeUpdate() {
k.UpdatedUnix = time.Now().UTC().Unix()
k.UpdatedUnix = time.Now().Unix()
}
func (k *DeployKey) AfterSet(colName string, _ xorm.Cell) {
@@ -668,14 +611,14 @@ func (k *DeployKey) GetContent() error {
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 {
@@ -703,7 +646,7 @@ 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
}
@@ -797,7 +740,7 @@ func DeleteDeployKey(doer *User, id int64) error {
if err != nil {
return fmt.Errorf("HasAccess: %v", err)
} else if !yes {
return ErrKeyAccessDenied{doer.Id, key.ID, "deploy"}
return ErrKeyAccessDenied{doer.ID, key.ID, "deploy"}
}
}
@@ -808,15 +751,15 @@ func DeleteDeployKey(doer *User, id int64) error {
}
if _, err = sess.Id(key.ID).Delete(new(DeployKey)); err != nil {
return fmt.Errorf("delete deploy key[%d]: %v", key.ID, err)
return fmt.Errorf("delete deploy key [%d]: %v", key.ID, err)
}
// 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 {
if err = deletePublicKey(sess, key.KeyID); err != nil {
if err = deletePublicKeys(sess, key.KeyID); err != nil {
return err
}
}
@@ -827,5 +770,5 @@ 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

@@ -1,7 +1,12 @@
// Copyright 2016 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 models
import (
"fmt"
"strings"
"testing"
. "github.com/smartystreets/goconvey/convey"
@@ -24,7 +29,7 @@ func Test_SSHParsePublicKey(t *testing.T) {
"rsa-2048": {"rsa", 2048, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMZXh+1OBUwSH9D45wTaxErQIN9IoC9xl7MKJkqvTvv6O5RR9YW/IK9FbfjXgXsppYGhsCZo1hFOOsXHMnfOORqu/xMDx4yPuyvKpw4LePEcg4TDipaDFuxbWOqc/BUZRZcXu41QAWfDLrInwsltWZHSeG7hjhpacl4FrVv9V1pS6Oc5Q1NxxEzTzuNLS/8diZrTm/YAQQ/+B+mzWI3zEtF4miZjjAljWd1LTBPvU23d29DcBmmFahcZ441XZsTeAwGxG/Q6j8NgNXj9WxMeWwxXV2jeAX/EBSpZrCVlCQ1yJswT6xCp8TuBnTiGWYMBNTbOZvPC4e0WI2/yZW/s5F nocomment"},
"ecdsa-256": {"ecdsa", 256, "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFQacN3PrOll7PXmN5B/ZNVahiUIqI05nbBlZk1KXsO3d06ktAWqbNflv2vEmA38bTFTfJ2sbn2B5ksT52cDDbA= nocomment"},
"ecdsa-384": {"ecdsa", 384, "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBINmioV+XRX1Fm9Qk2ehHXJ2tfVxW30ypUWZw670Zyq5GQfBAH6xjygRsJ5wWsHXBsGYgFUXIHvMKVAG1tpw7s6ax9oA+dJOJ7tj+vhn8joFqT+sg3LYHgZkHrfqryRasQ== nocomment"},
"ecdsa-521": {"ecdsa", 521, "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACGt3UG3EzRwNOI17QR84l6PgiAcvCE7v6aXPj/SC6UWKg4EL8vW9ZBcdYL9wzs4FZXh4MOV8jAzu3KRWNTwb4k2wFNUpGOt7l28MztFFEtH5BDDrtAJSPENPy8pvPLMfnPg5NhvWycqIBzNcHipem5wSJFN5PdpNOC2xMrPWKNqj+ZjQ== nocomment"},
// "ecdsa-521": {"ecdsa", 521, "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACGt3UG3EzRwNOI17QR84l6PgiAcvCE7v6aXPj/SC6UWKg4EL8vW9ZBcdYL9wzs4FZXh4MOV8jAzu3KRWNTwb4k2wFNUpGOt7l28MztFFEtH5BDDrtAJSPENPy8pvPLMfnPg5NhvWycqIBzNcHipem5wSJFN5PdpNOC2xMrPWKNqj+ZjQ== nocomment"},
}
Convey("Parse public keys in both native and ssh-keygen", t, func() {
@@ -37,7 +42,13 @@ func Test_SSHParsePublicKey(t *testing.T) {
So(lengthN, ShouldEqual, key.length)
keyTypeK, lengthK, errK := SSHKeyGenParsePublicKey(key.content)
So(errK, ShouldBeNil)
if errK != nil {
// Some server just does not support ecdsa format.
if strings.Contains(errK.Error(), "line 1 too long:") {
continue
}
So(errK, ShouldBeNil)
}
So(keyTypeK, ShouldEqual, key.typeName)
So(lengthK, ShouldEqual, key.length)
}

View File

@@ -29,11 +29,11 @@ type AccessToken struct {
}
func (t *AccessToken) BeforeInsert() {
t.CreatedUnix = time.Now().UTC().Unix()
t.CreatedUnix = time.Now().Unix()
}
func (t *AccessToken) BeforeUpdate() {
t.UpdatedUnix = time.Now().UTC().Unix()
t.UpdatedUnix = time.Now().Unix()
}
func (t *AccessToken) AfterSet(colName string, _ xorm.Cell) {
@@ -81,8 +81,11 @@ func UpdateAccessToken(t *AccessToken) error {
return err
}
// DeleteAccessTokenByID deletes access token by given ID.
func DeleteAccessTokenByID(id int64) error {
_, err := x.Id(id).Delete(new(AccessToken))
// DeleteAccessTokenOfUserByID deletes access token by given ID.
func DeleteAccessTokenOfUserByID(userID, id int64) error {
_, err := x.Delete(&AccessToken{
ID: id,
UID: userID,
})
return err
}

View File

@@ -10,9 +10,9 @@ import (
"os/exec"
"strings"
git "github.com/gogits/git-module"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/log"
git "github.com/gogits/git-module"
)
type UpdateTask struct {
@@ -47,6 +47,19 @@ func DeleteUpdateTaskByUUID(uuid string) error {
return err
}
// CommitToPushCommit transforms a git.Commit to PushCommit type.
func CommitToPushCommit(commit *git.Commit) *PushCommit {
return &PushCommit{
Sha1: commit.ID.String(),
Message: commit.Message(),
AuthorEmail: commit.Author.Email,
AuthorName: commit.Author.Name,
CommitterEmail: commit.Committer.Email,
CommitterName: commit.Committer.Name,
Timestamp: commit.Committer.When,
}
}
func ListToPushCommits(l *list.List) *PushCommits {
commits := make([]*PushCommit, 0)
var actEmail string
@@ -55,33 +68,28 @@ func ListToPushCommits(l *list.List) *PushCommits {
if actEmail == "" {
actEmail = commit.Committer.Email
}
commits = append(commits,
&PushCommit{commit.ID.String(),
commit.Message(),
commit.Author.Email,
commit.Author.Name,
})
commits = append(commits, CommitToPushCommit(commit))
}
return &PushCommits{l.Len(), commits, "", nil}
}
type PushUpdateOptions struct {
RefName string
OldCommitID string
NewCommitID string
PusherID int64
PusherName string
RepoUserName string
RepoName string
RefFullName string
OldCommitID string
NewCommitID string
}
// PushUpdate must be called for any push actions in order to
// generates necessary push action history feeds.
func PushUpdate(opts PushUpdateOptions) (err error) {
isNewRef := strings.HasPrefix(opts.OldCommitID, "0000000")
isDelRef := strings.HasPrefix(opts.NewCommitID, "0000000")
isNewRef := opts.OldCommitID == git.EMPTY_SHA
isDelRef := opts.NewCommitID == git.EMPTY_SHA
if isNewRef && isDelRef {
return fmt.Errorf("Old and new revisions both start with 000000")
return fmt.Errorf("Old and new revisions are both %s", git.EMPTY_SHA)
}
repoPath := RepoPath(opts.RepoUserName, opts.RepoName)
@@ -93,8 +101,8 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
}
if isDelRef {
log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %d",
opts.RefName, opts.RepoUserName, opts.RepoName, opts.PusherName)
log.Trace("Reference '%s' has been deleted from '%s/%s' by %s",
opts.RefFullName, opts.RepoUserName, opts.RepoName, opts.PusherName)
return nil
}
@@ -103,41 +111,30 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
return fmt.Errorf("OpenRepository: %v", err)
}
repoUser, err := GetUserByName(opts.RepoUserName)
owner, err := GetUserByName(opts.RepoUserName)
if err != nil {
return fmt.Errorf("GetUserByName: %v", err)
}
repo, err := GetRepositoryByName(repoUser.Id, opts.RepoName)
repo, err := GetRepositoryByName(owner.ID, opts.RepoName)
if err != nil {
return fmt.Errorf("GetRepositoryByName: %v", err)
}
// Push tags.
if strings.HasPrefix(opts.RefName, "refs/tags/") {
tag, err := gitRepo.GetTag(git.RefEndName(opts.RefName))
if err != nil {
return fmt.Errorf("gitRepo.GetTag: %v", err)
}
// When tagger isn't available, fall back to get committer email.
var actEmail string
if tag.Tagger != nil {
actEmail = tag.Tagger.Email
} else {
cmt, err := tag.Commit()
if err != nil {
return fmt.Errorf("tag.Commit: %v", err)
}
actEmail = cmt.Committer.Email
}
commit := &PushCommits{}
if err = CommitRepoAction(opts.PusherID, repoUser.Id, opts.PusherName, actEmail,
repo.ID, opts.RepoUserName, opts.RepoName, opts.RefName, commit, opts.OldCommitID, opts.NewCommitID); err != nil {
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
if err := CommitRepoAction(CommitRepoActionOptions{
PusherName: opts.PusherName,
RepoOwnerID: owner.ID,
RepoName: repo.Name,
RefFullName: opts.RefFullName,
OldCommitID: opts.OldCommitID,
NewCommitID: opts.NewCommitID,
Commits: &PushCommits{},
}); err != nil {
return fmt.Errorf("CommitRepoAction (tag): %v", err)
}
return err
return nil
}
newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
@@ -159,9 +156,15 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
}
}
if err = CommitRepoAction(opts.PusherID, repoUser.Id, opts.PusherName, repoUser.Email,
repo.ID, opts.RepoUserName, opts.RepoName, opts.RefName, ListToPushCommits(l),
opts.OldCommitID, opts.NewCommitID); err != nil {
if err := CommitRepoAction(CommitRepoActionOptions{
PusherName: opts.PusherName,
RepoOwnerID: owner.ID,
RepoName: repo.Name,
RefFullName: opts.RefFullName,
OldCommitID: opts.OldCommitID,
NewCommitID: opts.NewCommitID,
Commits: ListToPushCommits(l),
}); err != nil {
return fmt.Errorf("CommitRepoAction (branch): %v", err)
}
return nil

View File

@@ -8,27 +8,30 @@ import (
"bytes"
"container/list"
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
"errors"
"fmt"
"image"
"image/jpeg"
_ "image/jpeg"
"image/png"
"os"
"path/filepath"
"strings"
"time"
"unicode/utf8"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/nfnt/resize"
"golang.org/x/crypto/pbkdf2"
log "gopkg.in/clog.v1"
"github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client"
"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"
)
@@ -45,14 +48,13 @@ var (
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")
ErrLoginSourceNotExist = errors.New("Login source does not exist")
ErrLoginSourceNotActived = errors.New("Login source is not actived")
ErrUnsupportedLoginType = errors.New("Login source is unknown")
)
// User represents the object of individual and member of organization.
type User struct {
Id int64
ID int64 `xorm:"pk autoincr"`
LowerName string `xorm:"UNIQUE NOT NULL"`
Name string `xorm:"UNIQUE NOT NULL"`
FullName string
@@ -108,7 +110,7 @@ type User struct {
}
func (u *User) BeforeInsert() {
u.CreatedUnix = time.Now().UTC().Unix()
u.CreatedUnix = time.Now().Unix()
u.UpdatedUnix = u.CreatedUnix
}
@@ -116,7 +118,7 @@ func (u *User) BeforeUpdate() {
if u.MaxRepoCreation < -1 {
u.MaxRepoCreation = -1
}
u.UpdatedUnix = time.Now().UTC().Unix()
u.UpdatedUnix = time.Now().Unix()
}
func (u *User) AfterSet(colName string, _ xorm.Cell) {
@@ -130,6 +132,16 @@ func (u *User) AfterSet(colName string, _ xorm.Cell) {
}
}
func (u *User) APIFormat() *api.User {
return &api.User{
ID: u.ID,
UserName: u.Name,
FullName: u.FullName,
Email: u.Email,
AvatarUrl: u.AvatarLink(),
}
}
// returns true if user login type is LOGIN_PLAIN.
func (u *User) IsLocal() bool {
return u.LoginType <= LOGIN_PLAIN
@@ -137,7 +149,7 @@ func (u *User) IsLocal() bool {
// HasForkedRepo checks if user has already forked a repository with given ID.
func (u *User) HasForkedRepo(repoID int64) bool {
_, has := HasForkedRepo(u.Id, repoID)
_, has := HasForkedRepo(u.ID, repoID)
return has
}
@@ -158,6 +170,10 @@ func (u *User) CanCreateRepo() bool {
return u.NumRepos < u.MaxRepoCreation
}
func (u *User) CanCreateOrganization() bool {
return !setting.Admin.DisableRegularOrgCreation || u.IsAdmin
}
// CanEditGitHook returns true if user can edit Git hooks.
func (u *User) CanEditGitHook() bool {
return u.IsAdmin || u.AllowGitHook
@@ -165,7 +181,7 @@ func (u *User) CanEditGitHook() bool {
// CanImportLocal returns true if user can migrate repository by local path.
func (u *User) CanImportLocal() bool {
return u.IsAdmin || u.AllowImportLocal
return setting.Repository.EnableLocalPathMigration && (u.IsAdmin || u.AllowImportLocal)
}
// DashboardLink returns the user dashboard page link.
@@ -181,10 +197,14 @@ func (u *User) HomeLink() string {
return setting.AppSubUrl + "/" + u.Name
}
func (u *User) HTMLURL() string {
return setting.AppUrl + u.Name
}
// GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
func (u *User) GenerateEmailActivateCode(email string) string {
code := base.CreateTimeLimitCode(
com.ToStr(u.Id)+email+u.LowerName+u.Passwd+u.Rands,
com.ToStr(u.ID)+email+u.LowerName+u.Passwd+u.Rands,
setting.Service.ActiveCodeLives, nil)
// Add tail hex username
@@ -199,7 +219,7 @@ func (u *User) GenerateActivateCode() string {
// CustomAvatarPath returns user custom avatar file path.
func (u *User) CustomAvatarPath() string {
return filepath.Join(setting.AvatarUploadPath, com.ToStr(u.Id))
return filepath.Join(setting.AvatarUploadPath, com.ToStr(u.ID))
}
// GenerateRandomAvatar generates a random avatar for user.
@@ -222,17 +242,20 @@ func (u *User) GenerateRandomAvatar() error {
}
defer fw.Close()
if err = jpeg.Encode(fw, img, nil); err != nil {
if err = png.Encode(fw, img); err != nil {
return fmt.Errorf("Encode: %v", err)
}
log.Info("New random avatar created: %d", u.Id)
log.Info("New random avatar created: %d", u.ID)
return nil
}
// RelAvatarLink returns relative avatar link to the site domain,
// 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 := "/img/avatar_default.png"
if u.Id == -1 {
defaultImgUrl := setting.AppSubUrl + "/img/avatar_default.png"
if u.ID == -1 {
return defaultImgUrl
}
@@ -241,7 +264,7 @@ func (u *User) RelAvatarLink() string {
if !com.IsExist(u.CustomAvatarPath()) {
return defaultImgUrl
}
return "/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 {
@@ -249,16 +272,16 @@ func (u *User) RelAvatarLink() string {
}
}
return "/avatars/" + com.ToStr(u.Id)
return setting.AppSubUrl + "/avatars/" + com.ToStr(u.ID)
}
return setting.GravatarSource + u.Avatar
return base.AvatarLink(u.AvatarEmail)
}
// AvatarLink returns user avatar link.
// AvatarLink returns user avatar absolute link.
func (u *User) AvatarLink() string {
link := u.RelAvatarLink()
if link[0] == '/' && link[1] != '/' {
return strings.TrimSuffix(setting.AppUrl, "/") + link
return setting.AppUrl + strings.TrimPrefix(link, setting.AppSubUrl)[1:]
}
return link
}
@@ -266,7 +289,7 @@ func (u *User) AvatarLink() string {
// User.GetFollwoers 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 {
@@ -276,13 +299,13 @@ func (u *User) GetFollowers(page int) ([]*User, error) {
}
func (u *User) IsFollowing(followID int64) bool {
return IsFollowing(u.Id, followID)
return IsFollowing(u.ID, followID)
}
// 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 {
@@ -294,7 +317,7 @@ func (u *User) GetFollowing(page int) ([]*User, error) {
// NewGitSig generates and returns the signature of given user.
func (u *User) NewGitSig() *git.Signature {
return &git.Signature{
Name: u.Name,
Name: u.DisplayName(),
Email: u.Email,
When: time.Now(),
}
@@ -302,7 +325,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)
}
@@ -310,7 +333,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.
@@ -321,7 +344,7 @@ func (u *User) UploadAvatar(data []byte) error {
return fmt.Errorf("Decode: %v", err)
}
m := resize.Resize(290, 290, img, resize.NearestNeighbor)
m := resize.Resize(avatar.AVATAR_SIZE, avatar.AVATAR_SIZE, img, resize.NearestNeighbor)
sess := x.NewSession()
defer sessionRelease(sess)
@@ -350,7 +373,7 @@ 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())
log.Trace("DeleteAvatar[%d]: %s", u.ID, u.CustomAvatarPath())
os.Remove(u.CustomAvatarPath())
u.UseCustomAvatar = false
@@ -385,16 +408,16 @@ func (u *User) IsOrganization() bool {
// 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)
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)
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.
@@ -402,21 +425,31 @@ func (u *User) GetOrganizationCount() (int64, error) {
return u.getOrganizationCount(x)
}
// GetRepositories returns all repositories that user owns, including private repositories.
func (u *User) GetRepositories() (err error) {
u.Repos, err = GetRepositories(u.Id, true)
// GetRepositories returns repositories that user owns, including private repositories.
func (u *User) GetRepositories(page, pageSize int) (err error) {
u.Repos, err = GetUserRepositories(&UserRepoOptions{
UserID: u.ID,
Private: true,
Page: page,
PageSize: pageSize,
})
return err
}
// GetRepositories returns mirror repositories that user owns, including private repositories.
func (u *User) GetMirrorRepositories() ([]*Repository, error) {
return GetUserMirrorRepositories(u.ID)
}
// GetOwnedOrganizations returns all organizations that user owns.
func (u *User) GetOwnedOrganizations() (err error) {
u.OwnedOrgs, err = GetOwnedOrgsByUserID(u.Id)
u.OwnedOrgs, err = GetOwnedOrgsByUserID(u.ID)
return err
}
// GetOrganizations returns all organizations that user belongs to.
func (u *User) GetOrganizations(all bool) error {
ous, err := GetOrgUsersByUserID(u.Id, all)
ous, err := GetOrgUsersByUserID(u.ID, all)
if err != nil {
return err
}
@@ -444,6 +477,12 @@ func (u *User) ShortName(length int) string {
return base.EllipsisString(u.Name, length)
}
// IsMailable checks if a user is elegible
// to receive emails.
func (u *User) IsMailable() bool {
return u.IsActive
}
// IsUserExist checks if given user name exist,
// the user name should be noncased unique.
// If uid is presented, then check will rule out that one,
@@ -456,22 +495,56 @@ func IsUserExist(uid int64, name string) (bool, error) {
}
// GetUserSalt returns a ramdom user salt token.
func GetUserSalt() string {
func GetUserSalt() (string, error) {
return base.GetRandomString(10)
}
// NewFakeUser creates and returns a fake user for someone has deleted his/her account.
func NewFakeUser() *User {
// NewGhostUser creates and returns a fake user for someone has deleted his/her account.
func NewGhostUser() *User {
return &User{
Id: -1,
Name: "Someone",
LowerName: "someone",
ID: -1,
Name: "Ghost",
LowerName: "ghost",
}
}
var (
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 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))
if utf8.RuneCountInString(name) == 0 {
return ErrNameEmpty
}
for i := range names {
if name == names[i] {
return ErrNameReserved{name}
}
}
for _, pat := range patterns {
if pat[0] == '*' && strings.HasSuffix(name, pat[1:]) ||
(pat[len(pat)-1] == '*' && strings.HasPrefix(name, pat[:len(pat)-1])) {
return ErrNamePatternNotAllowed{pat}
}
}
return nil
}
func IsUsableUsername(name string) error {
return isUsableName(reservedUsernames, reservedUserPatterns, name)
}
// CreateUser creates record of a new user.
func CreateUser(u *User) (err error) {
if err = IsUsableName(u.Name); err != nil {
if err = IsUsableUsername(u.Name); err != nil {
return err
}
@@ -493,8 +566,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
@@ -554,7 +631,7 @@ func VerifyUserActiveCode(code string) (user *User) {
if user = getVerifyUser(code); user != nil {
// time limit code
prefix := code[:base.TimeLimitCodeLength]
data := com.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
data := com.ToStr(user.ID) + user.Email + user.LowerName + user.Passwd + user.Rands
if base.VerifyTimeLimitCode(data, minutes, prefix) {
return user
@@ -570,7 +647,7 @@ func VerifyActiveEmailCode(code, email string) *EmailAddress {
if user := getVerifyUser(code); user != nil {
// time limit code
prefix := code[:base.TimeLimitCodeLength]
data := com.ToStr(user.Id) + email + user.LowerName + user.Passwd + user.Rands
data := com.ToStr(user.ID) + email + user.LowerName + user.Passwd + user.Rands
if base.VerifyTimeLimitCode(data, minutes, prefix) {
emailAddress := &EmailAddress{Email: email}
@@ -584,7 +661,7 @@ func VerifyActiveEmailCode(code, email string) *EmailAddress {
// ChangeUserName changes all corresponding setting from old user name to new one.
func ChangeUserName(u *User, newUserName string) (err error) {
if err = IsUsableName(newUserName); err != nil {
if err = IsUsableUsername(newUserName); err != nil {
return err
}
@@ -600,7 +677,7 @@ 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 {
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
@@ -615,7 +692,7 @@ 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 {
@@ -634,7 +711,7 @@ func updateUser(e Engine, u *User) error {
u.Description = base.TruncateString(u.Description, 255)
u.FullName = markdown.Sanitizer.Sanitize(u.FullName)
_, err := e.Id(u.Id).AllCols().Update(u)
_, err := e.Id(u.ID).AllCols().Update(u)
return err
}
@@ -663,7 +740,7 @@ func deleteUser(e *xorm.Session, u *User) error {
if err != nil {
return fmt.Errorf("GetRepositoryCount: %v", err)
} else if count > 0 {
return ErrUserOwnRepos{UID: u.Id}
return ErrUserOwnRepos{UID: u.ID}
}
// Check membership of organization.
@@ -671,12 +748,12 @@ func deleteUser(e *xorm.Session, u *User) error {
if err != nil {
return fmt.Errorf("GetOrganizationCount: %v", err)
} else if count > 0 {
return ErrUserHasOrgs{UID: u.Id}
return ErrUserHasOrgs{UID: u.ID}
}
// ***** START: Watch *****
watches := make([]*Watch, 0, 10)
if err = e.Find(&watches, &Watch{UserID: u.Id}); err != nil {
if err = e.Find(&watches, &Watch{UserID: u.ID}); err != nil {
return fmt.Errorf("get all watches: %v", err)
}
for i := range watches {
@@ -688,7 +765,7 @@ func deleteUser(e *xorm.Session, u *User) error {
// ***** START: Star *****
stars := make([]*Star, 0, 10)
if err = e.Find(&stars, &Star{UID: u.Id}); err != nil {
if err = e.Find(&stars, &Star{UID: u.ID}); err != nil {
return fmt.Errorf("get all stars: %v", err)
}
for i := range stars {
@@ -700,7 +777,7 @@ func deleteUser(e *xorm.Session, u *User) error {
// ***** START: Follow *****
followers := make([]*Follow, 0, 10)
if err = e.Find(&followers, &Follow{UserID: u.Id}); err != nil {
if err = e.Find(&followers, &Follow{UserID: u.ID}); err != nil {
return fmt.Errorf("get all followers: %v", err)
}
for i := range followers {
@@ -711,37 +788,40 @@ func deleteUser(e *xorm.Session, u *User) error {
// ***** END: Follow *****
if err = deleteBeans(e,
&AccessToken{UID: u.Id},
&Collaboration{UserID: u.Id},
&Access{UserID: u.Id},
&Watch{UserID: u.Id},
&Star{UID: u.Id},
&Follow{FollowID: u.Id},
&Action{UserID: u.Id},
&IssueUser{UID: u.Id},
&EmailAddress{UID: u.Id},
&AccessToken{UID: u.ID},
&Collaboration{UserID: u.ID},
&Access{UserID: u.ID},
&Watch{UserID: u.ID},
&Star{UID: u.ID},
&Follow{FollowID: u.ID},
&Action{UserID: u.ID},
&IssueUser{UID: u.ID},
&EmailAddress{UID: u.ID},
); err != nil {
return fmt.Errorf("deleteBeans: %v", err)
}
// ***** START: PublicKey *****
keys := make([]*PublicKey, 0, 10)
if err = e.Find(&keys, &PublicKey{OwnerID: u.Id}); err != nil {
if err = e.Find(&keys, &PublicKey{OwnerID: u.ID}); err != nil {
return fmt.Errorf("get all public keys: %v", err)
}
for _, key := range keys {
if err = deletePublicKey(e, key.ID); err != nil {
return fmt.Errorf("deletePublicKey: %v", err)
}
keyIDs := make([]int64, len(keys))
for i := range keys {
keyIDs[i] = keys[i].ID
}
if err = deletePublicKeys(e, keyIDs...); err != nil {
return fmt.Errorf("deletePublicKeys: %v", err)
}
// ***** END: PublicKey *****
// Clear assignee.
if _, err = e.Exec("UPDATE `issue` SET assignee_id=0 WHERE assignee_id=?", u.Id); err != nil {
if _, err = e.Exec("UPDATE `issue` SET assignee_id=0 WHERE assignee_id=?", u.ID); err != nil {
return fmt.Errorf("clear assignee: %v", err)
}
if _, err = e.Id(u.Id).Delete(new(User)); err != nil {
if _, err = e.Id(u.ID).Delete(new(User)); err != nil {
return fmt.Errorf("Delete: %v", err)
}
@@ -749,7 +829,6 @@ func deleteUser(e *xorm.Session, u *User) error {
// Note: There are something just cannot be roll back,
// so just keep error logs of those operations.
RewriteAllPublicKeys()
os.RemoveAll(UserPath(u.Name))
os.Remove(u.CustomAvatarPath())
@@ -770,15 +849,20 @@ func DeleteUser(u *User) (err error) {
return err
}
return sess.Commit()
if err = sess.Commit(); err != nil {
return err
}
return RewriteAllPublicKeys()
}
// 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.
for _, u := range users {
if err = DeleteUser(u); err != nil {
// Ignore users that were set inactive by admin.
@@ -789,7 +873,7 @@ func DeleteInactivateUsers() (err error) {
}
}
_, err = x.Where("is_activated=?", false).Delete(new(EmailAddress))
_, err = x.Where("is_activated = ?", false).Delete(new(EmailAddress))
return err
}
@@ -827,7 +911,7 @@ 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, ACCESS_MODE_WRITE)
if err != nil {
return nil, err
} else if !has {
@@ -859,7 +943,9 @@ func GetUserEmailsByNames(names []string) []string {
if err != nil {
continue
}
mails = append(mails, u.Email)
if u.IsMailable() {
mails = append(mails, u.Email)
}
}
return mails
}
@@ -872,7 +958,7 @@ func GetUserIDsByNames(names []string) []int64 {
if err != nil {
continue
}
ids = append(ids, u.Id)
ids = append(ids, u.ID)
}
return ids
}
@@ -954,7 +1040,7 @@ type SearchUserOptions struct {
Type UserType
OrderBy string
Page int
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
PageSize int // Can be smaller than or equal to setting.UI.ExplorePagingNum
}
// SearchUserByName takes keyword and part of user name to search,
@@ -965,8 +1051,8 @@ func SearchUserByName(opts *SearchUserOptions) (users []*User, _ int64, _ error)
}
opts.Keyword = strings.ToLower(opts.Keyword)
if opts.PageSize <= 0 || opts.PageSize > setting.ExplorePagingNum {
opts.PageSize = setting.ExplorePagingNum
if opts.PageSize <= 0 || opts.PageSize > setting.UI.ExplorePagingNum {
opts.PageSize = setting.UI.ExplorePagingNum
}
if opts.Page <= 0 {
opts.Page = 1

View File

@@ -58,7 +58,15 @@ func isEmailUsed(e Engine, email string) (bool, error) {
return true, nil
}
return e.Get(&EmailAddress{Email: email})
has, err := e.Get(&EmailAddress{Email: email})
if err != nil {
return false, err
} else if has {
return true, nil
}
// We need to check primary email of users as well.
return e.Where("type=?", USER_TYPE_INDIVIDUAL).And("email=?", email).Get(new(User))
}
// IsEmailUsed returns true if the email has been used.
@@ -111,7 +119,9 @@ func (email *EmailAddress) Activate() error {
if err != nil {
return err
}
user.Rands = GetUserSalt()
if user.Rands, err = GetUserSalt(); err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
@@ -160,7 +170,7 @@ func MakeEmailPrimary(email *EmailAddress) error {
return ErrEmailNotActivated
}
user := &User{Id: email.UID}
user := &User{ID: email.UID}
has, err = x.Get(user)
if err != nil {
return err
@@ -182,7 +192,7 @@ func MakeEmailPrimary(email *EmailAddress) error {
}
if !has {
formerPrimaryEmail.UID = user.Id
formerPrimaryEmail.UID = user.ID
formerPrimaryEmail.IsActivated = user.IsActive
if _, err = sess.Insert(formerPrimaryEmail); err != nil {
return err
@@ -190,7 +200,7 @@ func MakeEmailPrimary(email *EmailAddress) error {
}
user.Email = email.Email
if _, err = sess.Id(user.Id).AllCols().Update(user); err != nil {
if _, err = sess.Id(user.ID).AllCols().Update(user); err != nil {
return err
}

View File

@@ -10,20 +10,21 @@ import (
"fmt"
"io/ioutil"
"strings"
"sync"
"time"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
gouuid "github.com/satori/go.uuid"
log "gopkg.in/clog.v1"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/httplib"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/sync"
)
var HookQueue = sync.NewUniqueQueue(setting.Webhook.QueueLength)
type HookContentType int
const (
@@ -58,8 +59,9 @@ func IsValidHookContentType(name string) bool {
}
type HookEvents struct {
Create bool `json:"create"`
Push bool `json:"push"`
Create bool `json:"create"`
Push bool `json:"push"`
PullRequest bool `json:"pull_request"`
}
// HookEvent represents events that will delivery hook.
@@ -102,12 +104,12 @@ type Webhook struct {
}
func (w *Webhook) BeforeInsert() {
w.CreatedUnix = time.Now().UTC().Unix()
w.CreatedUnix = time.Now().Unix()
w.UpdatedUnix = w.CreatedUnix
}
func (w *Webhook) BeforeUpdate() {
w.UpdatedUnix = time.Now().UTC().Unix()
w.UpdatedUnix = time.Now().Unix()
}
func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
@@ -157,14 +159,23 @@ func (w *Webhook) HasPushEvent() bool {
(w.ChooseEvents && w.HookEvents.Push)
}
// HasPullRequestEvent returns true if hook enabled pull request event.
func (w *Webhook) HasPullRequestEvent() bool {
return w.SendEverything ||
(w.ChooseEvents && w.HookEvents.PullRequest)
}
func (w *Webhook) EventsArray() []string {
events := make([]string, 0, 2)
events := make([]string, 0, 3)
if w.HasCreateEvent() {
events = append(events, "create")
}
if w.HasPushEvent() {
events = append(events, "push")
}
if w.HasPullRequestEvent() {
events = append(events, "pull_request")
}
return events
}
@@ -203,15 +214,18 @@ func GetWebhookByOrgID(orgID, id int64) (*Webhook, error) {
}
// GetActiveWebhooksByRepoID returns all active webhooks of repository.
func GetActiveWebhooksByRepoID(repoID int64) (ws []*Webhook, err error) {
err = x.Where("repo_id=?", repoID).And("is_active=?", true).Find(&ws)
return ws, err
func GetActiveWebhooksByRepoID(repoID int64) ([]*Webhook, error) {
webhooks := make([]*Webhook, 0, 5)
return webhooks, x.Find(&webhooks, &Webhook{
RepoID: repoID,
IsActive: true,
})
}
// GetWebhooksByRepoID returns all webhooks of repository.
func GetWebhooksByRepoID(repoID int64) (ws []*Webhook, err error) {
err = x.Find(&ws, &Webhook{RepoID: repoID})
return ws, err
// GetWebhooksByRepoID returns all webhooks of a repository.
func GetWebhooksByRepoID(repoID int64) ([]*Webhook, error) {
webhooks := make([]*Webhook, 0, 5)
return webhooks, x.Find(&webhooks, &Webhook{RepoID: repoID})
}
// UpdateWebhook updates information of webhook.
@@ -238,16 +252,16 @@ func deleteWebhook(bean *Webhook) (err error) {
return sess.Commit()
}
// DeleteWebhookByRepoID deletes webhook of repository by given ID.
func DeleteWebhookByRepoID(repoID, id int64) (error) {
// DeleteWebhookOfRepoByID deletes webhook of repository by given ID.
func DeleteWebhookOfRepoByID(repoID, id int64) error {
return deleteWebhook(&Webhook{
ID: id,
RepoID: repoID,
})
}
// DeleteWebhookByOrgID deletes webhook of organization by given ID.
func DeleteWebhookByOrgID(orgID, id int64) (error) {
// DeleteWebhookOfOrgByID deletes webhook of organization by given ID.
func DeleteWebhookOfOrgByID(orgID, id int64) error {
return deleteWebhook(&Webhook{
ID: id,
OrgID: orgID,
@@ -309,8 +323,9 @@ func IsValidHookTaskType(name string) bool {
type HookEventType string
const (
HOOK_EVENT_CREATE HookEventType = "create"
HOOK_EVENT_PUSH HookEventType = "push"
HOOK_EVENT_CREATE HookEventType = "create"
HOOK_EVENT_PUSH HookEventType = "push"
HOOK_EVENT_PULL_REQUEST HookEventType = "pull_request"
)
// HookRequest represents hook task request information.
@@ -422,17 +437,13 @@ func UpdateHookTask(t *HookTask) error {
// PrepareWebhooks adds new webhooks to task queue for given payload.
func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) error {
if err := repo.GetOwner(); err != nil {
return fmt.Errorf("GetOwner: %v", err)
}
ws, err := GetActiveWebhooksByRepoID(repo.ID)
if err != nil {
return fmt.Errorf("GetActiveWebhooksByRepoID: %v", err)
}
// check if repo belongs to org and append additional webhooks
if repo.Owner.IsOrganization() {
if repo.MustOwner().IsOrganization() {
// get hooks for org
orgws, err := GetActiveWebhooksByOrgID(repo.OwnerID)
if err != nil {
@@ -456,6 +467,10 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
if !w.HasPushEvent() {
continue
}
case HOOK_EVENT_PULL_REQUEST:
if !w.HasPullRequestEvent() {
continue
}
}
// Use separate objects so modifcations won't be made on payload on non-Gogs type hooks.
@@ -477,7 +492,7 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
URL: w.URL,
Payloader: payloader,
ContentType: w.ContentType,
EventType: HOOK_EVENT_PUSH,
EventType: event,
IsSSL: w.IsSSL,
}); err != nil {
return fmt.Errorf("CreateHookTask: %v", err)
@@ -486,64 +501,6 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
return nil
}
// UniqueQueue represents a queue that guarantees only one instance of same ID is in the line.
type UniqueQueue struct {
lock sync.Mutex
ids map[string]bool
queue chan string
}
func (q *UniqueQueue) Queue() <-chan string {
return q.queue
}
func NewUniqueQueue(queueLength int) *UniqueQueue {
if queueLength <= 0 {
queueLength = 100
}
return &UniqueQueue{
ids: make(map[string]bool),
queue: make(chan string, queueLength),
}
}
func (q *UniqueQueue) Remove(id interface{}) {
q.lock.Lock()
defer q.lock.Unlock()
delete(q.ids, com.ToStr(id))
}
func (q *UniqueQueue) AddFunc(id interface{}, fn func()) {
newid := com.ToStr(id)
if q.Exist(id) {
return
}
q.lock.Lock()
q.ids[newid] = true
if fn != nil {
fn()
}
q.lock.Unlock()
q.queue <- newid
}
func (q *UniqueQueue) Add(id interface{}) {
q.AddFunc(id, nil)
}
func (q *UniqueQueue) Exist(id interface{}) bool {
q.lock.Lock()
defer q.lock.Unlock()
return q.ids[com.ToStr(id)]
}
var HookQueue = NewUniqueQueue(setting.Webhook.QueueLength)
func (t *HookTask) deliver() {
t.IsDelivered = true
@@ -573,7 +530,7 @@ func (t *HookTask) deliver() {
}
defer func() {
t.Delivered = time.Now().UTC().UnixNano()
t.Delivered = time.Now().UnixNano()
if t.IsSucceed {
log.Trace("Hook delivered: %s", t.UUID)
} else {
@@ -640,12 +597,12 @@ func DeliverHooks() {
// Start listening on new hook requests.
for repoID := range HookQueue.Queue() {
log.Trace("DeliverHooks [%v]: processing delivery hooks", repoID)
log.Trace("DeliverHooks [repo_id: %v]", repoID)
HookQueue.Remove(repoID)
tasks = make([]*HookTask, 0, 5)
if err := x.Where("repo_id=? AND is_delivered=?", repoID, false).Find(&tasks); err != nil {
log.Error(4, "Get repository [%d] hook tasks: %v", repoID, err)
log.Error(4, "Get repository [%s] hook tasks: %v", repoID, err)
continue
}
for _, t := range tasks {

View File

@@ -12,6 +12,8 @@ import (
"github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/setting"
)
type SlackMeta struct {
@@ -34,6 +36,7 @@ type SlackPayload struct {
type SlackAttachment struct {
Fallback string `json:"fallback"`
Color string `json:"color"`
Title string `json:"title"`
Text string `json:"text"`
}
@@ -49,13 +52,20 @@ func (p *SlackPayload) JSONPayload() ([]byte, error) {
// see: https://api.slack.com/docs/formatting
func SlackTextFormatter(s string) string {
// take only first line of commit
first := strings.Split(s, "\n")[0]
// replace & < >
first = strings.Replace(first, "&", "&amp;", -1)
first = strings.Replace(first, "<", "&lt;", -1)
first = strings.Replace(first, ">", "&gt;", -1)
return first
s = strings.Replace(s, "&", "&amp;", -1)
s = strings.Replace(s, "<", "&lt;", -1)
s = strings.Replace(s, ">", "&gt;", -1)
return s
}
func SlackShortTextFormatter(s string) string {
s = strings.Split(s, "\n")[0]
// replace & < >
s = strings.Replace(s, "&", "&amp;", -1)
s = strings.Replace(s, "<", "&lt;", -1)
s = strings.Replace(s, ">", "&gt;", -1)
return s
}
func SlackLinkFormatter(url string, text string) string {
@@ -66,8 +76,8 @@ func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayloa
// created tag/branch
refName := git.RefEndName(p.Ref)
repoLink := SlackLinkFormatter(p.Repo.URL, p.Repo.Name)
refLink := SlackLinkFormatter(p.Repo.URL+"/src/"+refName, refName)
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName)
return &SlackPayload{
@@ -91,37 +101,83 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
} else {
commitDesc = fmt.Sprintf("%d new commits", len(p.Commits))
}
if len(p.CompareUrl) > 0 {
commitString = SlackLinkFormatter(p.CompareUrl, commitDesc)
if len(p.CompareURL) > 0 {
commitString = SlackLinkFormatter(p.CompareURL, commitDesc)
} else {
commitString = commitDesc
}
repoLink := SlackLinkFormatter(p.Repo.URL, p.Repo.Name)
branchLink := SlackLinkFormatter(p.Repo.URL+"/src/"+branchName, branchName)
text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.Name)
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
branchLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+branchName, branchName)
text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.UserName)
var attachmentText string
// for each commit, generate attachment text
for i, commit := range p.Commits {
attachmentText += fmt.Sprintf("%s: %s - %s", SlackLinkFormatter(commit.URL, commit.ID[:7]), SlackTextFormatter(commit.Message), SlackTextFormatter(commit.Author.Name))
attachmentText += fmt.Sprintf("%s: %s - %s", SlackLinkFormatter(commit.URL, commit.ID[:7]), SlackShortTextFormatter(commit.Message), SlackTextFormatter(commit.Author.Name))
// add linebreak to each commit but the last
if i < len(p.Commits)-1 {
attachmentText += "\n"
}
}
slackAttachments := []SlackAttachment{{
Color: slack.Color,
Text: attachmentText,
}}
return &SlackPayload{
Channel: slack.Channel,
Text: text,
Username: slack.Username,
IconURL: slack.IconURL,
Attachments: []SlackAttachment{{
Color: slack.Color,
Text: attachmentText,
}},
}, nil
}
func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*SlackPayload, error) {
senderLink := SlackLinkFormatter(setting.AppUrl+p.Sender.UserName, p.Sender.UserName)
titleLink := SlackLinkFormatter(fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index),
fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title))
var text, title, attachmentText string
switch p.Action {
case api.HOOK_ISSUE_OPENED:
text = fmt.Sprintf("[%s] Pull request submitted by %s", p.Repository.FullName, senderLink)
title = titleLink
attachmentText = SlackTextFormatter(p.PullRequest.Body)
case api.HOOK_ISSUE_CLOSED:
if p.PullRequest.HasMerged {
text = fmt.Sprintf("[%s] Pull request merged: %s by %s", p.Repository.FullName, titleLink, senderLink)
} else {
text = fmt.Sprintf("[%s] Pull request closed: %s by %s", p.Repository.FullName, titleLink, senderLink)
}
case api.HOOK_ISSUE_REOPENED:
text = fmt.Sprintf("[%s] Pull request re-opened: %s by %s", p.Repository.FullName, titleLink, senderLink)
case api.HOOK_ISSUE_EDITED:
text = fmt.Sprintf("[%s] Pull request edited: %s by %s", p.Repository.FullName, titleLink, senderLink)
attachmentText = SlackTextFormatter(p.PullRequest.Body)
case api.HOOK_ISSUE_ASSIGNED:
text = fmt.Sprintf("[%s] Pull request assigned to %s: %s by %s", p.Repository.FullName,
SlackLinkFormatter(setting.AppUrl+p.PullRequest.Assignee.UserName, p.PullRequest.Assignee.UserName),
titleLink, senderLink)
case api.HOOK_ISSUE_UNASSIGNED:
text = fmt.Sprintf("[%s] Pull request unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink)
case api.HOOK_ISSUE_LABEL_UPDATED:
text = fmt.Sprintf("[%s] Pull request labels updated: %s by %s", p.Repository.FullName, titleLink, senderLink)
case api.HOOK_ISSUE_LABEL_CLEARED:
text = fmt.Sprintf("[%s] Pull request labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink)
case api.HOOK_ISSUE_SYNCHRONIZED:
text = fmt.Sprintf("[%s] Pull request synchronized: %s by %s", p.Repository.FullName, titleLink, senderLink)
}
return &SlackPayload{
Channel: slack.Channel,
Text: text,
Username: slack.Username,
IconURL: slack.IconURL,
Attachments: slackAttachments,
Channel: slack.Channel,
Text: text,
Username: slack.Username,
IconURL: slack.IconURL,
Attachments: []SlackAttachment{{
Color: slack.Color,
Title: title,
Text: attachmentText,
}},
}, nil
}
@@ -138,6 +194,8 @@ func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackP
return getSlackCreatePayload(p.(*api.CreatePayload), slack)
case HOOK_EVENT_PUSH:
return getSlackPushPayload(p.(*api.PushPayload), slack)
case HOOK_EVENT_PULL_REQUEST:
return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
}
return s, nil

View File

@@ -12,57 +12,16 @@ import (
"path"
"path/filepath"
"strings"
"sync"
"github.com/Unknwon/com"
"github.com/gogits/git-module"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/sync"
)
// workingPool represents a pool of working status which makes sure
// that only one instance of same task is performing at a time.
// However, different type of tasks can performing at the same time.
type workingPool struct {
lock sync.Mutex
pool map[string]*sync.Mutex
count map[string]int
}
// CheckIn checks in a task and waits if others are running.
func (p *workingPool) CheckIn(name string) {
p.lock.Lock()
lock, has := p.pool[name]
if !has {
lock = &sync.Mutex{}
p.pool[name] = lock
}
p.count[name]++
p.lock.Unlock()
lock.Lock()
}
// CheckOut checks out a task to let other tasks run.
func (p *workingPool) CheckOut(name string) {
p.lock.Lock()
defer p.lock.Unlock()
p.pool[name].Unlock()
if p.count[name] == 1 {
delete(p.pool, name)
delete(p.count, name)
} else {
p.count[name]--
}
}
var wikiWorkingPool = &workingPool{
pool: make(map[string]*sync.Mutex),
count: make(map[string]int),
}
var wikiWorkingPool = sync.NewExclusivePool()
// ToWikiPageURL formats a string to corresponding wiki URL name.
func ToWikiPageURL(name string) string {
@@ -105,6 +64,8 @@ func (repo *Repository) InitWiki() error {
if err := git.InitRepository(repo.WikiPath(), true); err != nil {
return fmt.Errorf("InitRepository: %v", err)
} else if err = createUpdateHook(repo.WikiPath()); err != nil {
return fmt.Errorf("createUpdateHook: %v", err)
}
return nil
}
@@ -115,24 +76,13 @@ func (repo *Repository) LocalWikiPath() string {
// UpdateLocalWiki makes sure the local copy of repository wiki is up-to-date.
func (repo *Repository) UpdateLocalWiki() error {
return updateLocalCopy(repo.WikiPath(), repo.LocalWikiPath())
// Don't pass branch name here because it fails to clone and
// checkout to a specific branch when wiki is an empty repository.
return UpdateLocalCopyBranch(repo.WikiPath(), repo.LocalWikiPath(), "")
}
// discardLocalWikiChanges discards local commits make sure
// it is even to remote branch when local copy exists.
func discardLocalWikiChanges(localPath string) error {
if !com.IsExist(localPath) {
return nil
}
// No need to check if nothing in the repository.
if !git.IsBranchExist(localPath, "master") {
return nil
}
if err := git.ResetHEAD(localPath, true, "origin/master"); err != nil {
return fmt.Errorf("ResetHEAD: %v", err)
}
return nil
return discardLocalRepoBranchChanges(localPath, "master")
}
// updateWikiPage adds new page to repository wiki.
@@ -179,7 +129,10 @@ func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, mes
}
if err = git.AddChanges(localPath, true); err != nil {
return fmt.Errorf("AddChanges: %v", err)
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
Committer: doer.NewGitSig(),
Message: message,
}); err != nil {
return fmt.Errorf("CommitChanges: %v", err)
} else if err = git.Push(localPath, "origin", "master"); err != nil {
return fmt.Errorf("Push: %v", err)
@@ -215,7 +168,10 @@ func (repo *Repository) DeleteWikiPage(doer *User, title string) (err error) {
if err = git.AddChanges(localPath, true); err != nil {
return fmt.Errorf("AddChanges: %v", err)
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
Committer: doer.NewGitSig(),
Message: message,
}); err != nil {
return fmt.Errorf("CommitChanges: %v", err)
} else if err = git.Push(localPath, "origin", "master"); err != nil {
return fmt.Errorf("Push: %v", err)

View File

@@ -13,11 +13,11 @@ import (
"github.com/go-macaron/binding"
"github.com/go-macaron/session"
gouuid "github.com/satori/go.uuid"
log "gopkg.in/clog.v1"
"gopkg.in/macaron.v1"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)

View File

@@ -11,9 +11,8 @@ import (
"fmt"
"strings"
log "gopkg.in/clog.v1"
"gopkg.in/ldap.v2"
"github.com/gogits/gogs/modules/log"
)
type SecurityProtocol int
@@ -50,7 +49,7 @@ func (ls *Source) sanitizedUserQuery(username string) (string, bool) {
// See http://tools.ietf.org/search/rfc4515
badCharacters := "\x00()*\\"
if strings.ContainsAny(username, badCharacters) {
log.Debug("'%s' contains invalid query characters. Aborting.", username)
log.Trace("Username contains invalid query characters: %s", username)
return "", false
}
@@ -59,9 +58,9 @@ func (ls *Source) sanitizedUserQuery(username string) (string, bool) {
func (ls *Source) sanitizedUserDN(username string) (string, bool) {
// See http://tools.ietf.org/search/rfc4514: "special characters"
badCharacters := "\x00()*\\,='\"#+;<> "
if strings.ContainsAny(username, badCharacters) {
log.Debug("'%s' contains invalid DN characters. Aborting.", username)
badCharacters := "\x00()*\\,='\"#+;<>"
if strings.ContainsAny(username, badCharacters) || strings.HasPrefix(username, " ") || strings.HasSuffix(username, " ") {
log.Trace("Username contains invalid query characters: %s", username)
return "", false
}
@@ -73,12 +72,12 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
if ls.BindDN != "" && ls.BindPassword != "" {
err := l.Bind(ls.BindDN, ls.BindPassword)
if err != nil {
log.Debug("Failed to bind as BindDN[%s]: %v", ls.BindDN, err)
log.Trace("Failed to bind as BindDN '%s': %v", ls.BindDN, err)
return "", false
}
log.Trace("Bound as BindDN %s", ls.BindDN)
log.Trace("Bound as BindDN: %s", ls.BindDN)
} else {
log.Trace("Proceeding with anonymous LDAP search.")
log.Trace("Proceeding with anonymous LDAP search")
}
// A search for the user.
@@ -87,7 +86,7 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
return "", false
}
log.Trace("Searching for DN using filter %s and base %s", userFilter, ls.UserBase)
log.Trace("Searching for DN using filter '%s' and base '%s'", userFilter, ls.UserBase)
search := ldap.NewSearchRequest(
ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0,
false, userFilter, []string{}, nil)
@@ -95,10 +94,10 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
// Ensure we found a user
sr, err := l.Search(search)
if err != nil || len(sr.Entries) < 1 {
log.Debug("Failed search using filter[%s]: %v", userFilter, err)
log.Trace("Failed search using filter '%s': %v", userFilter, err)
return "", false
} else if len(sr.Entries) > 1 {
log.Debug("Filter '%s' returned more than one user.", userFilter)
log.Trace("Filter '%s' returned more than one user", userFilter)
return "", false
}
@@ -112,7 +111,7 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
}
func dial(ls *Source) (*ldap.Conn, error) {
log.Trace("Dialing LDAP with security protocol (%v) without verifying: %v", ls.SecurityProtocol, ls.SkipVerify)
log.Trace("Dialing LDAP with security protocol '%v' without verifying: %v", ls.SecurityProtocol, ls.SkipVerify)
tlsCfg := &tls.Config{
ServerName: ls.Host,
@@ -141,7 +140,7 @@ func bindUser(l *ldap.Conn, userDN, passwd string) error {
log.Trace("Binding with userDN: %s", userDN)
err := l.Bind(userDN, passwd)
if err != nil {
log.Debug("LDAP auth. failed for %s, reason: %v", userDN, err)
log.Trace("LDAP authentication failed for '%s': %v", userDN, err)
return err
}
log.Trace("Bound successfully with userDN: %s", userDN)
@@ -150,9 +149,14 @@ func bindUser(l *ldap.Conn, userDN, passwd string) error {
// searchEntry : search an LDAP source if an entry (name, passwd) is valid and in the specific filter
func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, string, string, string, bool, bool) {
// See https://tools.ietf.org/search/rfc4513#section-5.1.2
if len(passwd) == 0 {
log.Trace("authentication failed for '%s' with empty password")
return "", "", "", "", false, false
}
l, err := dial(ls)
if err != nil {
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
log.Error(4, "LDAP connect failed for '%s': %v", ls.Host, err)
ls.Enabled = false
return "", "", "", "", false, false
}
@@ -168,7 +172,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
return "", "", "", "", false, false
}
} else {
log.Trace("LDAP will use BindDN.")
log.Trace("LDAP will use BindDN")
var found bool
userDN, found = ls.findUserDN(l, name)
@@ -190,7 +194,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
return "", "", "", "", false, false
}
log.Trace("Fetching attributes '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, userFilter, userDN)
log.Trace("Fetching attributes '%v', '%v', '%v', '%v' with filter '%s' and base '%s'", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, userFilter, userDN)
search := ldap.NewSearchRequest(
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
[]string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail},
@@ -198,13 +202,13 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
sr, err := l.Search(search)
if err != nil {
log.Error(4, "LDAP Search failed unexpectedly! (%v)", err)
log.Error(4, "LDAP search failed: %v", err)
return "", "", "", "", false, false
} else if len(sr.Entries) < 1 {
if directBind {
log.Error(4, "User filter inhibited user login.")
log.Error(4, "User filter inhibited user login")
} else {
log.Error(4, "LDAP Search failed unexpectedly! (0 entries)")
log.Error(4, "LDAP search failed: 0 entries")
}
return "", "", "", "", false, false
@@ -217,7 +221,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
isAdmin := false
if len(ls.AdminFilter) > 0 {
log.Trace("Checking admin with filter %s and base %s", ls.AdminFilter, userDN)
log.Trace("Checking admin with filter '%s' and base '%s'", ls.AdminFilter, userDN)
search = ldap.NewSearchRequest(
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, ls.AdminFilter,
[]string{ls.AttributeName},
@@ -225,9 +229,9 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
sr, err = l.Search(search)
if err != nil {
log.Error(4, "LDAP Admin Search failed unexpectedly! (%v)", err)
log.Error(4, "LDAP admin search failed: %v", err)
} else if len(sr.Entries) < 1 {
log.Error(4, "LDAP Admin Search failed")
log.Error(4, "LDAP admin search failed: 0 entries")
} else {
isAdmin = true
}

View File

@@ -53,7 +53,7 @@ func (f *MigrateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
}
// ParseRemoteAddr checks if given remote address is valid,
// and returns composed URL with needed username and passowrd.
// and returns composed URL with needed username and password.
// It also checks if given user has permission when remote address
// is actually a local path.
func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) {
@@ -96,6 +96,7 @@ type RepoSettingForm struct {
ExternalWikiURL string
EnableIssues bool
EnableExternalTracker bool
ExternalTrackerURL string
TrackerURLFormat string
TrackerIssueStyle string
EnablePulls bool
@@ -113,10 +114,11 @@ func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
// \/ \/ \/ \/ \/ \/
type WebhookForm struct {
Events string
Create bool
Push bool
Active bool
Events string
Create bool
Push bool
PullRequest bool
Active bool
}
func (f WebhookForm) PushOnly() bool {
@@ -168,7 +170,7 @@ type CreateIssueForm struct {
MilestoneID int64
AssigneeID int64
Content string
Attachments []string
Files []string
}
func (f *CreateIssueForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
@@ -176,9 +178,9 @@ func (f *CreateIssueForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
}
type CreateCommentForm struct {
Content string
Status string `binding:"OmitEmpty;In(reopen,close)"`
Attachments []string
Content string
Status string `binding:"OmitEmpty;In(reopen,close)"`
Files []string
}
func (f *CreateCommentForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
@@ -219,6 +221,14 @@ func (f *CreateLabelForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
return validate(errs, ctx.Data, f, ctx.Locale)
}
type InitializeLabelsForm struct {
TemplateName string `binding:"Required"`
}
func (f *InitializeLabelsForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// __________ .__
// \______ \ ____ | | ____ _____ ______ ____
// | _// __ \| | _/ __ \\__ \ / ___// __ \
@@ -268,3 +278,79 @@ type NewWikiForm struct {
func (f *NewWikiForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ___________ .___.__ __
// \_ _____/ __| _/|__|/ |_
// | __)_ / __ | | \ __\
// | \/ /_/ | | || |
// /_______ /\____ | |__||__|
// \/ \/
type EditRepoFileForm struct {
TreePath string `binding:"Required;MaxSize(500)"`
Content string `binding:"Required"`
CommitSummary string `binding:"MaxSize(100)`
CommitMessage string
CommitChoice string `binding:"Required;MaxSize(50)"`
NewBranchName string `binding:"AlphaDashDot;MaxSize(100)"`
LastCommit string
}
func (f *EditRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
type EditPreviewDiffForm struct {
Content string
}
func (f *EditPreviewDiffForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ____ ___ .__ .___
// | | \______ | | _________ __| _/
// | | /\____ \| | / _ \__ \ / __ |
// | | / | |_> > |_( <_> ) __ \_/ /_/ |
// |______/ | __/|____/\____(____ /\____ |
// |__| \/ \/
//
type UploadRepoFileForm struct {
TreePath string `binding:MaxSize(500)"`
CommitSummary string `binding:"MaxSize(100)`
CommitMessage string
CommitChoice string `binding:"Required;MaxSize(50)"`
NewBranchName string `binding:"AlphaDashDot;MaxSize(100)"`
Files []string
}
func (f *UploadRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
type RemoveUploadFileForm struct {
File string `binding:"Required;MaxSize(50)"`
}
func (f *RemoveUploadFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ________ .__ __
// \______ \ ____ | | _____/ |_ ____
// | | \_/ __ \| | _/ __ \ __\/ __ \
// | ` \ ___/| |_\ ___/| | \ ___/
// /_______ /\___ >____/\___ >__| \___ >
// \/ \/ \/ \/
type DeleteRepoFileForm struct {
CommitSummary string `binding:"MaxSize(100)`
CommitMessage string
CommitChoice string `binding:"Required;MaxSize(50)"`
NewBranchName string `binding:"AlphaDashDot;MaxSize(100)"`
}
func (f *DeleteRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View File

@@ -36,11 +36,12 @@ type InstallForm struct {
RegisterConfirm bool
MailNotify bool
OfflineMode bool
DisableGravatar bool
DisableRegistration bool
EnableCaptcha bool
RequireSignInView bool
OfflineMode bool
DisableGravatar bool
EnableFederatedAvatar bool
DisableRegistration bool
EnableCaptcha bool
RequireSignInView bool
AdminName string `binding:"OmitEmpty;AlphaDashDot;MaxSize(30)" locale:"install.admin_name"`
AdminPasswd string `binding:"OmitEmpty;MaxSize(255)" locale:"install.admin_password"`
@@ -93,19 +94,25 @@ type UpdateProfileForm struct {
Email string `binding:"Required;Email;MaxSize(254)"`
Website string `binding:"Url;MaxSize(100)"`
Location string `binding:"MaxSize(50)"`
Gravatar string `binding:"OmitEmpty;Email;MaxSize(254)"`
}
func (f *UpdateProfileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
type UploadAvatarForm struct {
Enable bool
Avatar *multipart.FileHeader
const (
AVATAR_LOCAL string = "local"
AVATAR_BYMAIL string = "bymail"
)
type AvatarForm struct {
Source string
Avatar *multipart.FileHeader
Gravatar string `binding:"OmitEmpty;Email;MaxSize(254)"`
Federavatar bool
}
func (f *UploadAvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
func (f *AvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View File

@@ -14,7 +14,7 @@ import (
"github.com/issue9/identicon"
)
const _RANDOM_AVATAR_SIZE = 200
const AVATAR_SIZE = 290
// RandomImage generates and returns a random avatar image unique to input data
// in custom size (height and width).
@@ -39,5 +39,5 @@ func RandomImageSize(size int, data []byte) (image.Image, error) {
// RandomImage generates and returns a random avatar image unique to input data
// in default size (height and width).
func RandomImage(data []byte) (image.Image, error) {
return RandomImageSize(_RANDOM_AVATAR_SIZE, data)
return RandomImageSize(AVATAR_SIZE, data)
}

View File

@@ -5,16 +5,15 @@
package base
import (
"crypto/hmac"
"crypto/md5"
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"fmt"
"hash"
"html/template"
"math"
"math/big"
"net/http"
"strings"
"time"
@@ -23,10 +22,10 @@ import (
"github.com/Unknwon/com"
"github.com/Unknwon/i18n"
log "gopkg.in/clog.v1"
"github.com/gogits/chardet"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
@@ -45,7 +44,7 @@ func EncodeSha1(str string) string {
}
func ShortSha(sha1 string) string {
if len(sha1) == 40 {
if len(sha1) > 10 {
return sha1[:10]
}
return sha1
@@ -53,17 +52,17 @@ func ShortSha(sha1 string) string {
func DetectEncoding(content []byte) (string, error) {
if utf8.Valid(content) {
log.Debug("Detected encoding: utf-8 (fast)")
log.Trace("Detected encoding: utf-8 (fast)")
return "UTF-8", nil
}
result, err := chardet.NewTextDetector().DetectBest(content)
if result.Charset != "UTF-8" && len(setting.Repository.AnsiCharset) > 0 {
log.Debug("Using default AnsiCharset: %s", setting.Repository.AnsiCharset)
log.Trace("Using default AnsiCharset: %s", setting.Repository.AnsiCharset)
return setting.Repository.AnsiCharset, err
}
log.Debug("Detected encoding: %s", result.Charset)
log.Trace("Detected encoding: %s", result.Charset)
return result.Charset, err
}
@@ -82,57 +81,31 @@ func BasicAuthEncode(username, password string) string {
}
// GetRandomString generate random string by specify chars.
func GetRandomString(n int, alphabets ...byte) string {
func GetRandomString(n int) (string, error) {
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
var bytes = make([]byte, n)
rand.Read(bytes)
for i, b := range bytes {
if len(alphabets) == 0 {
bytes[i] = alphanum[b%byte(len(alphanum))]
} else {
bytes[i] = alphabets[b%byte(len(alphabets))]
buffer := make([]byte, n)
max := big.NewInt(int64(len(alphanum)))
for i := 0; i < n; i++ {
index, err := randomInt(max)
if err != nil {
return "", err
}
buffer[i] = alphanum[index]
}
return string(bytes)
return string(buffer), nil
}
// http://code.google.com/p/go/source/browse/pbkdf2/pbkdf2.go?repo=crypto
// FIXME: use https://godoc.org/golang.org/x/crypto/pbkdf2?
func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
prf := hmac.New(h, password)
hashLen := prf.Size()
numBlocks := (keyLen + hashLen - 1) / hashLen
var buf [4]byte
dk := make([]byte, 0, numBlocks*hashLen)
U := make([]byte, hashLen)
for block := 1; block <= numBlocks; block++ {
// N.B.: || means concatenation, ^ means XOR
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
// U_1 = PRF(password, salt || uint(i))
prf.Reset()
prf.Write(salt)
buf[0] = byte(block >> 24)
buf[1] = byte(block >> 16)
buf[2] = byte(block >> 8)
buf[3] = byte(block)
prf.Write(buf[:4])
dk = prf.Sum(dk)
T := dk[len(dk)-hashLen:]
copy(U, T)
// U_n = PRF(password, U_(n-1))
for n := 2; n <= iter; n++ {
prf.Reset()
prf.Write(U)
U = U[:0]
U = prf.Sum(U)
for x := range U {
T[x] ^= U[x]
}
}
func randomInt(max *big.Int) (int, error) {
rand, err := rand.Int(rand.Reader, max)
if err != nil {
return 0, err
}
return dk[:keyLen]
return int(rand.Int64()), nil
}
// verify time limit code
@@ -204,13 +177,24 @@ func HashEmail(email string) string {
return hex.EncodeToString(h.Sum(nil))
}
// AvatarLink returns avatar link by given email.
func AvatarLink(email string) string {
if setting.DisableGravatar || setting.OfflineMode {
return setting.AppSubUrl + "/img/avatar_default.png"
// AvatarLink returns relative avatar link to the site domain by given email,
// which includes app sub-url as prefix. However, it is possible
// to return full URL if user enables Gravatar-like service.
func AvatarLink(email string) (url string) {
if setting.EnableFederatedAvatar && setting.LibravatarService != nil {
var err error
url, err = setting.LibravatarService.FromEmail(email)
if err != nil {
log.Error(4, "LibravatarService.FromEmail [%s]: %v", email, err)
}
}
return setting.GravatarSource + HashEmail(email)
if len(url) == 0 && !setting.DisableGravatar {
url = setting.GravatarSource + HashEmail(email)
}
if len(url) == 0 {
url = setting.AppSubUrl + "/img/avatar_default.png"
}
return url
}
// Seconds-based time units
@@ -507,26 +491,22 @@ func IsLetter(ch rune) bool {
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
}
func IsTextFile(data []byte) (string, bool) {
contentType := http.DetectContentType(data)
if strings.Index(contentType, "text/") != -1 {
return contentType, true
// IsTextFile returns true if file content format is plain text or empty.
func IsTextFile(data []byte) bool {
if len(data) == 0 {
return true
}
return contentType, false
return strings.Index(http.DetectContentType(data), "text/") != -1
}
func IsImageFile(data []byte) (string, bool) {
contentType := http.DetectContentType(data)
if strings.Index(contentType, "image/") != -1 {
return contentType, true
}
return contentType, false
func IsImageFile(data []byte) bool {
return strings.Index(http.DetectContentType(data), "image/") != -1
}
func IsPDFFile(data []byte) (string, bool) {
contentType := http.DetectContentType(data)
if strings.Index(contentType, "application/pdf") != -1 {
return contentType, true
}
return contentType, false
func IsPDFFile(data []byte) bool {
return strings.Index(http.DetectContentType(data), "application/pdf") != -1
}
func IsVideoFile(data []byte) bool {
return strings.Index(http.DetectContentType(data), "video/") != -1
}

File diff suppressed because one or more lines are too long

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