mirror of
https://github.com/gogs/gogs.git
synced 2026-03-01 17:50:59 +01:00
Compare commits
360 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d324500959 | ||
|
|
3d218861e2 | ||
|
|
c65bd65254 | ||
|
|
72ce06eab8 | ||
|
|
912f7b51e9 | ||
|
|
90fab0be6b | ||
|
|
c9516c4c60 | ||
|
|
6e74dd4388 | ||
|
|
d160c7e565 | ||
|
|
8ac04a3f29 | ||
|
|
b91b35b565 | ||
|
|
ac78bae7b5 | ||
|
|
926e75d721 | ||
|
|
d5a3021a7d | ||
|
|
d8a994ef24 | ||
|
|
7140dbac95 | ||
|
|
acf094fb07 | ||
|
|
7e0baf4136 | ||
|
|
a703f7d7b4 | ||
|
|
a9981d8099 | ||
|
|
5649556a33 | ||
|
|
834d92a47b | ||
|
|
e2f95c2845 | ||
|
|
5609585ec1 | ||
|
|
b7f3d94cd0 | ||
|
|
f6c98465c7 | ||
|
|
aa12135b97 | ||
|
|
f38d5e57dd | ||
|
|
341da3cea7 | ||
|
|
7162095635 | ||
|
|
0b54035d7a | ||
|
|
dbd4697001 | ||
|
|
2408df3f35 | ||
|
|
a1b28fc33c | ||
|
|
a467184e13 | ||
|
|
658bfc2704 | ||
|
|
736a46dff9 | ||
|
|
0f1b26ed1e | ||
|
|
60896c66af | ||
|
|
eb009923f4 | ||
|
|
338af89d56 | ||
|
|
2fdf8fc938 | ||
|
|
89d6b18dad | ||
|
|
b97780ba51 | ||
|
|
ccc94dd11c | ||
|
|
d5ca913b2f | ||
|
|
3af1d3c581 | ||
|
|
24829f314b | ||
|
|
779b71eda4 | ||
|
|
9cf4fe043b | ||
|
|
2765b5c7cf | ||
|
|
632c27802c | ||
|
|
dc89c51f3e | ||
|
|
bb595666ac | ||
|
|
e9b9e6eb53 | ||
|
|
58e004f7da | ||
|
|
fd92d91da3 | ||
|
|
d8631b616e | ||
|
|
aa5e837c65 | ||
|
|
4f6c3e8bb2 | ||
|
|
a1d97e8f5c | ||
|
|
daa43cfb6e | ||
|
|
9adfe453d5 | ||
|
|
29cd8ac270 | ||
|
|
d710b5e791 | ||
|
|
c47866b34a | ||
|
|
15d37b7a95 | ||
|
|
15394f613f | ||
|
|
3650bd8528 | ||
|
|
de3be370f7 | ||
|
|
364874937e | ||
|
|
10e4887b2b | ||
|
|
643acdd32d | ||
|
|
8662990746 | ||
|
|
25845ea1a5 | ||
|
|
d3ca5accfd | ||
|
|
8ab5399e83 | ||
|
|
ec478b4b06 | ||
|
|
1feecd6beb | ||
|
|
a3e8c32a30 | ||
|
|
779bb890fa | ||
|
|
1fa4fe706a | ||
|
|
f4bc9263d9 | ||
|
|
600d8edaca | ||
|
|
ce3708b3ea | ||
|
|
23bc9a2911 | ||
|
|
47adc0e8f7 | ||
|
|
5258ee3740 | ||
|
|
59745c62b4 | ||
|
|
0ad5f51059 | ||
|
|
6b3e47b103 | ||
|
|
297e772c20 | ||
|
|
8bf3032b16 | ||
|
|
e40d94bb4f | ||
|
|
7ffe845c61 | ||
|
|
af8e323248 | ||
|
|
b09ddc72d2 | ||
|
|
a881f776d0 | ||
|
|
40f9d4f920 | ||
|
|
dd7608a36e | ||
|
|
662482d366 | ||
|
|
08ff1b7d4b | ||
|
|
3808638df1 | ||
|
|
ee53204e02 | ||
|
|
f15a2f9b25 | ||
|
|
3b102a71a2 | ||
|
|
133397ee0d | ||
|
|
e2b4a24cb6 | ||
|
|
d37cf09ccd | ||
|
|
2cfe6f8c60 | ||
|
|
16270ee9a4 | ||
|
|
1dfead1eef | ||
|
|
894946c319 | ||
|
|
45db167f7a | ||
|
|
10fbb1aa2f | ||
|
|
bc0eee48d5 | ||
|
|
fa5a1cb54f | ||
|
|
e797a225b6 | ||
|
|
6d5c986d4f | ||
|
|
45659d0fd2 | ||
|
|
acfc942ad7 | ||
|
|
db150f2e42 | ||
|
|
9fe9cd8b5c | ||
|
|
f8182ac521 | ||
|
|
4e96a4a62b | ||
|
|
90e9e3c89d | ||
|
|
d4583ebd4b | ||
|
|
b024de7bf5 | ||
|
|
4a0d2edc3d | ||
|
|
8e40f86d2c | ||
|
|
2bfb8bb5fd | ||
|
|
137a49e834 | ||
|
|
a3bdede2ce | ||
|
|
ddf9fa06c7 | ||
|
|
d91004ee71 | ||
|
|
739d5aa1d3 | ||
|
|
04be8c0de5 | ||
|
|
c3ff476ed6 | ||
|
|
fb1708e1af | ||
|
|
a47baa1b7a | ||
|
|
995487e822 | ||
|
|
5e97693e0e | ||
|
|
452bc385fe | ||
|
|
71bb7f6053 | ||
|
|
0255e6a703 | ||
|
|
5a27aea8e0 | ||
|
|
0e4ae27caa | ||
|
|
1c74612b3c | ||
|
|
d3ba246693 | ||
|
|
a93af59b36 | ||
|
|
0d41827f23 | ||
|
|
32efc3ec0a | ||
|
|
d33ed36fb4 | ||
|
|
9d67528c82 | ||
|
|
66d2ba1b4e | ||
|
|
84749736a8 | ||
|
|
857b340498 | ||
|
|
3e0a27157c | ||
|
|
3abad75a1b | ||
|
|
d568019306 | ||
|
|
b3e0efc0c3 | ||
|
|
caa4ca46c0 | ||
|
|
5d192c2ebf | ||
|
|
29c3e9f428 | ||
|
|
532f9fdd99 | ||
|
|
4848620594 | ||
|
|
bead46363b | ||
|
|
57c10aae33 | ||
|
|
0e0cd9100b | ||
|
|
90780a0d90 | ||
|
|
fdad234445 | ||
|
|
bba1847a8e | ||
|
|
a9d68a6884 | ||
|
|
9cf95e4e37 | ||
|
|
8c4588c4c9 | ||
|
|
e35791b2b2 | ||
|
|
5eafe2b17e | ||
|
|
1c1246fcb9 | ||
|
|
8436d69eaf | ||
|
|
20403f75fb | ||
|
|
295de51b99 | ||
|
|
6e03f61617 | ||
|
|
055c1ea02d | ||
|
|
abc5abce30 | ||
|
|
112a7cab31 | ||
|
|
ee814bf8d6 | ||
|
|
a4a23c0268 | ||
|
|
cd89d387b6 | ||
|
|
beefc53e59 | ||
|
|
1becf01cfa | ||
|
|
9fbf54ee6b | ||
|
|
12c8953381 | ||
|
|
b7b30cd85e | ||
|
|
81e5722bcc | ||
|
|
303d091ea9 | ||
|
|
c11c3b6c11 | ||
|
|
566163ab82 | ||
|
|
e2dde6eb0a | ||
|
|
b900150b1d | ||
|
|
4deb876343 | ||
|
|
0617720c0c | ||
|
|
9b8ad01bc0 | ||
|
|
96dee1c354 | ||
|
|
674c5c37be | ||
|
|
5deb726f3f | ||
|
|
1ab8a60d73 | ||
|
|
8eb0577791 | ||
|
|
85335c5f56 | ||
|
|
93f40995b3 | ||
|
|
646e90d833 | ||
|
|
d943429672 | ||
|
|
3a9fd81f59 | ||
|
|
edc414c584 | ||
|
|
a849ac0164 | ||
|
|
b31c7fe074 | ||
|
|
2665728ee7 | ||
|
|
f65dedc3be | ||
|
|
b921161666 | ||
|
|
2cc1ee3fc0 | ||
|
|
ab0ba4bbae | ||
|
|
86f841dd71 | ||
|
|
e3075865e4 | ||
|
|
3509f1f610 | ||
|
|
7ca1821725 | ||
|
|
ee5d6fb025 | ||
|
|
1372cab35a | ||
|
|
e33ddac9bf | ||
|
|
71b9537393 | ||
|
|
b33abc6280 | ||
|
|
9032bd097b | ||
|
|
38efa72146 | ||
|
|
4ae7e64e2a | ||
|
|
863ff19e1f | ||
|
|
eb14fbf95f | ||
|
|
a3eab8185d | ||
|
|
f36c82c3b3 | ||
|
|
1105a3139f | ||
|
|
fb99d50fa1 | ||
|
|
b8d0367a6c | ||
|
|
7ef9a05588 | ||
|
|
c631a4a9b9 | ||
|
|
dccfadf7b8 | ||
|
|
d1675c2701 | ||
|
|
29b07693dd | ||
|
|
f75b5f4287 | ||
|
|
40413c5c6c | ||
|
|
a72f57374d | ||
|
|
98306a5d8a | ||
|
|
cb92af4a6c | ||
|
|
ae2c6d42fd | ||
|
|
ab89be33a9 | ||
|
|
a1a4f1103c | ||
|
|
653e1506ad | ||
|
|
41fdaabcf7 | ||
|
|
8e09e03127 | ||
|
|
688fc515f8 | ||
|
|
53a63de9dc | ||
|
|
f610bfa8a2 | ||
|
|
fc4a4d38d1 | ||
|
|
939d96813c | ||
|
|
f43cc90841 | ||
|
|
a2ef9a2b64 | ||
|
|
c199703e2a | ||
|
|
db719abff2 | ||
|
|
91bab801aa | ||
|
|
17c4400b12 | ||
|
|
efa0e7b27a | ||
|
|
cd966787f3 | ||
|
|
e2f0587ca3 | ||
|
|
9620f48ed0 | ||
|
|
4db0e1d340 | ||
|
|
8a93113192 | ||
|
|
86bce4a2ae | ||
|
|
21d7b5acaf | ||
|
|
bcf6aed452 | ||
|
|
4331d1d2a0 | ||
|
|
62edc5c59a | ||
|
|
cc8c67ff29 | ||
|
|
697b0e2aba | ||
|
|
03427fb005 | ||
|
|
7655337a1f | ||
|
|
bf11ad19ea | ||
|
|
e0f0f72a36 | ||
|
|
ca35ddd078 | ||
|
|
f4309bbb05 | ||
|
|
6dc407c7d9 | ||
|
|
81ed5c4bee | ||
|
|
73474c043b | ||
|
|
0d5dc8a064 | ||
|
|
0cb7396840 | ||
|
|
4ea75dfcbe | ||
|
|
cc22c8a1ae | ||
|
|
2481fe2f56 | ||
|
|
2087156119 | ||
|
|
3870a7a3c8 | ||
|
|
19c234db39 | ||
|
|
8fe5d887ae | ||
|
|
4e6d048ba1 | ||
|
|
0df39b33eb | ||
|
|
7392b6a755 | ||
|
|
cb8134da52 | ||
|
|
590637246b | ||
|
|
053d1424b2 | ||
|
|
4993ab1a76 | ||
|
|
a62290de52 | ||
|
|
8d58e06ad8 | ||
|
|
b8fbf6559d | ||
|
|
44637f03cc | ||
|
|
7bab3d682f | ||
|
|
34f01aab5e | ||
|
|
240fe07287 | ||
|
|
93f03707a7 | ||
|
|
85af36332b | ||
|
|
13fe733037 | ||
|
|
4c896bb620 | ||
|
|
157d868254 | ||
|
|
e16042010e | ||
|
|
227dcc3cb9 | ||
|
|
e914969e4c | ||
|
|
a49af93faf | ||
|
|
76d4af891f | ||
|
|
0721095944 | ||
|
|
c62a6b7a12 | ||
|
|
cadf03db68 | ||
|
|
5ff6eedf5e | ||
|
|
53eb37d529 | ||
|
|
3bcdb3855c | ||
|
|
f00fef0cd0 | ||
|
|
2d3ecbe5b2 | ||
|
|
09c981846b | ||
|
|
037a01c4e4 | ||
|
|
1d95844d55 | ||
|
|
1c9dd11ba7 | ||
|
|
1e7e092992 | ||
|
|
33a99d587a | ||
|
|
9cd16c5b12 | ||
|
|
6673dcb038 | ||
|
|
71142929cc | ||
|
|
d7b924f17d | ||
|
|
b117befc2b | ||
|
|
7786cb76f3 | ||
|
|
eb918c2368 | ||
|
|
8ecbf0f16d | ||
|
|
b13caa23d9 | ||
|
|
fd79fad2ec | ||
|
|
19423957b1 | ||
|
|
3362b3a44f | ||
|
|
50264200f0 | ||
|
|
7436ce6403 | ||
|
|
91789930bc | ||
|
|
ea375c0dcc | ||
|
|
7509fa2c33 | ||
|
|
acdb4d8bdd | ||
|
|
95f9c85bcc | ||
|
|
79dcd7ee6e | ||
|
|
ed001d70e4 | ||
|
|
42a8c15ad0 | ||
|
|
9a27e5ccdc | ||
|
|
71123c816d | ||
|
|
168c69273f |
@@ -1,6 +1,7 @@
|
||||
[run]
|
||||
init_cmds = [
|
||||
#["grep", "-rn", "FIXME", "."],
|
||||
["make", "build-dev"],
|
||||
["./gogs", "web"]
|
||||
]
|
||||
watch_all = true
|
||||
@@ -11,9 +12,9 @@ watch_dirs = [
|
||||
"$WORKDIR/routers"
|
||||
]
|
||||
watch_exts = [".go"]
|
||||
ignore_files = [".+_test.go"]
|
||||
build_delay = 1500
|
||||
cmds = [
|
||||
["go", "install", "-race"], # sqlite redis memcache cert pam tidb
|
||||
["go", "build", "-race"],
|
||||
["make", "build-dev"], # sqlite cert pam tidb
|
||||
["./gogs", "web"]
|
||||
]
|
||||
6
CONTRIBUTING.md → .github/CONTRIBUTING.md
vendored
6
CONTRIBUTING.md → .github/CONTRIBUTING.md
vendored
@@ -46,11 +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.md) and [FAQs](http://gogs.io/docs/intro/faqs.html) pages.
|
||||
|
||||
## Things To Notice
|
||||
|
||||
Please take a moment to check that an issue on [GitHub](https://github.com/gogits/gogs/issues) or card on [Trello](https://trello.com/b/uxAoeLUl/gogs-go-git-service) doesn't already exist documenting your bug report or improvement proposal. If it does, it never hurts to add a quick "+1" or "I have this problem too". This will help prioritize the most common problems and requests.
|
||||
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.
|
||||
|
||||
## Code of conduct
|
||||
|
||||
18
.github/ISSUE_TEMPLATE.md
vendored
Normal file
18
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
We DO NOT take questions or config/deploy problems on GitHub, please use our forum: https://discuss.gogs.io
|
||||
|
||||
Please take a moment to search that an issue doesn't already exist.
|
||||
|
||||
For bug reports, please give the relevant info:
|
||||
|
||||
- Gogs version (or commit ref):
|
||||
- Git version:
|
||||
- Operating system:
|
||||
- Database:
|
||||
- [ ] PostgreSQL
|
||||
- [ ] MySQL
|
||||
- [ ] SQLite
|
||||
- Log gist:
|
||||
|
||||
## Description
|
||||
|
||||
...
|
||||
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
Please, make sure you are targeting the `develop` branch!
|
||||
|
||||
More instructions about contributing with Gogs code can be found here:
|
||||
https://github.com/gogits/gogs/wiki/Contributing-Code
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,7 +14,6 @@ files/
|
||||
*.so
|
||||
_obj
|
||||
_test
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
|
||||
49
.gopmfile
49
.gopmfile
@@ -2,48 +2,51 @@
|
||||
path = github.com/gogits/gogs
|
||||
|
||||
[deps]
|
||||
github.com/bradfitz/gomemcache = commit:72a68649ba
|
||||
github.com/codegangsta/cli = commit:b5232bb
|
||||
github.com/go-macaron/binding = commit:2502aaf
|
||||
github.com/bradfitz/gomemcache = commit:fb1f79c
|
||||
github.com/codegangsta/cli = commit:5db7419
|
||||
github.com/go-macaron/binding = commit:a68f342
|
||||
github.com/go-macaron/cache = commit:5617353
|
||||
github.com/go-macaron/captcha = commit:8aa5919
|
||||
github.com/go-macaron/csrf = commit:715bca0
|
||||
github.com/go-macaron/gzip = commit:4938e9b
|
||||
github.com/go-macaron/gzip = commit:cad1c65
|
||||
github.com/go-macaron/i18n = commit:d2d3329
|
||||
github.com/go-macaron/inject = commit:c5ab7bf
|
||||
github.com/go-macaron/session = commit:66031fc
|
||||
github.com/go-macaron/toolbox = commit:ab30a81
|
||||
github.com/go-sql-driver/mysql = commit:d512f20
|
||||
github.com/go-xorm/core = commit:acb6f00
|
||||
github.com/go-xorm/xorm = commit:a8fba4d
|
||||
github.com/go-macaron/toolbox = commit:82b5115
|
||||
github.com/go-sql-driver/mysql = commit:1309049
|
||||
github.com/go-xorm/core = commit:9ddf4ee
|
||||
github.com/go-xorm/xorm = commit:e72082c
|
||||
github.com/gogits/chardet = commit:2404f77725
|
||||
github.com/gogits/git-shell = commit:1ffc4bc
|
||||
github.com/gogits/go-gogs-client = commit:4b541fa
|
||||
github.com/gogits/cron = commit:3abc0f8
|
||||
github.com/gogits/git-module = commit:a1c5096
|
||||
github.com/gogits/go-gogs-client = commit:d584b1e
|
||||
github.com/issue9/identicon = commit:f8c0d2c
|
||||
github.com/kardianos/minwinsvc = commit:cad6b2b
|
||||
github.com/klauspost/compress = commit:42eb574
|
||||
github.com/klauspost/cpuid = commit:eebb3ea
|
||||
github.com/klauspost/crc32 = commit:0aff1ea
|
||||
github.com/lib/pq = commit:11fc39a
|
||||
github.com/mattn/go-sqlite3 = commit:5651a9d
|
||||
github.com/klauspost/compress = commit:f962535
|
||||
github.com/klauspost/cpuid = commit:2c698c6
|
||||
github.com/klauspost/crc32 = commit:19b0b33
|
||||
github.com/lib/pq = commit:69552e5
|
||||
github.com/mattn/go-sqlite3 = commit:09d5c45
|
||||
github.com/mcuadros/go-version = commit:d52711f
|
||||
github.com/microcosm-cc/bluemonday = commit:4ac6f27
|
||||
github.com/msteinert/pam = commit:02ccfbf
|
||||
github.com/nfnt/resize = commit:dc93e1b98c
|
||||
github.com/russross/blackfriday = commit:d18b67a
|
||||
github.com/nfnt/resize = commit:4d93a29
|
||||
github.com/russross/blackfriday = commit:006144a
|
||||
github.com/satori/go.uuid = commit:e673fdd
|
||||
github.com/sergi/go-diff = commit:ec7fdbb
|
||||
github.com/shurcooL/sanitized_anchor_name = commit:10ef21a
|
||||
github.com/Unknwon/cae = commit:7f5e046
|
||||
github.com/Unknwon/com = commit:28b053d
|
||||
github.com/Unknwon/i18n = commit:3b48b66
|
||||
github.com/Unknwon/paginater = commit:7748a72
|
||||
golang.org/x/net = commit:d75b190
|
||||
golang.org/x/text = commit:458f474
|
||||
golang.org/x/crypto = commit:7b85b09
|
||||
golang.org/x/net = commit:4599ae7
|
||||
golang.org/x/text = commit:07b9a78
|
||||
golang.org/x/crypto = commit:1f22c01
|
||||
gopkg.in/asn1-ber.v1 = commit:4e86f43
|
||||
gopkg.in/gomail.v2 = commit:fbb71dd
|
||||
gopkg.in/ini.v1 = commit:a4e5487
|
||||
gopkg.in/ldap.v2 = commit:e9a325d
|
||||
gopkg.in/macaron.v1 = commit:1c6dd87
|
||||
gopkg.in/ini.v1 = commit:776aa73
|
||||
gopkg.in/ldap.v2 = commit:07a7330
|
||||
gopkg.in/macaron.v1 = commit:b9eee38
|
||||
gopkg.in/redis.v2 = commit:e617904962
|
||||
|
||||
[res]
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
@@ -13,7 +14,9 @@ before_install:
|
||||
install:
|
||||
- go get -t -v ./...
|
||||
|
||||
script: go build -v -tags "pam"
|
||||
script:
|
||||
- go build -v -tags "pam"
|
||||
- go test -v -cover -race ./...
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
||||
14
Dockerfile
14
Dockerfile
@@ -1,13 +1,10 @@
|
||||
FROM alpine:3.2
|
||||
MAINTAINER roemer.jp@gmail.com
|
||||
FROM alpine:3.3
|
||||
MAINTAINER jp@roemer.im
|
||||
|
||||
# Install system utils & Gogs runtime dependencies
|
||||
ADD https://github.com/tianon/gosu/releases/download/1.6/gosu-amd64 /usr/sbin/gosu
|
||||
RUN echo "@edge http://dl-4.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories \
|
||||
&& echo "@community http://dl-4.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories \
|
||||
&& apk -U --no-progress upgrade \
|
||||
&& apk -U --no-progress add ca-certificates bash git linux-pam s6@edge curl openssh socat \
|
||||
&& chmod +x /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
|
||||
|
||||
ENV GOGS_CUSTOM /data/gogs
|
||||
|
||||
@@ -15,6 +12,9 @@ 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
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
FROM sander85/rpi-alpine:latest
|
||||
MAINTAINER roemer.jp@gmail.com, raxetul@gmail.com
|
||||
FROM hypriot/rpi-alpine-scratch:v3.2
|
||||
MAINTAINER jp@roemer.im, raxetul@gmail.com
|
||||
|
||||
# Install system utils & Gogs runtime dependencies
|
||||
ADD https://github.com/tianon/gosu/releases/download/1.6/gosu-armhf /usr/sbin/gosu
|
||||
RUN echo "@edge http://dl-4.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories \
|
||||
&& echo "@community http://dl-4.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories \
|
||||
RUN echo "http://dl-4.alpinelinux.org/alpine/v3.3/main/" | tee /etc/apk/repositories \
|
||||
&& echo "http://dl-4.alpinelinux.org/alpine/v3.3/community/" | tee -a /etc/apk/repositories \
|
||||
&& echo "@edge http://dl-4.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories \
|
||||
&& apk -U --no-progress upgrade \
|
||||
&& apk -U --no-progress add ca-certificates bash git linux-pam s6@edge curl openssh socat \
|
||||
&& chmod +x /usr/sbin/gosu
|
||||
@@ -15,8 +16,11 @@ 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 ["/usr/bin/s6-svscan", "/app/gogs/docker/s6/"]
|
||||
CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]
|
||||
|
||||
11
Makefile
11
Makefile
@@ -16,12 +16,16 @@ NOW = $(shell date -u '+%Y%m%d%I%M%S')
|
||||
.IGNORE: public/css/gogs.css
|
||||
|
||||
build: $(GENERATED)
|
||||
go install -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
|
||||
go install -v -ldflags '$(LDFLAGS)' -tags '$(TAGS)'
|
||||
cp '$(GOPATH)/bin/gogs' .
|
||||
|
||||
govet:
|
||||
go tool vet -composites=false -methods=false -structtags=false .
|
||||
|
||||
build-dev: $(GENERATED) govet
|
||||
go install -v -race -tags '$(TAGS)'
|
||||
cp '$(GOPATH)/bin/gogs' .
|
||||
|
||||
pack:
|
||||
rm -rf $(RELEASE_GOGS)
|
||||
mkdir -p $(RELEASE_GOGS)
|
||||
@@ -34,7 +38,7 @@ release: build pack
|
||||
bindata: modules/bindata/bindata.go
|
||||
|
||||
modules/bindata/bindata.go: $(DATA_FILES)
|
||||
go-bindata -o=$@ -ignore="\\.DS_Store|README.md" -pkg=bindata conf/...
|
||||
go-bindata -o=$@ -ignore="\\.DS_Store|README.md|TRANSLATORS" -pkg=bindata conf/...
|
||||
|
||||
less: public/css/gogs.css
|
||||
|
||||
@@ -46,3 +50,6 @@ clean:
|
||||
|
||||
clean-mac: clean
|
||||
find . -name ".DS_Store" -print0 | xargs -0 rm
|
||||
|
||||
test:
|
||||
go test -cover -race ./...
|
||||
|
||||
25
README.md
25
README.md
@@ -3,7 +3,7 @@ Gogs - Go Git Service [
|
||||
|
||||
##### Current version: 0.8.0
|
||||
##### Current version: 0.8.43
|
||||
|
||||
| Web | UI | Preview |
|
||||
|:-------------:|:-------:|:-------:|
|
||||
@@ -13,13 +13,13 @@ Gogs - Go Git Service [ for bug report and contributing code. :bangbang:
|
||||
- Please [start discussion](http://forum.gogs.io/category/2/general-discussion) or [ask a question](http://forum.gogs.io/category/4/getting-help) on [the forum](http://forum.gogs.io/). GitHub issue tracker only keeps **bugs** and **feature requests**, all other topics will be closed without reason.
|
||||
- Due to testing purpose, data of [try.gogs.io](https://try.gogs.io) was reset in **Jan 28, 2015** and will reset multiple times after. Please do **NOT** put your important data on the site.
|
||||
- The demo site [try.gogs.io](https://try.gogs.io) is running under `develop` branch.
|
||||
- If you think there are vulnerabilities in the project, please talk privately to **u@gogs.io**. Thanks!
|
||||
- If you're interested in using APIs, we have experimental support with [documentation](https://github.com/gogits/go-gogs-client/wiki).
|
||||
- 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.
|
||||
1. :bangbang: You **MUST** **MUST** **MUST** read [CONTRIBUTING.md](https://github.com/gogits/gogs/blob/master/.github/CONTRIBUTING.md) for bug report and contributing code. :bangbang:
|
||||
2. **PLEASE** **PLEASE** **PLEASE** [ask questions](https://discuss.gogs.io/c/getting-help) on [the forum](https://discuss.gogs.io/). GitHub issue tracker only keeps **bugs** and **feature requests**, all other topics will be closed without reason.
|
||||
3. Due to testing purpose, data of [try.gogs.io](https://try.gogs.io) was reset in **Jan 28, 2015** and will reset multiple times after. Please do **NOT** put your important data on the site.
|
||||
4. The demo site [try.gogs.io](https://try.gogs.io) is running under `develop` branch.
|
||||
5. If you think there are vulnerabilities in the project, please talk privately to **u@gogs.io**. Thanks!
|
||||
6. If you're interested in using APIs, we have experimental support with [documentation](https://github.com/gogits/go-gogs-client/wiki).
|
||||
7. 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.
|
||||
|
||||
[简体中文](README_ZH.md)
|
||||
|
||||
@@ -82,10 +82,11 @@ There are 5 ways to install Gogs:
|
||||
- [阿里云上 Ubuntu 14.04 64 位安装 Gogs](http://my.oschina.net/luyao/blog/375654) (Chinese)
|
||||
- [Installing Gogs on FreeBSD](https://www.codejam.info/2015/03/installing-gogs-on-freebsd.html)
|
||||
- [Gogs on Raspberry Pi](http://blog.meinside.pe.kr/Gogs-on-Raspberry-Pi/)
|
||||
- [Cloudflare Full SSL with GOGS (Go Git Service) using NGINX](http://www.listekconsulting.com/articles/cloudflare-full-ssl-with-gogs-go-git-service-using-nginx/)
|
||||
|
||||
### Screencasts
|
||||
|
||||
- [Instalando Gogs no Ubuntu](http://blog.linuxpro.com.br/2015/08/14/instalando-gogs-no-ubuntu/) (Português)
|
||||
- [Instalando Gogs no Ubuntu](https://www.youtube.com/watch?v=4UkHAR1F7ZA) (Português)
|
||||
|
||||
### Deploy to Cloud
|
||||
|
||||
@@ -95,12 +96,16 @@ 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)
|
||||
|
||||
## Software and Service Support
|
||||
|
||||
- [Drone](https://github.com/drone/drone) (CI)
|
||||
- [Fabric8](http://fabric8.io/) (DevOps)
|
||||
- [Taiga](https://taiga.io/) (Project Management)
|
||||
- [Puppet](https://forge.puppetlabs.com/Siteminds/gogs) (IT)
|
||||
- [Kanboard](http://kanboard.net/plugin/gogs-webhook) (Project Management)
|
||||
- [BearyChat](https://bearychat.com/) (Team Communication)
|
||||
|
||||
### Product Support
|
||||
|
||||
@@ -110,11 +115,11 @@ There are 5 ways to install Gogs:
|
||||
## Acknowledgments
|
||||
|
||||
- Router and middleware mechanism of [Macaron](https://github.com/go-macaron/macaron).
|
||||
- Modules design is inspired by [WeTalk](https://github.com/beego/wetalk).
|
||||
- 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 [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.
|
||||
|
||||
## Contributors
|
||||
|
||||
|
||||
@@ -67,12 +67,16 @@ 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)
|
||||
|
||||
## 软件及服务支持
|
||||
|
||||
- [Drone](https://github.com/drone/drone)(CI)
|
||||
- [Fabric8](http://fabric8.io/)(DevOps)
|
||||
- [Taiga](https://taiga.io/)(项目管理)
|
||||
- [Puppet](https://forge.puppetlabs.com/Siteminds/gogs)(IT)
|
||||
- [Kanboard](http://kanboard.net/plugin/gogs-webhook)(项目管理)
|
||||
- [BearyChat](https://bearychat.com/)(团队交流)
|
||||
|
||||
### 产品支持
|
||||
|
||||
@@ -82,11 +86,11 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
## 特别鸣谢
|
||||
|
||||
- 基于 [Macaron](https://github.com/go-macaron/macaron) 的路由与中间件机制。
|
||||
- 基于 [WeTalk](https://github.com/beego/wetalk) 修改的模块设计。
|
||||
- 基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改的系统监视状态。
|
||||
- 感谢 [lavachen](http://www.lavachen.cn/) 和 [Rocker](http://weibo.com/rocker1989) 设计的 Logo。
|
||||
- 感谢 [Crowdin](https://crowdin.com/project/gogs) 提供免费的开源项目本地化支持。
|
||||
- 感谢 [DigitalOcean](https://www.digitalocean.com) 提供主站和体验站点的服务器赞助。
|
||||
- 感谢 [KeyCDN](https://www.keycdn.com/) 提供 CDN 服务赞助。
|
||||
|
||||
## 贡献成员
|
||||
|
||||
|
||||
@@ -14,11 +14,10 @@ import (
|
||||
)
|
||||
|
||||
var CmdCert = cli.Command{
|
||||
Name: "cert",
|
||||
Usage: "Generate self-signed certificate",
|
||||
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
||||
Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
||||
Action: runCert,
|
||||
Name: "cert",
|
||||
Usage: "Generate self-signed certificate",
|
||||
Description: `Please use build tags "cert" to rebuild Gogs in order to have this ability`,
|
||||
Action: runCert,
|
||||
}
|
||||
|
||||
func runCert(ctx *cli.Context) {
|
||||
|
||||
39
cmd/serve.go
39
cmd/serve.go
@@ -15,12 +15,13 @@ import (
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/codegangsta/cli"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
|
||||
"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"
|
||||
"github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -41,11 +42,6 @@ func setup(logPath string) {
|
||||
setting.NewContext()
|
||||
log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
|
||||
|
||||
if setting.DisableSSH {
|
||||
println("Gogs: SSH has been disabled")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
models.LoadConfigs()
|
||||
|
||||
if setting.UseSQLite3 || setting.UseTiDB {
|
||||
@@ -87,7 +83,7 @@ func fail(userMessage, logMessage string, args ...interface{}) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func handleUpdateTask(uuid string, user *models.User, username, reponame string, isWiki bool) {
|
||||
func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string, isWiki bool) {
|
||||
task, err := models.GetUpdateTaskByUUID(uuid)
|
||||
if err != nil {
|
||||
if models.IsErrUpdateTaskNotExist(err) {
|
||||
@@ -103,14 +99,21 @@ func handleUpdateTask(uuid string, user *models.User, username, reponame string,
|
||||
return
|
||||
}
|
||||
|
||||
if err = models.Update(task.RefName, task.OldCommitID, task.NewCommitID,
|
||||
user.Name, username, reponame, user.Id); err != nil {
|
||||
if err = models.PushUpdate(models.PushUpdateOptions{
|
||||
RefName: task.RefName,
|
||||
OldCommitID: task.OldCommitID,
|
||||
NewCommitID: task.NewCommitID,
|
||||
PusherID: user.Id,
|
||||
PusherName: user.Name,
|
||||
RepoUserName: repoUser.Name,
|
||||
RepoName: reponame,
|
||||
}); err != nil {
|
||||
log.GitLogger.Error(2, "Update: %v", err)
|
||||
}
|
||||
|
||||
// Ask for running deliver hook and test pull request tasks.
|
||||
reqURL := setting.LocalUrl + username + "/" + reponame + "/tasks/trigger?branch=" +
|
||||
strings.TrimPrefix(task.RefName, "refs/heads/")
|
||||
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)
|
||||
|
||||
resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
|
||||
@@ -130,8 +133,14 @@ func runServ(c *cli.Context) {
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
}
|
||||
|
||||
setup("serv.log")
|
||||
|
||||
if setting.DisableSSH {
|
||||
println("Gogs: SSH has been disabled")
|
||||
return
|
||||
}
|
||||
|
||||
if len(c.Args()) < 1 {
|
||||
fail("Not enough arguments", "Not enough arguments")
|
||||
}
|
||||
@@ -163,7 +172,7 @@ func runServ(c *cli.Context) {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
fail("Repository owner does not exist", "Unregistered owner: %s", username)
|
||||
}
|
||||
fail("Internal error", "Failed to get repository owner(%s): %v", username, err)
|
||||
fail("Internal error", "Failed to get repository owner (%s): %v", username, err)
|
||||
}
|
||||
|
||||
repo, err := models.GetRepositoryByName(repoUser.Id, reponame)
|
||||
@@ -208,7 +217,7 @@ func runServ(c *cli.Context) {
|
||||
}
|
||||
// Check if this deploy key belongs to current repository.
|
||||
if !models.HasDeployKey(key.ID, repo.ID) {
|
||||
fail("Key access denied", "Key access denied: %d-%d", 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.
|
||||
@@ -242,7 +251,7 @@ func runServ(c *cli.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
uuid := uuid.NewV4().String()
|
||||
uuid := gouuid.NewV4().String()
|
||||
os.Setenv("uuid", uuid)
|
||||
|
||||
// Special handle for Windows.
|
||||
@@ -266,7 +275,7 @@ func runServ(c *cli.Context) {
|
||||
}
|
||||
|
||||
if requestedMode == models.ACCESS_MODE_WRITE {
|
||||
handleUpdateTask(uuid, user, username, reponame, isWiki)
|
||||
handleUpdateTask(uuid, user, repoUser, reponame, isWiki)
|
||||
}
|
||||
|
||||
// Update user key activity.
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
|
||||
var CmdUpdate = cli.Command{
|
||||
Name: "update",
|
||||
Usage: "This command should only be called by SSH shell",
|
||||
Usage: "This command should only be called by Git hook",
|
||||
Description: `Update get pushed info and insert into database`,
|
||||
Action: runUpdate,
|
||||
Flags: []cli.Flag{
|
||||
@@ -28,18 +28,19 @@ func runUpdate(c *cli.Context) {
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
}
|
||||
cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
|
||||
if cmd == "" {
|
||||
return
|
||||
}
|
||||
|
||||
setup("update.log")
|
||||
|
||||
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
||||
log.GitLogger.Trace("SSH_ORIGINAL_COMMAND is empty")
|
||||
return
|
||||
}
|
||||
|
||||
args := c.Args()
|
||||
if len(args) != 3 {
|
||||
log.GitLogger.Fatal(2, "received less 3 parameters")
|
||||
} else if args[0] == "" {
|
||||
log.GitLogger.Fatal(2, "refName is empty, shouldn't use")
|
||||
log.GitLogger.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")
|
||||
}
|
||||
|
||||
task := models.UpdateTask{
|
||||
|
||||
56
cmd/web.go
56
cmd/web.go
@@ -29,11 +29,11 @@ import (
|
||||
"gopkg.in/ini.v1"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"github.com/gogits/git-shell"
|
||||
"github.com/gogits/git-module"
|
||||
"github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/avatar"
|
||||
"github.com/gogits/gogs/modules/bindata"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/middleware"
|
||||
@@ -80,7 +80,7 @@ func checkVersion() {
|
||||
// Check dependency version.
|
||||
checkers := []VerChecker{
|
||||
{"github.com/go-xorm/xorm", func() string { return xorm.Version }, "0.4.4.1029"},
|
||||
{"github.com/go-macaron/binding", binding.Version, "0.1.0"},
|
||||
{"github.com/go-macaron/binding", binding.Version, "0.2.1"},
|
||||
{"github.com/go-macaron/cache", cache.Version, "0.1.2"},
|
||||
{"github.com/go-macaron/csrf", csrf.Version, "0.0.3"},
|
||||
{"github.com/go-macaron/i18n", i18n.Version, "0.2.0"},
|
||||
@@ -88,7 +88,8 @@ func checkVersion() {
|
||||
{"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, "0.8.0"},
|
||||
{"github.com/gogits/git-shell", git.Version, "0.1.0"},
|
||||
{"github.com/gogits/git-module", git.Version, "0.2.7"},
|
||||
{"github.com/gogits/go-gogs-client", gogs.Version, "0.7.3"},
|
||||
}
|
||||
for _, c := range checkers {
|
||||
if !version.Compare(c.Version(), c.Expected, ">=") {
|
||||
@@ -243,11 +244,6 @@ func runWeb(ctx *cli.Context) {
|
||||
})
|
||||
// ***** END: User *****
|
||||
|
||||
// Gravatar service.
|
||||
avt := avatar.CacheServer("public/img/avatar/", "public/img/avatar_default.jpg")
|
||||
os.MkdirAll("public/img/avatar/", os.ModePerm)
|
||||
m.Get("/avatar/:hash", avt.ServeHTTP)
|
||||
|
||||
adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true})
|
||||
|
||||
// ***** START: Admin *****
|
||||
@@ -289,7 +285,13 @@ func runWeb(ctx *cli.Context) {
|
||||
// ***** END: Admin *****
|
||||
|
||||
m.Group("", func() {
|
||||
m.Get("/:username", user.Profile)
|
||||
m.Group("/:username", func() {
|
||||
m.Get("", user.Profile)
|
||||
m.Get("/followers", user.Followers)
|
||||
m.Get("/following", user.Following)
|
||||
m.Get("/stars", user.Stars)
|
||||
})
|
||||
|
||||
m.Get("/attachments/:uuid", func(ctx *middleware.Context) {
|
||||
attach, err := models.GetAttachmentByUUID(ctx.Params(":uuid"))
|
||||
if err != nil {
|
||||
@@ -319,6 +321,10 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Post("/issues/attachments", repo.UploadIssueAttachment)
|
||||
}, ignSignIn)
|
||||
|
||||
m.Group("/:username", func() {
|
||||
m.Get("/action/:action", user.Action)
|
||||
}, reqSignIn)
|
||||
|
||||
if macaron.Env == macaron.DEV {
|
||||
m.Get("/template/*", dev.TemplatePreview)
|
||||
}
|
||||
@@ -338,11 +344,14 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Get("/members/action/:action", org.MembersAction)
|
||||
|
||||
m.Get("/teams", org.Teams)
|
||||
}, middleware.OrgAssignment(true))
|
||||
|
||||
m.Group("/:org", func() {
|
||||
m.Get("/teams/:team", org.TeamMembers)
|
||||
m.Get("/teams/:team/repositories", org.TeamRepositories)
|
||||
m.Route("/teams/:team/action/:action", "GET,POST", org.TeamsAction)
|
||||
m.Route("/teams/:team/action/repo/:action", "GET,POST", org.TeamsRepoAction)
|
||||
}, middleware.OrgAssignment(true))
|
||||
}, middleware.OrgAssignment(true, false, true))
|
||||
|
||||
m.Group("/:org", func() {
|
||||
m.Get("/teams/new", org.NewTeam)
|
||||
@@ -389,7 +398,7 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Group("/settings", func() {
|
||||
m.Combo("").Get(repo.Settings).
|
||||
Post(bindIgnErr(auth.RepoSettingForm{}), repo.SettingsPost)
|
||||
m.Route("/collaboration", "GET,POST", repo.Collaboration)
|
||||
m.Combo("/collaboration").Get(repo.Collaboration).Post(repo.CollaborationPost)
|
||||
|
||||
m.Group("/hooks", func() {
|
||||
m.Get("", repo.Webhooks)
|
||||
@@ -420,9 +429,8 @@ func runWeb(ctx *cli.Context) {
|
||||
})
|
||||
}, reqSignIn, middleware.RepoAssignment(), reqRepoAdmin, middleware.RepoRef())
|
||||
|
||||
m.Get("/:username/:reponame/action/:action", reqSignIn, middleware.RepoAssignment(), repo.Action)
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Get("/action/:action", repo.Action)
|
||||
|
||||
m.Group("/issues", func() {
|
||||
m.Combo("/new", repo.MustEnableIssues).Get(middleware.RepoRef(), repo.NewIssue).
|
||||
Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
|
||||
@@ -462,9 +470,9 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Post("/delete", repo.DeleteRelease)
|
||||
}, reqRepoAdmin, middleware.RepoRef())
|
||||
|
||||
m.Combo("/compare/*", repo.MustEnablePulls).Get(repo.CompareAndPullRequest).
|
||||
m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest).
|
||||
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
|
||||
}, reqSignIn, middleware.RepoAssignment())
|
||||
}, reqSignIn, middleware.RepoAssignment(), repo.MustBeNotBare)
|
||||
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Group("", func() {
|
||||
@@ -492,23 +500,25 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Get("/archive/*", repo.Download)
|
||||
|
||||
m.Group("/pulls/:index", func() {
|
||||
m.Get("/commits", repo.ViewPullCommits)
|
||||
m.Get("/files", repo.ViewPullFiles)
|
||||
m.Get("/commits", middleware.RepoRef(), repo.ViewPullCommits)
|
||||
m.Get("/files", middleware.RepoRef(), repo.ViewPullFiles)
|
||||
m.Post("/merge", reqRepoAdmin, repo.MergePullRequest)
|
||||
}, repo.MustEnablePulls)
|
||||
}, repo.MustAllowPulls)
|
||||
|
||||
m.Group("", func() {
|
||||
m.Get("/src/*", repo.Home)
|
||||
m.Get("/raw/*", repo.SingleDownload)
|
||||
m.Get("/commits/*", repo.RefCommits)
|
||||
m.Get("/commit/*", repo.Diff)
|
||||
m.Get("/stars", repo.Stars)
|
||||
m.Get("/watchers", repo.Watchers)
|
||||
m.Get("/forks", repo.Forks)
|
||||
}, middleware.RepoRef())
|
||||
|
||||
m.Get("/compare/:before([a-z0-9]{40})...:after([a-z0-9]{40})", repo.CompareDiff)
|
||||
}, ignSignIn, middleware.RepoAssignment())
|
||||
m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.CompareDiff)
|
||||
}, ignSignIn, middleware.RepoAssignment(), repo.MustBeNotBare)
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Get("/stars", repo.Stars)
|
||||
m.Get("/watchers", repo.Watchers)
|
||||
}, ignSignIn, middleware.RepoAssignment(), middleware.RepoRef())
|
||||
|
||||
m.Group("/:username", func() {
|
||||
m.Group("/:reponame", func() {
|
||||
|
||||
30
conf/app.ini
30
conf/app.ini
@@ -27,6 +27,10 @@ EXPLORE_PAGING_NUM = 20
|
||||
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`
|
||||
|
||||
[ui.admin]
|
||||
; Number of users that are showed in one page
|
||||
@@ -41,6 +45,9 @@ ORG_PAGING_NUM = 50
|
||||
[markdown]
|
||||
; Enable hard line break extension
|
||||
ENABLE_HARD_LINE_BREAK = false
|
||||
; List of custom URL-Schemes that are allowed as links when rendering Markdown
|
||||
; for example git,magnet
|
||||
CUSTOM_URL_SCHEMES =
|
||||
|
||||
[server]
|
||||
PROTOCOL = http
|
||||
@@ -57,11 +64,12 @@ DISABLE_SSH = false
|
||||
; Whether use builtin SSH server or not.
|
||||
START_SSH_SERVER = false
|
||||
SSH_PORT = 22
|
||||
; Root path of SSH directory
|
||||
SSH_ROOT_PATH =
|
||||
; Disable CDN even in "prod" mode
|
||||
OFFLINE_MODE = false
|
||||
DISABLE_ROUTER_LOG = false
|
||||
; Generate steps:
|
||||
; $ cd path/to/gogs/custom/https
|
||||
; $ ./gogs cert -ca=true -duration=8760h0m0s -host=myhost.example.com
|
||||
;
|
||||
; Or from a .pfx file exported from the Windows certificate store (do
|
||||
@@ -87,7 +95,7 @@ USER = root
|
||||
PASSWD =
|
||||
; For "postgres" only, either "disable", "require" or "verify-full"
|
||||
SSL_MODE = disable
|
||||
; For "sqlite3" and "tidb"
|
||||
; For "sqlite3" and "tidb", use absolute path when you start as service
|
||||
PATH = data/gogs.db
|
||||
|
||||
[admin]
|
||||
@@ -112,28 +120,14 @@ REGISTER_EMAIL_CONFIRM = false
|
||||
DISABLE_REGISTRATION = false
|
||||
; User must sign in to view anything.
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
; Cache avatar as picture
|
||||
ENABLE_CACHE_AVATAR = false
|
||||
; Mail notification
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
; More detail: https://github.com/gogits/gogs/issues/165
|
||||
ENABLE_REVERSE_PROXY_AUTHENTICATION = false
|
||||
ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
|
||||
; Do not check minimum key size with corresponding type
|
||||
DISABLE_MINIMUM_KEY_SIZE_CHECK = false
|
||||
; Enable captcha validation for registration
|
||||
ENABLE_CAPTCHA = true
|
||||
|
||||
; used to filter keys which are too short
|
||||
[service.minimum_key_sizes]
|
||||
ED25519 = 256
|
||||
ECDSA = 256
|
||||
NTRU = 1087
|
||||
MCE = 1702
|
||||
McE = 1702
|
||||
RSA = 1024
|
||||
DSA = 1024
|
||||
|
||||
[webhook]
|
||||
; Hook task queue length
|
||||
QUEUE_LENGTH = 1000
|
||||
@@ -339,6 +333,10 @@ pl-PL = pl
|
||||
bg-BG = bg
|
||||
it-IT = it
|
||||
|
||||
; Extension mapping to highlight class
|
||||
; e.g. .toml=ini
|
||||
[highlight.mapping]
|
||||
|
||||
[other]
|
||||
SHOW_FOOTER_BRANDING = false
|
||||
; Show version information about gogs and go in the footer
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
Creative Commons CC0 1.0 Universal
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
|
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
|
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
|
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
|
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
|
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
|
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
|
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
|
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
|
||||
@@ -1,30 +1,44 @@
|
||||
# This file lists all PUBLIC individuals having contributed content to the translation.
|
||||
# Entries are in alphabetical order.
|
||||
|
||||
Adam Strzelecki <ono AT java DOT pl>
|
||||
Adrian Verde <me AT adrianverde DOT com>
|
||||
Akihiro YAGASAKI <yaggytter AT momiage DOT com>
|
||||
Aleksejs Grocevs <aleksejs AT grocevs DOT pro>
|
||||
Aleksey Tarakin <hukendo AT yandex DOT ru>
|
||||
Alexander Steinhöfer <kontakt AT lx-s DOT de>
|
||||
Alexandre Magno <alexandre DOT mbm AT gmail DOT com>
|
||||
Andrey Nering <andrey AT nering DOT com DOT br>
|
||||
Andrey Solomatin <toadron AT yandex DOT ru>
|
||||
Antoine GIRARD <sapk AT sapk DOT fr>
|
||||
Arthur Aslanyan <arthur DOT e DOT aslanyan AT gmail DOT com>
|
||||
Barış Arda Yılmaz <ardayilmazgamer AT gmail DOT com>
|
||||
Christoph Kisfeld <christoph DOT kisfeld AT gmail DOT com>
|
||||
Cysioland
|
||||
Daniel Speichert <daniel AT speichert DOT pl>
|
||||
David Yzaguirre <dvdyzag AT gmail DOT com>
|
||||
Dmitriy Nogay <me AT catwhocode DOT ga>
|
||||
Ezequiel Gonzalez Rial <gonrial AT gmail DOT com>
|
||||
Gregor Santner <gdev AT live DOT de>
|
||||
Hamid Feizabadi <hamidfzm AT gmail DOT com>
|
||||
Huimin Wang <wanghm2009 AT hotmail DOT co DOT jp>
|
||||
ilko
|
||||
ilko <kontact-mr.k AT outlook DOT com">
|
||||
Ilya Makarov
|
||||
Juraj Bubniak <contact AT jbub DOT eu>
|
||||
Lafriks <lafriks AT gmail DOT com>
|
||||
Lauri Ojansivu <x AT xet7 DOT org>
|
||||
Luc Stepniewski <luc AT stepniewski DOT fr>
|
||||
Luca Kröger <l DOT kroeger01 AT gmail DOT com>
|
||||
Marc Schiller <marc AT schiller DOT im>
|
||||
Miguel de la Cruz <miguel AT mcrx DOT me>
|
||||
Mikhail Burdin <xdshot9000 AT gmail DOT com>
|
||||
Morten Sørensen <klim8d AT gmail DOT com>
|
||||
Nakao Takamasa <at.mattenn AT gmail DOT com>
|
||||
Natan Albuquerque <natanalbuquerque5 AT gmail DOT com>
|
||||
Odilon Junior <odilon DOT junior93 AT gmail DOT com>
|
||||
Thomas Fanninger <gogs DOT thomas AT fanninger DOT at>
|
||||
Tilmann Bach <tilmann AT outlook DOT com>
|
||||
Toni Villena Jiménez <tonivj5 AT gmail DOT com>
|
||||
Vladimir Vissoultchev <wqweto AT gmail DOT com>
|
||||
YJSoft <yjsoft AT yjsoft DOT pe DOT kr>
|
||||
Łukasz Jan Niemier <lukasz AT niemier DOT pl>
|
||||
|
||||
@@ -38,7 +38,7 @@ settings=Настройки
|
||||
your_profile=Вашият профил
|
||||
your_settings=Вашите настройки
|
||||
|
||||
news_feed=Поток новини
|
||||
activities=Активности
|
||||
pull_requests=Заявки за сливане
|
||||
issues=Задачи
|
||||
|
||||
@@ -65,7 +65,7 @@ db_name=Име на база данни
|
||||
db_helper=Моля, използвайте INNODB engine с utf8_general_ci кодиране на знаци за MySQL.
|
||||
ssl_mode=Режим SSL
|
||||
path=Път
|
||||
sqlite_helper=Файл на SQLite3 или TiDB база данни.
|
||||
sqlite_helper=Файл на SQLite3 или TiDB база данни.<br>Моля използвайте абсолютен път до файл когато стартирате Gogs като услуга.
|
||||
err_empty_db_path=Пътят до SQLite3 или TiDB база данни не може да е празен.
|
||||
err_invalid_tidb_name=TiDB не позволява "." и "-" в името на базата данни.
|
||||
no_admin_and_disable_registration=Невъзможно изключване на регистрациите без предварително да е създаден поне един административен профил.
|
||||
@@ -86,6 +86,8 @@ http_port=HTTP порт
|
||||
http_port_helper=Порт, на който приложението ще слуша.
|
||||
app_url=URL адрес на приложението
|
||||
app_url_helper=Този настройка променя HTTP/HTTPS адреса за клониране, а понякога и адреса на ел. поща.
|
||||
log_root_path=Път към журналите
|
||||
log_root_path_helper=Директория в която се записват журналите.
|
||||
|
||||
optional_title=Опционални настройки
|
||||
email_title=Настройки на пощенска услуга
|
||||
@@ -122,6 +124,7 @@ run_user_not_match=Потребителският контекст на прил
|
||||
save_config_failed=Неуспешно запазване на конфигурация: %v
|
||||
invalid_admin_setting=Настройките на профил на администратора са невалидни: %v
|
||||
install_success=Добре дошли! Радваме се, че избрахте Gogs, и Ви пожелаваме приятна работа и сърдечни поздрави!
|
||||
invalid_log_root_path=Основният път към журналите е невалиден: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Име или ел. поща
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken=Името на хранилището вече се пол
|
||||
org_name_been_taken=Името на организацията вече се ползва.
|
||||
team_name_been_taken=Името на екипа вече се ползва.
|
||||
email_been_used=Този адрес на ел. поща вече се ползва.
|
||||
illegal_team_name=Името на екипа съдържа недопустими знаци.
|
||||
username_password_incorrect=Потребителското име или паролата не са верни.
|
||||
enterred_invalid_repo_name=Моля уверете се, че въведеното име на хранилище е вярно.
|
||||
enterred_invalid_owner_name=Моля уверете се, че въведеното име на притежател е вярно.
|
||||
@@ -232,6 +234,8 @@ activity=Публична дейност
|
||||
followers=Последователи
|
||||
starred=Харесано
|
||||
following=Следване
|
||||
follow=Следване
|
||||
unfollow=Не следвай
|
||||
|
||||
form.name_reserved=Потребителското име '%s' е запазено.
|
||||
form.name_pattern_not_allowed=Потребителското име '%s' не е допустимо.
|
||||
@@ -492,6 +496,7 @@ issues.label_modify=Промяна на етикет
|
||||
issues.label_deletion=Изтрий етикет
|
||||
issues.label_deletion_desc=При изтриване на този етикет ще се премахне информацията за него във всички свързани задачи. Желаете ли да продължите?
|
||||
issues.label_deletion_success=Етикетът е изтрит успешно!
|
||||
issues.num_participants=%d участника
|
||||
|
||||
pulls.new=Нова заявка за сливане
|
||||
pulls.compare_changes=Сравни промените
|
||||
@@ -579,14 +584,19 @@ settings.tracker_url_format=Формат на URL адрес на външна
|
||||
settings.tracker_url_format_desc=Можете да използвате текстови маркери <code>{user} {repo} {index}</code> за потребителско име, име на хранилище и индекс на задача съответно.
|
||||
settings.pulls_desc=Включва заявки за сливане за да може да се приемат външни доработки
|
||||
settings.danger_zone=Опасна зона
|
||||
settings.new_owner_has_same_repo=Новият притежател вече има хранилище със същото име. Изберете друго име.
|
||||
settings.convert=Промени към редовно хранилище
|
||||
settings.convert_desc=Можете да промените това огледало към редовно хранилище. Конверсията не може да се отмени.
|
||||
settings.convert_notices_1=- Тази операция ще конвертира огледалото към редовно хранилище и не може да бъде отменена в последствие.
|
||||
settings.convert_confirm=Потвърдете конверсията
|
||||
settings.convert_succeed=Конверсията към редовно хранилище е извършена успешно.
|
||||
settings.transfer=Прехвърли притежание
|
||||
settings.transfer_desc=Прехвърля това хранилище на друг потребител или към организация, в която имате права на администратор.
|
||||
settings.new_owner_has_same_repo=Новият притежател вече има хранилище със същото име. Изберете друго име.
|
||||
settings.delete=Изтрий това хранилище
|
||||
settings.delete_desc=След като изтриете хранилището, няма връщане назад. Моля, бъдете сигурни.
|
||||
settings.transfer_notices_1=- Вие ще загубите достъп, ако новият притежател е индивидуален потребител.
|
||||
settings.transfer_notices_2=- Вие ще запазите достъпа си, ако новият притежател е организация и ако вие сте един от притежателите ѝ.
|
||||
settings.transfer_form_title=Моля въведете следната информация за да потвърдите операцията:
|
||||
settings.delete=Изтрий това хранилище
|
||||
settings.delete_desc=След като изтриете хранилището, няма връщане назад. Моля, бъдете сигурни.
|
||||
settings.delete_notices_1=- Тази операция <strong>НЕ МОЖЕ</strong> да бъде отменена в последствие.
|
||||
settings.delete_notices_2=- Тази операция ще изтрие всичко от това хранилище, включително Git данни, задачи, коментари и достъпа на сътрудници.
|
||||
settings.delete_notices_fork_1=- Ако това хранилище е публично, всички негови разклонения ще останат независими след изтриването му.
|
||||
@@ -602,6 +612,7 @@ settings.add_collaborator=Добави нов сътрудник
|
||||
settings.add_collaborator_success=Добавен е нов сътрудник.
|
||||
settings.remove_collaborator_success=Сътрудникът е премахнат.
|
||||
settings.search_user_placeholder=Име на потребител...
|
||||
settings.org_not_allowed_to_be_collaborator=Невъзможно добавяне на организация като сътрудник.
|
||||
settings.user_is_org_member=Потребителят вече участва в организацията и не може да бъде добавен като сътрудник.
|
||||
settings.add_webhook=Добави уеб-кука
|
||||
settings.hooks_desc=Уеб-куките много приличат на обикновен HTTP POST тригер. Когато нещо се случи в Gogs, ние ще изпратим уведомление до сървъра, който посочите. Научете повече в <a target="_blank" href="%s">Ръководство за уеб-куки</a>.
|
||||
@@ -666,6 +677,8 @@ diff.parent=родител
|
||||
diff.commit=ревизия
|
||||
diff.data_not_available=Няма данни за разлики.
|
||||
diff.show_diff_stats=Покажи статистика за разликите
|
||||
diff.show_split_view=Разделен изглед
|
||||
diff.show_unified_view=Обединен изглед
|
||||
diff.stats_desc=променени са <strong>%d файла</strong>, в които са <strong>добавени %d</strong> реда и са <strong>изтрити %d</strong> реда
|
||||
diff.bin=BIN
|
||||
diff.view_file=Целия файл
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys=Презапис на ".ssh/authorized_keys" фай
|
||||
dashboard.resync_all_sshkeys_success=Всички публични ключове са презаписани успешно.
|
||||
dashboard.resync_all_update_hooks=Презапис на всички куки, закачени на актуализация на хранилищата (необходимо, когато се ползва собствен път за конфигурацията)
|
||||
dashboard.resync_all_update_hooks_success=Всички куки, закачени на актуализация на хранилищата, са презаписани успешно.
|
||||
dashboard.reinit_missing_repos=Реинициализира всички записи за хранилища
|
||||
dashboard.reinit_missing_repos_success=Всички записи за хранилища със загубени Git файлове са реинициализирани успешно.
|
||||
|
||||
dashboard.server_uptime=Операционно време
|
||||
dashboard.current_goroutine=Текущи Goroutines
|
||||
@@ -907,6 +922,7 @@ auths.attribute_username_placeholder=Оставете празно за да и
|
||||
auths.attribute_name=Атрибут за име
|
||||
auths.attribute_surname=Атрибут за фамилия
|
||||
auths.attribute_mail=Атрибут за ел. поща
|
||||
auths.attributes_in_bind=Извличане на атрибути от контекста на име (DN) за свръзка
|
||||
auths.filter=Филтър за потребител
|
||||
auths.admin_filter=Филтър за администратор
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm=Изисквай потвърждение на а
|
||||
config.disable_register=Изключи нови регистрации
|
||||
config.show_registration_button=Покажи бутон за регистрация
|
||||
config.require_sign_in_view=Изисквай вписване за преглед
|
||||
config.enable_cache_avatar=Включи кеширане на аватари
|
||||
config.mail_notify=Уведомяване по ел. поща
|
||||
config.disable_key_size_check=Изключи проверка минимален размер на ключ
|
||||
config.enable_captcha=Включи Captcha
|
||||
@@ -1025,6 +1040,8 @@ create_repo=създаде хранилище <a href="%s"> %s</a>
|
||||
rename_repo=преименува хранилище от <code>%[1]s</code> на <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=предаде към <a href="%[1]s/src/%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`отвори задача <a href="%s/issues/%s">%s#%[2]s"</a>`
|
||||
close_issue=`closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`създаде заявка за сливане <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`коментира задача <a href="%s/issues/%s">%s#%[2]s"</a>`
|
||||
merge_pull_request=`обедини заявка за сливане <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
app_desc=Ein einfacher, selbst gehosteter Git-Service, geschrieben in Go
|
||||
app_desc=Ein einfacher, selbst gehosteter Git-Service
|
||||
|
||||
home=Home
|
||||
dashboard=Übersicht
|
||||
@@ -35,12 +35,12 @@ manage_org=Organisationen verwalten
|
||||
admin_panel=Admin-Panel
|
||||
account_settings=Kontoeinstellungen
|
||||
settings=Einstellungen
|
||||
your_profile=Dein Profil
|
||||
your_settings=Deine Einstellungen
|
||||
your_profile=Ihr Profil
|
||||
your_settings=Ihre Einstellungen
|
||||
|
||||
news_feed=Neuigkeiten
|
||||
pull_requests=Pull Requests
|
||||
issues=Issues
|
||||
activities=Aktivitäten
|
||||
pull_requests=Pull-Requests
|
||||
issues=Tickets
|
||||
|
||||
cancel=Abbrechen
|
||||
|
||||
@@ -62,10 +62,10 @@ host=Host
|
||||
user=Benutzer
|
||||
password=Passwort
|
||||
db_name=Datenbankname
|
||||
db_helper=Bitte verwenden sie die InnoDB-Engine mit utf8_general_ci Zeichensatz für MySQL.
|
||||
db_helper=Bitte verwenden Sie in MySQL die InnoDB-Engine mit dem Zeichensatz utf8_general_ci.
|
||||
ssl_mode=SSL-Modus
|
||||
path=Pfad
|
||||
sqlite_helper=Der Dateipfad zur SQLite3 oder TiDB Datenbank.
|
||||
sqlite_helper=Der Dateipfad zur SQLite3- oder TiDB-Datenbank. <br> Bitte benutze eine absolute Pfadangabe, wenn Gogs als Service gestartet wird.
|
||||
err_empty_db_path=SQLite3 oder TiDB Datenbankpfad darf nicht leer sein.
|
||||
err_invalid_tidb_name=Der TiDB Datenbankname darf kein "." und kein "-" enthalten.
|
||||
no_admin_and_disable_registration=Du kannst die Registrierung nicht deaktivieren, ohne ein Administratorkonto zu erstellen.
|
||||
@@ -86,6 +86,8 @@ http_port=HTTP Port
|
||||
http_port_helper=Auf dieser Port Nummer wird Gogs erreichbar sein.
|
||||
app_url=Anwendungs-URL
|
||||
app_url_helper=Dies hat Auswirkung auf die HTTP/HTTPS clone URLs und für die E-Mails.
|
||||
log_root_path=Protokollpfad
|
||||
log_root_path_helper=Verzeichnis in das Logdateien geschrieben werden.
|
||||
|
||||
optional_title=Optionale Einstellungen
|
||||
email_title=E-Mail-Service Einstellungen
|
||||
@@ -93,18 +95,18 @@ smtp_host=SMTP Host
|
||||
smtp_from=Von
|
||||
smtp_from_helper=Absender-Adresse nach RFC 5322. Entweder nur eine E-Mail Adresse oder im folgenden Format: "Name" <email@example.com>.
|
||||
mailer_user=Sender E-mail
|
||||
mailer_password=Sender Passwort
|
||||
mailer_password=Absender Passwort
|
||||
register_confirm=Registrierungsbestätigung aktivieren
|
||||
mail_notify=E-Mail-Benachrichtigungen aktivieren
|
||||
mail_notify=E-Mail-Benachrichtigung aktivieren
|
||||
server_service_title=Server- und sonstige Diensteinstellungen
|
||||
offline_mode=Offline-Modus aktivieren
|
||||
offline_mode_popup=Deaktiviere das CDN auch im Produktionsmodus, alle Dateien werden von diesem Server ausgeliefert.
|
||||
disable_gravatar=Gravatar-Dienst deaktivieren
|
||||
disable_gravatar_popup=Gravatar und benutzerdefinierte Quellen deaktivieren, alle Avatare werden standardmäßig vom Nutzer hochgeladen oder sind Standardavatare.
|
||||
disable_registration=Benutzerregistrierung deaktivieren
|
||||
disable_registration=Selbstregistrierung deaktivieren
|
||||
disable_registration_popup=Deaktiviere die Benutzerregistrierung, nur Administratoren können Benutzerkonten anlegen.
|
||||
enable_captcha=Captcha aktivieren
|
||||
enable_captcha_popup=Benötigt Captcha-Überprüfung für Registrierung durch Benutzer.
|
||||
enable_captcha_popup=Verlange Captcha-Überprüfung für Selbst-Registrierung.
|
||||
require_sign_in_view=Erfordere Anmeldung, um Inhalte anzusehen
|
||||
require_sign_in_view_popup=Lediglich angemeldete Benutzer können Inhalte betrachten, Gäste sehen nur die Anmelden/Registrieren Seite.
|
||||
admin_setting_desc=Sie müssen jetzt noch keinen Administrator-Account anlegen. Der erste Benutzer ("ID=1") erhält automatisch Administrationsrechte.
|
||||
@@ -115,25 +117,26 @@ confirm_password=Passwort bestätigen
|
||||
admin_email=Administrator E-Mail
|
||||
install_gogs=Gogs installieren
|
||||
test_git_failed=Fehler beim Test des 'git' Kommandos: %v
|
||||
sqlite3_not_available=Ihre Gogs-Version unterstützt kein SQLite3, bitte lade dir die offizielle binäre Version von %s herunter, NICHT die gobuild-Version.
|
||||
sqlite3_not_available=Ihre Gogs-Version unterstützt SQLite3 nicht. Bitte laden Sie die offizielle binäre Version von %s herunter, NICHT die gobuild-Version.
|
||||
invalid_db_setting=Datenbank-Einstellungen sind nicht korrekt: %v
|
||||
invalid_repo_path=Repository Root-Verzeichnis ist ungültig: %v
|
||||
run_user_not_match=Der ausführende Benutzer ist nicht der aktuelle Benutzer: %s -> %s
|
||||
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 du dich für Gogs entschieden hast. Wir wünschen viel Vergnügen damit.
|
||||
install_success=Herzlich Willkommen! Wir sind froh, dass Sie sich für Gogs entschieden haben. Wir wünschen viel Vergnügen damit.
|
||||
invalid_log_root_path=Pfad zum Log-Verzeichnis ist ungültig: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Benutzername oder E-Mail
|
||||
password_holder=Passwort
|
||||
switch_dashboard_context=Dashboard Kontext wechseln
|
||||
switch_dashboard_context=Dashboard-Kontext wechseln
|
||||
my_repos=Meine Repositories
|
||||
collaborative_repos=Gemeinschaftliche Repositories
|
||||
my_orgs=Meine Organisationen
|
||||
my_mirrors=Meine Spiegel
|
||||
view_home=%s betrachten
|
||||
|
||||
issues.in_your_repos=In deinen Repositories
|
||||
issues.in_your_repos=In ihren Repositories
|
||||
|
||||
[explore]
|
||||
repos=Repositories
|
||||
@@ -141,29 +144,29 @@ repos=Repositories
|
||||
[auth]
|
||||
create_new_account=Neues Konto erstellen
|
||||
register_hepler_msg=Du hast bereits ein Konto? Jetzt anmelden!
|
||||
social_register_hepler_msg=Du hast bereits ein soziales Konto? Jetzt verknüpfen!
|
||||
disable_register_prompt=Es tut uns leid, die Registrierung wurde deaktiviert. Bitte wende dich an den Administrator.
|
||||
social_register_hepler_msg=Haben Sie bereits ein Konto? Jetzt verknüpfen!
|
||||
disable_register_prompt=Es tut uns leid, die Registrierung wurde deaktiviert. Bitte wenden Sie sich an den Administrator.
|
||||
disable_register_mail=Es tut uns leid, die Bestätigung der Registrierungs-E-Mail wurde deaktiviert.
|
||||
remember_me=Angemeldet bleiben
|
||||
forgot_password=Passwort vergessen
|
||||
forget_password=Passwort vergessen?
|
||||
sign_up_now=Du willst ein Konto? Jetzt registrieren!
|
||||
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. Kontrolliere dein Postfach innerhalb der nächsten %d Stunden, um die Registrierung abzuschließen.
|
||||
active_your_account=Aktiviere dein Konto
|
||||
resent_limit_prompt=Es tut uns leid, du sendest zu häufig Aktivierungs-E-Mails. Bitte warte 3 Minuten.
|
||||
has_unconfirmed_mail=Hallo %s, du hast eine unbestätigte E-Mail-Adresse (<b>%s</b>). Wenn du keine Bestätigungs-E-Mail erhalten hast oder eine neue benötigst, klicke bitte auf den folgenden Button.
|
||||
resend_mail=Hier klicken, um deine Aktivierungs-E-Mail erneut zu versenden
|
||||
active_your_account=Aktivieren Sie Ihr Konto
|
||||
resent_limit_prompt=Es tut uns leid, Sie erbitten zu häufig Aktivierungs-E-Mails. Bitte warten Sie 3 Minuten.
|
||||
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.
|
||||
reset_password_helper=Hier klicken, um das Passwort zurückzusetzen
|
||||
password_too_short=Das Passwort muss mindenstens 6 Zeichen lang sein
|
||||
password_too_short=Das Passwort muss mindenstens 6 Zeichen lang sein.
|
||||
|
||||
[mail]
|
||||
activate_account=Bitte aktiviere dein Konto
|
||||
activate_email=Verifiziere deine E-Mail-Adresse
|
||||
reset_password=Setze dein Passwort zurück
|
||||
activate_account=Bitte aktivieren Sie Ihr Konto
|
||||
activate_email=Bestätigen Sie Ihre E-Mail-Adresse
|
||||
reset_password=Passwort zurücksetzen
|
||||
register_success=Registrierung erfolgreich, Willkommen
|
||||
register_notify=Willkommen an Bord
|
||||
|
||||
@@ -177,17 +180,17 @@ UserName=Benutzername
|
||||
RepoName=Repository-Name
|
||||
Email=E-Mail-Adresse
|
||||
Password=Passwort
|
||||
Retype=Passwort bestätigen
|
||||
Retype=Passwort erneut eingeben
|
||||
SSHTitle=SSH-Schlüsselname
|
||||
HttpsUrl=HTTPS-URL
|
||||
HttpsUrl=HTTPS URL
|
||||
PayloadUrl=Payload-URL
|
||||
TeamName=Teamname
|
||||
AuthName=Authentifizierungsname
|
||||
AdminEmail=Admin E-mail
|
||||
AdminEmail=Administrator E-Mail
|
||||
|
||||
require_error=` darf nicht leer sein.`
|
||||
alpha_dash_error=` muss ausschließlich alphanumerische Zeichen und "-_" enthalten.`
|
||||
alpha_dash_dot_error=` muss ausschließlich alphanumerische Zeichen und ".-_" enthalten.`
|
||||
alpha_dash_error=` kann ausschließlich alphanumerische Zeichen und "-_" enthalten.`
|
||||
alpha_dash_dot_error=` kann ausschließlich alphanumerische Zeichen und ".-_" enthalten.`
|
||||
size_error=` muss die Größe %s haben.`
|
||||
min_size_error=` muss mindestens %s Zeichen enthalten.`
|
||||
max_size_error=` darf höchstens %s Zeichen enthalten.`
|
||||
@@ -203,35 +206,36 @@ repo_name_been_taken=Repository-Name ist bereits vergeben.
|
||||
org_name_been_taken=Organisationsname ist bereits vergeben.
|
||||
team_name_been_taken=Teamname ist bereits vergeben.
|
||||
email_been_used=E-Mail-Adresse wird bereits verwendet.
|
||||
illegal_team_name=Teamname enthält ungültige Zeichen.
|
||||
username_password_incorrect=Benutzername oder Passwort ist nicht korrekt.
|
||||
enterred_invalid_repo_name=Bitte stelle sicher, dass der eingegebene Repository-Name richtig ist.
|
||||
enterred_invalid_owner_name=Bitte stelle sicher, dass der eingegebene Besitzername richtig ist.
|
||||
enterred_invalid_password=Bitte stelle sicher, dass das eingegebene Passwort richtig ist.
|
||||
enterred_invalid_repo_name=Bitte achten Sie darauf, dass der von Ihnen eingegebene Repository-Name korrekt ist.
|
||||
enterred_invalid_owner_name=Bitte achten Sie darauf, dass der eingegebene Besitzersname korrekt ist.
|
||||
enterred_invalid_password=Bitte achten Sie darauf, dass das eingegebene Passwort richtig ist.
|
||||
user_not_exist=Angegebener Benutzer existiert nicht.
|
||||
last_org_owner=Der zu entfernende Benutzer ist der letzte Besitzer einer Organisation. Diese müssen zuerst gelöscht oder übertragen werden.
|
||||
last_org_owner=Entfernen des letzten Benutzers von einem Eigentümer-Team ist nicht zulässig, denn es muss immer mindestens ein Besitzer in jeder Organisation.
|
||||
|
||||
invalid_ssh_key=Leider sind wir nicht in der Lage, deinen SSH-Schlüssel zu überprüfen: %s
|
||||
unable_verify_ssh_key=Gogs kann deinen SSH-Schlüssel nicht verifizieren, nimmt aber an, dass er gültig ist. Bitte stelle dies selbst sicher.
|
||||
unable_verify_ssh_key=Gogs kann Ihren SSH-Schlüssel nicht überprüfen, nimmt aber an, dass er gültig ist. Bitte stellen Sie dies selbst sicher.
|
||||
auth_failed=Authentifizierung fehlgeschlagen: %v
|
||||
|
||||
still_own_repo=Dein Konto besitzt noch Repositories. Diese müssen zuerst gelöscht oder übertragen werden.
|
||||
still_has_org=Du bist noch Mitglied einer Organisation, bitte lösche zunächst diese Mitgliedschaft.
|
||||
still_own_repo=Ihr Konto besitzt noch Repositories. Diese müssen zuerst gelöscht oder übertragen werden.
|
||||
still_has_org=Sie sind noch Mitglied einer Organisation, bitte löschen Sie zunächst diese Mitgliedschaft.
|
||||
org_still_own_repo=Diese Organisation besitzt noch Repositories. Diese müssen zuerst gelöscht oder übertragen werden.
|
||||
|
||||
still_own_user=Diese Authentifizierung wird noch von einigen Benutzern genutzt. Entferne diese zuvor und lösche erneut.
|
||||
still_own_user=Diese Authentifizierung wird noch von mindestens einem Benutzern verwendet. Entfernen Sie diesen von dieser Authentifizierung und versuchen es erneut.
|
||||
|
||||
target_branch_not_exist=Ziel-Branch existiert nicht
|
||||
|
||||
[user]
|
||||
change_avatar=Ändere dein Profilbild auf gravatar.com
|
||||
change_custom_avatar=Ändere deinen Avatar in den Einstellungen
|
||||
join_on=Registriert
|
||||
change_custom_avatar=Ändern Sie Ihr Profilbild in den Einstellungen
|
||||
join_on=Beigetreten am
|
||||
repositories=Repositories
|
||||
activity=Öffentliche Aktivität
|
||||
followers=Followers
|
||||
starred=Markiert
|
||||
starred=Mit Sternchen markierte Repositories
|
||||
following=Folgt
|
||||
follow=Folgen
|
||||
unfollow=Nicht mehr folgen
|
||||
|
||||
form.name_reserved=Der Benutzername '%s' ist reserviert.
|
||||
form.name_pattern_not_allowed=Benutzernamens-Muster "%s" ist nicht zulässig.
|
||||
@@ -247,7 +251,7 @@ delete=Konto löschen
|
||||
uid=Uid
|
||||
|
||||
public_profile=Öffentliches Profil
|
||||
profile_desc=Deine E-Mail-Adresse ist öffentlich einsehbar und wird für accountspezifische Benachrichtigungen verwendet, sowie für alle web-basierten Funktionen, die über die Seite gemacht werden.
|
||||
profile_desc=Ihre E-Mail-Adresse ist öffentlich einsehbar und dient dazu, Ihnen Benachrichtigungen bezüglich Ihres Kontos und Aktivitäten auf der Webseite zu schicken.
|
||||
password_username_disabled=Nicht-lokalen Benutzern ist es nicht erlaubt, ihren Usernamen zu ändern.
|
||||
full_name=Vollständiger Name
|
||||
website=Webseite
|
||||
@@ -255,16 +259,16 @@ location=Standort
|
||||
update_profile=Profil aktualisieren
|
||||
update_profile_success=Ihr Profil wurde erfolgreich aktualisiert.
|
||||
change_username=Benutzername geändert
|
||||
change_username_prompt=Diese Änderung wird sich auf die Linkbezüge zu deinem Account auswirken.
|
||||
change_username_prompt=Diese Änderung wirkt sich darauf aus, wie Links sich auf Ihr Konto beziehen.
|
||||
continue=Weiter
|
||||
cancel=Abbrechen
|
||||
|
||||
enable_custom_avatar=Aktiviere benutzerdefinierten Avatar
|
||||
enable_custom_avatar_helper=Aktiviere dies, um deinen Avatar nicht von Gravatar zu laden
|
||||
choose_new_avatar=Neuen Avatar auswählen
|
||||
update_avatar=Avatar-Einstellung aktualisieren
|
||||
enable_custom_avatar_helper=Abruf des Profilbild von Gravatar deaktivieren
|
||||
choose_new_avatar=Neues Profilbild auswählen
|
||||
update_avatar=Profilbildeinstellungen aktualisieren
|
||||
uploaded_avatar_not_a_image=Die hochgeladene Datei ist kein Bild.
|
||||
no_custom_avatar_available=Kein benutzerdefinierter Avatar verfügbar, Aktivierung ist nicht möglich.
|
||||
no_custom_avatar_available=Kein benutzerdefiniertes Profilbild verfügbar, Aktivierung ist nicht möglich.
|
||||
update_avatar_success=Deine Avatar-Einstellung wurde aktualisiert.
|
||||
|
||||
change_password=Passwort ändern
|
||||
@@ -272,36 +276,36 @@ old_password=Aktuelles Passwort
|
||||
new_password=Neues Passwort
|
||||
retype_new_password=Neues Passwort erneut eingeben
|
||||
password_incorrect=Aktuelles Passwort ist nicht korrekt.
|
||||
change_password_success=Passwort geändert. Du kannst dich jetzt mit deinem neuen Passwort anmelden.
|
||||
change_password_success=Ihr Passwort wurde geändert. Sie können sich jetzt mit ihrem neuen Passwort anmelden.
|
||||
password_change_disabled=Nicht-lokalen Benutzern ist es nicht erlaubt, ihr Passwort zu ändern.
|
||||
|
||||
emails=E-Mail-Adressen
|
||||
manage_emails=E-Mail-Adressen verwalten
|
||||
email_desc=Deine primäre E-Mail-Adresse wird für Benachrichtigungen und andere Funktionen verwendet.
|
||||
email_desc=Ihre primäre E-Mail-Adresse wird für Benachrichtigungen und andere Funktionen verwendet werden.
|
||||
primary=Primär
|
||||
primary_email=Als primäre Adresse verwenden
|
||||
delete_email=Löschen
|
||||
email_deletion=E-Mail löschen
|
||||
email_deletion_desc=Das Löschen dieser E-Mail Adresse wird alle Informationen entfernen, die mit dieser E-Mail Adresse verknüpft sind. Willst du fortfahren?
|
||||
email_deletion_desc=Das Löschen dieser E-Mail Adresse wird alle Informationen entfernen, die mit dieser E-Mail Adresse verknüpft sind. Wollen Sie fortfahren?
|
||||
email_deletion_success=E-Mail-Adresse wurde erfolgreich gelöscht!
|
||||
add_new_email=Neue E-Mail-Adresse hinzufügen
|
||||
add_email=E-Mail-Adresse hinzufügen
|
||||
add_email_confirmation_sent=Eine neue Bestätigungsmail wurde an '%s' gesendet, bitte überprüfen Sie Ihren Posteingang innerhalb von %d Stunden um die Bestätigung abzuschließen.
|
||||
add_email_success=Deine neue E-Mail-Adresse wurde erfolgreich hinzugefügt.
|
||||
add_email_success=Ihre neue E-Mail-Adresse wurde erfolgreich hinzugefügt.
|
||||
|
||||
manage_ssh_keys=SSH-Schlüssel verwalten
|
||||
add_key=SSH-Schlüssel hinzufügen
|
||||
ssh_desc=Dies ist eine Liste aller SSH-Schlüssel, die mit deinem Konto verknüpft sind. Bitte entferne alle Schlüssel, die dir nicht bekannt sind.
|
||||
ssh_helper=<strong>Du brauchst Hilfe?</strong> Hier ist eine Anleitung zum <a href="%s">Erzeugen von SSH-Schlüsseln</a> oder <a href="%s">Problemlösen einfacher SSH-Probleme</a>.
|
||||
ssh_desc=Dies ist eine Liste aller SSH-Schlüssel, die Ihrem Konto zugeordnet sind. Bitte entfernen Sie alle Schlüssel, die Ihnen nicht bekannt sind.
|
||||
ssh_helper=<strong>Sie brauchen Hilfe?</strong> Hier ist eine Anleitung zum <a href="%s">Erzeugen von SSH-Schlüsseln</a> oder <a href="%s">Problemlösen einfacher SSH-Probleme</a>.
|
||||
add_new_key=SSH-Schlüssel hinzufügen
|
||||
ssh_key_been_used=Inhalt des öffentlichen Schlüssels wurde verwendet.
|
||||
ssh_key_name_used=Ein öffentlicher Schlüssel mit dem selben Namen existiert bereits.
|
||||
key_name=Schlüsselname
|
||||
key_content=Inhalt
|
||||
add_key_success=Neuer SSH-Schlüssel '%s' wurde erfolgreich hinzugefügt!
|
||||
delete_key=SSH-Schlüssel löschen
|
||||
delete_key=Löschen
|
||||
ssh_key_deletion=SSH-Schlüssel entfernen
|
||||
ssh_key_deletion_desc=Das Löschen dieses SSH-Schlüssels wird alle zugehörigen Zugriffsberechtigungen auf deinen Account entfernen. Möchtest du fortfahren?
|
||||
ssh_key_deletion_desc=Das Löschen dieses SSH-Schlüssels wird alle zugehörigen Zugriffsberechtigungen auf ihr Konto entfernen. Möchten Sie fortfahren?
|
||||
ssh_key_deletion_success=SSH-Schlüssel wurde erfolgreich gelöscht!
|
||||
add_on=Hinzugefügt am
|
||||
last_used=Zuletzt verwendet am
|
||||
@@ -310,45 +314,45 @@ key_state_desc=Dieser Schlüssel wurde in den letzten 7 Tagen verwendet
|
||||
token_state_desc=Dieses Token wurde in den letzten 7 Tagen benutzt
|
||||
|
||||
manage_social=Verknüpfte soziale Konten verwalten
|
||||
social_desc=Dies ist eine Liste verknüpfter sozialer Konten. Bitte entferne alle Verknüpfungen, die dir nicht bekannt sind.
|
||||
social_desc=Dies ist eine Liste verknüpfter sozialer Konten. Bitte entfernen Sie alle Verknüpfungen, die Ihnen nicht bekannt sind.
|
||||
unbind=Verknüpfung entfernen
|
||||
unbind_success=Die Verknüpfung zum sozialen Konto wurde entfernt.
|
||||
|
||||
manage_access_token=Verwaltung persönlicher Zugangs-Tokens
|
||||
generate_new_token=Neuen Token erzeugen
|
||||
tokens_desc=Von dir generierte Token können benutzt werden, um auf die Gogs APIs zuzugreifen.
|
||||
tokens_desc=Die von Ihnen erzeugten Tokens können zum Zugriff auf die Gogs-API verwendet werden.
|
||||
new_token_desc=Momentan erlaubt jeder Token vollen Zugriff auf dein Konto.
|
||||
token_name=Token-Name
|
||||
generate_token=Token generieren
|
||||
generate_token_succees=Neuer Zugangs-Token wurde erstellt! Stelle sicher, dass du den Token kopiert hast, da du ihn später nicht mehr ansehen kannst!
|
||||
generate_token_succees=Ihr Zugangs-Token wurde erfolgreich generiert! Stellen Sie sicher, dass Sie den Token kopiert haben, da Sie ihn später nicht mehr ansehen können!
|
||||
delete_token=Löschen
|
||||
access_token_deletion=Entfernung von persönlichen Token
|
||||
access_token_deletion_desc=Das Löschen dieses persönlichen Tokens wird alle zugehörigen Zugriffe der Anwendung entfernen. Möchtest du fortfahren?
|
||||
delete_token_success=Persönlicher Zugriffs-Token wurde erfolgreich entfernt! Vergiss nicht deine Anwendung zu aktualisieren.
|
||||
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.
|
||||
|
||||
delete_account=Konto löschen
|
||||
delete_prompt=Diese Aktion wird dein Konto dauerhaft löschen und kann <strong>NICHT</strong> rückgängig gemacht werden!
|
||||
confirm_delete_account=Löschen
|
||||
delete_account_title=Account löschen
|
||||
delete_account_desc=Du bist dabei dieses Konto dauerhaft zu löschen, möchtest du wirklich fortfahren?
|
||||
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
|
||||
delete_account_title=Konto löschen
|
||||
delete_account_desc=Sie sind dabei dieses Konto dauerhaft zu löschen, möchten Sie wirklich fortfahren?
|
||||
|
||||
[repo]
|
||||
owner=Besitzer
|
||||
repo_name=Repository-Name
|
||||
repo_name_helper=Gute Repository-Namen sind kurz, einprägsam und <strong>einzigartig</strong>.
|
||||
repo_name_helper=Ein guter Repository-Namen besteht gewöhnlich aus kurzen, einprägsamen und einzigartigen Schlüsselworten.
|
||||
visibility=Sichtbarkeit
|
||||
visiblity_helper=Diese Repository ist <span class="ui red text">Privat</span>
|
||||
visiblity_helper=Dieses Repository ist <span class="ui red text">privat</span>
|
||||
visiblity_helper_forced=Der Administrator hat festgelegt, dass alle neuen Repositories <span class="ui red text">privat</span> sein müssen
|
||||
visiblity_fork_helper=(Eine Änderung dieses Wertes wirkt sich auf alle Forks aus)
|
||||
clone_helper=Du brauchst Hilfe beim Klonen? Hier gibt es <a target="_blank" href="%s">Hilfe</a>!
|
||||
fork_repo=Repository abspalten
|
||||
fork_from=Forken von
|
||||
fork_repo=Repository forken
|
||||
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=.gitignore Dateien auswählen
|
||||
license=Lizenz
|
||||
license_helper=Wähle eine Lizenz aus
|
||||
license_helper=Wählen Sie eine Lizenz aus
|
||||
readme=Readme
|
||||
readme_helper=Readme Vorlage auswählen
|
||||
auto_init=Repository mit ausgewählten Dateien und Vorlagen initialisieren
|
||||
@@ -361,11 +365,11 @@ watchers=Beobachter
|
||||
stargazers=Sterngucker
|
||||
forks=Forks
|
||||
|
||||
form.reach_limit_of_creation=Der Besitzer hat die maximale Anzahl vo %d erstellbaren Repositorys erreicht.
|
||||
form.name_reserved=Repository-Name '%s' ist bereits vergeben.
|
||||
form.reach_limit_of_creation=Der Besitzer hat die maximale Anzahl von %d erstellbaren Repositorys erreicht.
|
||||
form.name_reserved=Repository-Name '%s' ist reserviert.
|
||||
form.name_pattern_not_allowed=Repository-Namesmuster '%s' ist nicht zulässig.
|
||||
|
||||
need_auth=Autorisierung benötigt
|
||||
need_auth=Authorisierung benötigt
|
||||
migrate_type=Migrationstyp
|
||||
migrate_type_helper=Diese Repository wird ein <span class="text blue">Spiegel</span> sein
|
||||
migrate_repo=Repository migrieren
|
||||
@@ -377,36 +381,36 @@ migrate.failed=Fehler bei Migration: %v
|
||||
|
||||
mirror_from=spiegeln von
|
||||
forked_from=Geforkt von
|
||||
fork_from_self=Sie können keine Repository forken, welche ihnen gehört!
|
||||
fork_from_self=SIe können kein Repository forken, das ihnen gehört!
|
||||
copy_link=Kopieren
|
||||
copy_link_success=Kopiert!
|
||||
copy_link_error=Drücke ⌘-C oder Strg-C zum Kopieren
|
||||
copied=Kopiert OK
|
||||
unwatch=Nicht mehr beobachten
|
||||
watch=Beobachten
|
||||
unstar=Markierung aufheben
|
||||
star=Markieren
|
||||
unstar=Sternchen entfernen
|
||||
star=Markierung
|
||||
fork=Fork
|
||||
|
||||
no_desc=Keine Beschreibung
|
||||
quick_guide=Kurzanleitung
|
||||
clone_this_repo=Diese Repository klonen
|
||||
create_new_repo_command=Erstelle eine neue Repository mittels Kommandozeile
|
||||
clone_this_repo=Dieses Repository klonen
|
||||
create_new_repo_command=Erstellen Sie ein neues Repository mittels der Kommandozeile
|
||||
push_exist_repo=Übertrage eine existierende Repository von der Kommandozeile
|
||||
repo_is_empty=Das Repository ist leer, bitte komm später wieder!
|
||||
repo_is_empty=Das Repository ist leer, bitte kommen Sie später wieder!
|
||||
|
||||
code=Code
|
||||
branch=Branch
|
||||
tree=Struktur
|
||||
filter_branch_and_tag=Nach Zweig oder Tag filtern
|
||||
filter_branch_and_tag=Nach Branch oder Tag filtern
|
||||
branches=Branches
|
||||
tags=Tags
|
||||
issues=Issues
|
||||
pulls=Pull-Anforderung
|
||||
pulls=Pull-Requests
|
||||
labels=Label
|
||||
milestones=Meilensteine
|
||||
commits=Commits
|
||||
releases=Veröffentlichungen
|
||||
releases=Releases
|
||||
file_raw=Roh
|
||||
file_history=Verlauf
|
||||
file_view_raw=Ansicht Roh
|
||||
@@ -415,7 +419,7 @@ file_permalink=Permalink
|
||||
commits.commits=Commits
|
||||
commits.search=Durchsuche Commits
|
||||
commits.find=Finden
|
||||
commits.author=Author
|
||||
commits.author=Autor
|
||||
commits.message=Nachricht
|
||||
commits.date=Datum
|
||||
commits.older=Älter
|
||||
@@ -442,25 +446,25 @@ issues.close_tab=%d geschlossen
|
||||
issues.filter_label=Label
|
||||
issues.filter_label_no_select=Kein Label gewählt
|
||||
issues.filter_milestone=Meilenstein
|
||||
issues.filter_milestone_no_select=Kein ausgewählter Meilenstein
|
||||
issues.filter_milestone_no_select=Kein Meilenstein ausgewählt
|
||||
issues.filter_assignee=Zuständiger
|
||||
issues.filter_assginee_no_select=Kein ausgewählter Zuständiger
|
||||
issues.filter_assginee_no_select=Kein Zuständiger ausgewählt
|
||||
issues.filter_type=Typ
|
||||
issues.filter_type.all_issues=Alle Probleme
|
||||
issues.filter_type.assigned_to_you=Dir zugewiesen
|
||||
issues.filter_type.created_by_you=Erstellt von dir
|
||||
issues.filter_type.mentioning_you=Erwähnen dich
|
||||
issues.filter_type.assigned_to_you=Ihnen zugewiesenen
|
||||
issues.filter_type.created_by_you=von Ihnen erstellt
|
||||
issues.filter_type.mentioning_you=Erwähnen Sie
|
||||
issues.filter_sort=Sortieren
|
||||
issues.filter_sort.latest=Neueste
|
||||
issues.filter_sort.oldest=Älteste
|
||||
issues.filter_sort.recentupdate=Zuletzt aktualisiert
|
||||
issues.filter_sort.recentupdate=Kürzlich aktualisiert
|
||||
issues.filter_sort.leastupdate=Am längsten nicht aktualisiert
|
||||
issues.filter_sort.mostcomment=Am meisten kommentiert
|
||||
issues.filter_sort.leastcomment=Am wenigsten kommentiert
|
||||
issues.opened_by=%[1]s geöffnet von <a href="%[2]s">%[3]s</a>
|
||||
issues.opened_by_fake=eröffnet %[1]s von %[2]s
|
||||
issues.previous=Vorherige Seite
|
||||
issues.next=Nächste Seite
|
||||
issues.opened_by_fake=geöffnet %[1]s von %[2]s
|
||||
issues.previous=Vorherige
|
||||
issues.next=Nächste
|
||||
issues.open_title=Offen
|
||||
issues.closed_title=Geschlossen
|
||||
issues.num_comments=%d Kommentare
|
||||
@@ -468,17 +472,17 @@ issues.commented_at=`kommentiert in <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.no_content=Hier gibt es bis jetzt noch keinen Inhalt.
|
||||
issues.close_issue=Schließen
|
||||
issues.close_comment_issue=Kommentieren und schließen
|
||||
issues.reopen_issue=Wiedereröffnen
|
||||
issues.reopen_comment_issue=Kommentieren und wiedereröffnen
|
||||
issues.reopen_issue=Wiederöffnen
|
||||
issues.reopen_comment_issue=Kommentieren und wiederöffnen
|
||||
issues.create_comment=Kommentieren
|
||||
issues.closed_at=`geschlossen in <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.reopened_at=`wiedereröffnet in <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.reopened_at=`wiedergeöffnet in <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.commit_ref_at=`referenziert dieses Issue aus einem Commit <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.poster=Ersteller
|
||||
issues.admin=Admin
|
||||
issues.owner=Besitzer
|
||||
issues.sign_up_for_free=Kostenlos anmelden
|
||||
issues.sign_in_require_desc=um dieser Konverstion beizutreten. Hast du bereits einen Account? <a href="%s">Anmelden zum kommentieren</a>
|
||||
issues.sign_in_require_desc=um dieser Konversation beizutreten. Haben Sie bereits ein Konto? <a href="%s">Anmelden um zu kommentieren</a>
|
||||
issues.edit=Bearbeiten
|
||||
issues.cancel=Abbrechen
|
||||
issues.save=Speichern
|
||||
@@ -492,6 +496,7 @@ issues.label_modify=Label Änderung
|
||||
issues.label_deletion=Label Löschung
|
||||
issues.label_deletion_desc=Das Löschen eines Labels entfernt es von allen verknüpften Issues. Möchtest du fortfahren?
|
||||
issues.label_deletion_success=Label wurde erfolgreich gelöscht!
|
||||
issues.num_participants=%d Beteiligte
|
||||
|
||||
pulls.new=Neuer Pull-Request
|
||||
pulls.compare_changes=Änderungen vergleichen
|
||||
@@ -500,9 +505,9 @@ pulls.compare_base=Base
|
||||
pulls.compare_compare=vergleichen
|
||||
pulls.filter_branch=Filter Branch
|
||||
pulls.no_results=Keine Ergebnisse verfügbar.
|
||||
pulls.nothing_to_compare=Es ist nichts zu vergleichen, da Base- und Head-Branch gleich sind.
|
||||
pulls.has_pull_request=`Es existiert bereits eine Pull-Anforderung zwischen diesen beiden Zielen: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
|
||||
pulls.create=Pull Request erstellen
|
||||
pulls.nothing_to_compare=Es gibt nichts zu vergleichen, da Base- und Head-Branch gleich sind.
|
||||
pulls.has_pull_request=`Es existiert bereits ein Pull-Request zwischen diesen beiden Zielen: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
|
||||
pulls.create=Pull-Request erstellen
|
||||
pulls.title_desc=möchte %[1]d Commits von <code>%[2]s</code> nach <code>%[3]s</code> zusammenführen
|
||||
pulls.merged_title_desc=%[1]d Commits von <code>%[2]s</code> nach <code>%[3]s</code> %[4]s zusammengeführt
|
||||
pulls.tab_conversation=Konversation
|
||||
@@ -576,43 +581,49 @@ settings.external_wiki_url_desc=Besucher werden auf die URL umgeleitet, wenn sie
|
||||
settings.issues_desc=Benutze eingebauten leichtgewichtigen Issue-Tracker
|
||||
settings.use_external_issue_tracker=Benutze externen Issue-Tracker
|
||||
settings.tracker_url_format=URL-Format für externen Issu-Tracker
|
||||
settings.tracker_url_format_desc=Du kannst einen Platzhalter <code>{user} {repo} {index}</code> für den Benutzernamen, den Repositorynamen und den Issue-Index benutzen.
|
||||
settings.tracker_url_format_desc=Sie können einen Platzhalter <code>{user} {repo} {index}</code> für den Benutzernamen, den Namen des Repositorys und den Issue-Index verwenden.
|
||||
settings.pulls_desc=Aktiviere Pull-Anforderungen zum Akzeptieren von öffentlichen Beiträgen
|
||||
settings.danger_zone=Gefahrenzone
|
||||
settings.new_owner_has_same_repo=Der neue Eigentümer hat bereits ein Repository mit dem gleichen Namen. Bitte wählen Sie einen anderen Namen.
|
||||
settings.convert=In ein normales Repository umwandeln
|
||||
settings.convert_desc=Dieser Spiegel kann in ein normales Repository umgewandelt werden. Dies kann nicht rückgängig gemacht werden.
|
||||
settings.convert_notices_1=- Dieser Vorgang wandelt das Spiegel-Repository in ein normales Repository um. Dies kann nicht rückgängig gemacht werden.
|
||||
settings.convert_confirm=Bestätige die Umwandlung
|
||||
settings.convert_succeed=Das Repository wurde erfolgreich in ein normales Repository umgewandelt.
|
||||
settings.transfer=Besitz übertragen
|
||||
settings.transfer_desc=Übertrage diese Repository auf einen anderen Benutzer oder eine Organisation in der du Admin-Rechte hast.
|
||||
settings.new_owner_has_same_repo=Der neue Eigentümer hat bereits ein Repository mit dem gleichen Namen.
|
||||
settings.delete=Repository löschen
|
||||
settings.delete_desc=Wenn diese Repository gelöscht ist, gibt es keinen Weg zurück. Bitte sei behutsam.
|
||||
settings.transfer_notices_1=- Du wirst den Zugang verlieren, wenn der neue Besitzer ein individueller Benutzer ist.
|
||||
settings.transfer_notices_2=- Du wirst den Zugang behalten, wenn der neue Besitzer eine Organisation ist und du einer der Besitzer bist.
|
||||
settings.transfer_form_title=Bitte gib die folgenden Informationen ein, um die Operation zu bestätigen:
|
||||
settings.delete=Repository löschen
|
||||
settings.delete_desc=Wenn diese Repository gelöscht ist, gibt es keinen Weg zurück. Bitte sei behutsam.
|
||||
settings.delete_notices_1=- Diese Operation kann <strong>NICHT</strong> rückgängig gemacht werden.
|
||||
settings.delete_notices_2=- Die Operation wird alles, was mit dieser Git-Repository verbunden ist, dauerhaft löschen, inklusive der Daten, Issues, Kommentare und Zugriffsrechte von Benutzern.
|
||||
settings.delete_notices_2=- Die Operation wird alles, was mit diesem Git-Repository verbunden ist, dauerhaft löschen, inklusive der Daten, Issues, Kommentare und Zugriffsrechte von Mitarbeitern.
|
||||
settings.delete_notices_fork_1=- Wenn dies eine öffentliche Repository ist, werden nach der Löschung alle Forks unabhängig.
|
||||
settings.delete_notices_fork_2=- Wenn dies eine private Repository ist, dann werden gleichzeitig alle Forks entfernt.
|
||||
settings.delete_notices_fork_3=Wenn alle Forks erhalten bleiben sollen, dann muss zuerst die Sichtbarkeit der Repository auf öffentlich gesetzt werden.
|
||||
settings.deletion_success=Repository wurde erfolgreich gelöscht!
|
||||
settings.update_settings_success=Repository-Optionen aktualisiert.
|
||||
settings.transfer_owner=Neuer Besitzer
|
||||
settings.make_transfer=übertragen
|
||||
settings.make_transfer=Transfer starten
|
||||
settings.transfer_succeed=Die Repository wurde erfolgreich übertragen.
|
||||
settings.confirm_delete=Löschen
|
||||
settings.add_collaborator=Mitarbeiter hinzufügen
|
||||
settings.add_collaborator_success=Mitarbeiter hinzugefügt
|
||||
settings.remove_collaborator_success=Mitarbeiter entfernt
|
||||
settings.add_collaborator_success=Neuer Mitarbeiter hinzugefügt.
|
||||
settings.remove_collaborator_success=Mitarbeiter wurde entfernt.
|
||||
settings.search_user_placeholder=Benutzer suchen...
|
||||
settings.org_not_allowed_to_be_collaborator=Eine Organisation kann nicht als Mitarbeiter hinzugefügt werden.
|
||||
settings.user_is_org_member=Benutzer ist ein Organisationsmitglied und kann nicht als Mitarbeiter hinzugefügt werden.
|
||||
settings.add_webhook=Webhook hinzufügen
|
||||
settings.hooks_desc=Webhooks erlauben es dir, externe Dienste zu informieren, wenn etwas bestimmtes in deiner Repository passiert. Gogs sendet dann einen POST-Request an alle angegebenen URLs. Erfahre mehr in unserer <a target="_blank" href="%s">Webhooks Guide</a>.
|
||||
settings.webhook_deletion=Webhook entfernen
|
||||
settings.webhook_deletion_desc=Das Löschen dieses Webhooks wird alle zugehörigen Informationen und den Übertragungsverlauf entfernen. Wirklich fortfahren?
|
||||
settings.webhook_deletion_success=Webhook wurde erfolgreich entfernt!
|
||||
settings.webhook.test_delivery=Auslieferungstest
|
||||
settings.webhook.test_delivery=Auslieferung testen
|
||||
settings.webhook.test_delivery_desc=Sende eine imitierte Push-Ereignis-Auslieferung um die Webhook-Einstellungen zu testen
|
||||
settings.webhook.test_delivery_success=Test-Webhook wurde zur Auslieferungswarteschlange hinzugefügt. Es kann einige Sekunden dauern, bevor es in der Auslieferungshistorie erscheint.
|
||||
settings.webhook.request=Anfrage
|
||||
settings.webhook.response=Rückmeldung
|
||||
settings.webhook.response=Antwort
|
||||
settings.webhook.headers=Kopfzeilen
|
||||
settings.webhook.payload=Nutzdaten
|
||||
settings.webhook.body=Inhalt
|
||||
@@ -628,7 +639,7 @@ settings.secret=Secret
|
||||
settings.slack_username=Benutzername
|
||||
settings.slack_icon_url=Icon URL
|
||||
settings.slack_color=Farbe
|
||||
settings.event_desc=Welche Ereignisse sollen diesen Webhook auslösen?
|
||||
settings.event_desc=Wann soll dieser Webhook ausgelöst werden?
|
||||
settings.event_push_only=Nur das <code>push</code>-Ereignis.
|
||||
settings.event_send_everything=Ich brauche <strong>alles</strong>.
|
||||
settings.event_choose=Lass mich auswählen, was ich brauche.
|
||||
@@ -666,6 +677,8 @@ diff.parent=Ursprung
|
||||
diff.commit=Commit
|
||||
diff.data_not_available=Keine Diff-Daten verfügbar.
|
||||
diff.show_diff_stats=Diff-Statistik anzeigen
|
||||
diff.show_split_view=Geteilte Ansicht
|
||||
diff.show_unified_view=Gesamtansicht
|
||||
diff.stats_desc=<strong> %d geänderte Dateien</strong> mit <strong>%d neuen Zeilen</strong> und <strong>%d gelöschten Zeilen</strong>
|
||||
diff.bin=BIN
|
||||
diff.view_file=Datei anzeigen
|
||||
@@ -694,10 +707,10 @@ release.cancel=Abbrechen
|
||||
release.publish=Release veröffentlichen
|
||||
release.save_draft=Entwurf speichern
|
||||
release.edit_release=Release bearbeiten
|
||||
release.delete_release=Diese Version löschen
|
||||
release.deletion=Version löschen
|
||||
release.deletion_desc=Beim Löschen dieser Version wird das entsprechende Git-Tag gelöscht. Möchten Sie fortfahren?
|
||||
release.deletion_success=Version wurde erfolgreich gelöscht!
|
||||
release.delete_release=Dieses Release löschen
|
||||
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.downloads=Downloads
|
||||
|
||||
@@ -769,7 +782,7 @@ teams.update_settings=Einstellungen aktualisieren
|
||||
teams.delete_team=Dieses Team löschen
|
||||
teams.add_team_member=Teammitglied hinzufügen
|
||||
teams.delete_team_title=Team löschen
|
||||
teams.delete_team_desc=Dieses Team wird gelöscht, möchtest du fortfahren? Mitglieder dieses Teams verlieren möglicherweise ihren Zugang zu einigen Repositories.
|
||||
teams.delete_team_desc=Mitglieder dieses Teams verlieren möglicherweise ihren Zugang zu einigen Repositories, wenn dieses Team gelöscht wird. Möchten Sie fortfahren?
|
||||
teams.delete_team_success=Team gelöscht
|
||||
teams.read_permission_desc=Dieses Team erlaubt <strong>Lesezugriff</strong>: Mitglieder können Team-Repositories einsehen und klonen.
|
||||
teams.write_permission_desc=Dieses Team erlaubt <strong>Schreibzugriff</strong>: Mitglieder können Team-Repositories einsehen und Push Operationen ausführen.
|
||||
@@ -778,7 +791,7 @@ teams.repositories=Team-Repositorys
|
||||
teams.search_repo_placeholder=Repository durchsuchen...
|
||||
teams.add_team_repository=Team-Repository hinzufügen
|
||||
teams.remove_repo=Entfernen
|
||||
teams.add_nonexistent_repo=Die Repository, welche du hinzufügen möchtest, existiert nicht. Bitte erstelle diese zuerst.
|
||||
teams.add_nonexistent_repo=Das Repository, das Sie hinzufügen möchten, existiert nicht. Bitte erstellen Sie es zuerst.
|
||||
|
||||
[admin]
|
||||
dashboard=Dashboard
|
||||
@@ -796,7 +809,7 @@ total=Total: %d
|
||||
dashboard.statistic=Statistik
|
||||
dashboard.operations=Operationen
|
||||
dashboard.system_status=System-Monitor-Status
|
||||
dashboard.statistic_info=GoGS Datenbank hat <b>%d</b> Benutzer, <b>%d</b> Organisationen, <b>%d</b> öffentliche Schlüssel, <b>%d</b> Repositorys, <b>%d</b> Beobachtungen, <b>%d</b> Markierungen, <b>%d</b> Aktionen, <b>%d</b> Zugriffe, <b>%d</b> Issues, <b>%d</b> Kommentare, <b>%d</b> soziale Konten, <b>%d</b> Folgende, <b>%d</b> Spiegel, <b>%d</b> Releases, <b>%d</b> Login-Quellen, <b>%d</b> Webhooks, <b>%d</b> Milestones, <b>%d</b> Labels, <b>%d</b> Hook-Tasks, <b>%d</b> Teams, <b>%d</b> Aktualisierungs-Tasks, <b>%d</b> Anhänge.
|
||||
dashboard.statistic_info=Gogs Datenbank hat <b>%d</b> Benutzer, <b>%d</b> Organisationen, <b>%d</b> öffentliche Schlüssel, <b>%d</b> Repositorys, <b>%d</b> Beobachtungen, <b>%d</b> Markierungen, <b>%d</b> Aktionen, <b>%d</b> Zugriffe, <b>%d</b> Issues, <b>%d</b> Kommentare, <b>%d</b> soziale Konten, <b>%d</b> Folgende, <b>%d</b> Spiegel, <b>%d</b> Releases, <b>%d</b> Login-Quellen, <b>%d</b> Webhooks, <b>%d</b> Milestones, <b>%d</b> Labels, <b>%d</b> Hook-Tasks, <b>%d</b> Teams, <b>%d</b> Aktualisierungs-Tasks, <b>%d</b> Anhänge.
|
||||
dashboard.operation_name=Name der Operation
|
||||
dashboard.operation_switch=Switch
|
||||
dashboard.operation_run=Ausführen
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys=Überschreibe '.ssh/authorized_keys' Datei (Warnung
|
||||
dashboard.resync_all_sshkeys_success=Alle öffentlichen Keys wurden erfolgreich neu geschrieben.
|
||||
dashboard.resync_all_update_hooks=Überschreibe alle Hooks der Repositories (benötigt, wenn sich der Pfad in der Konfiguration ändert)
|
||||
dashboard.resync_all_update_hooks_success=Die Hooks aller Repositories sind erfolgreich neu geschrieben worden.
|
||||
dashboard.reinit_missing_repos=Initialisieren sie alle Repository-Datensätze die Git-Dateien verloren haben neu
|
||||
dashboard.reinit_missing_repos_success=Alle Repository-Datensätze, die Git-Dateien verloren haben wurden erfolgreich neu initialisiert.
|
||||
|
||||
dashboard.server_uptime=Server-Uptime
|
||||
dashboard.current_goroutine=Aktuelle Goroutines
|
||||
@@ -824,7 +839,7 @@ dashboard.pointer_lookup_times=Pointer Lookup Times
|
||||
dashboard.memory_allocate_times=Memory Allocate Times
|
||||
dashboard.memory_free_times=Memory Free Times
|
||||
dashboard.current_heap_usage=Aktuelle Heap-Auslastung
|
||||
dashboard.heap_memory_obtained=erhaltener Heap-Memory
|
||||
dashboard.heap_memory_obtained=Erhaltener Heap-Memory
|
||||
dashboard.heap_memory_idle=unbenutzter Heap-Memory
|
||||
dashboard.heap_memory_in_use=benutzter Heap-Memory
|
||||
dashboard.heap_memory_released=freigegebener Heap-Memory
|
||||
@@ -857,7 +872,7 @@ users.new_success=Der neue Account '%s' wurde erfolgreich erstellt.
|
||||
users.edit=Bearbeiten
|
||||
users.auth_source=Authentifizierungsquelle
|
||||
users.local=Lokal
|
||||
users.auth_login_name=Authentifizierung-Loginnname
|
||||
users.auth_login_name=Authentifizierung-Login-Name
|
||||
users.password_helper=Leer lassen um es unverändert zu lassen.
|
||||
users.update_profile_success=Kontoprofil wurde erfolgreich aktualisiert.
|
||||
users.edit_account=Konto bearbeiten
|
||||
@@ -883,7 +898,7 @@ repos.owner=Besitzer
|
||||
repos.name=Name
|
||||
repos.private=Privat
|
||||
repos.watches=Beobachtungen
|
||||
repos.stars=Markierungen
|
||||
repos.stars=Sternchen
|
||||
repos.issues=Issues
|
||||
|
||||
auths.auth_manage_panel=Verwaltungspanel für die Authentifizierung
|
||||
@@ -903,14 +918,15 @@ auths.bind_password_helper=Warnung: Das Passwort wird im Klartext gespeichert. B
|
||||
auths.user_base=Benutzer-Such-Basis
|
||||
auths.user_dn=Benutzer DN
|
||||
auths.attribute_username=Attribute des Benutzernamens
|
||||
auths.attribute_username_placeholder=Leer lassen, um den Wert aus dem Login-Formular als Benutzername zu verwenden.
|
||||
auths.attribute_username_placeholder=Leer lassen, um den Wert aus dem Anmelde-Formular als Benutzername zu verwenden.
|
||||
auths.attribute_name=Vorname Attribut
|
||||
auths.attribute_surname=Nachname Attribut
|
||||
auths.attribute_mail=E-Mail Attribut
|
||||
auths.attributes_in_bind=Hole Attribute im Bind-Kontext
|
||||
auths.filter=Benutzernamen Filter
|
||||
auths.admin_filter=Admin Filter
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=SMTP Authentifizierungstyp
|
||||
auths.smtp_auth=SMTP Authentifizierung
|
||||
auths.smtphost=SMTP-Host
|
||||
auths.smtpport=SMTP-Port
|
||||
auths.allowed_domains=Erlaubte Domains
|
||||
@@ -937,7 +953,7 @@ config.app_url=Anwendungs-URL
|
||||
config.domain=Domain
|
||||
config.offline_mode=Offline-Modus
|
||||
config.disable_router_log=Router-Log deaktivieren
|
||||
config.run_user=Laufzeit-Benutzer
|
||||
config.run_user=Ausführender Benutzer
|
||||
config.run_mode=Laufzeit-Modus
|
||||
config.repo_root_path=Repository-Verzeichnis
|
||||
config.static_file_root_path=Verzeichnis für statische Dateien
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm=E-Mail-Bestätigung bei Registrierung
|
||||
config.disable_register=Registrierung deaktivieren
|
||||
config.show_registration_button=Zeige die Schaltfläche Registrieren
|
||||
config.require_sign_in_view=Ansehen erfordert Registrierung
|
||||
config.enable_cache_avatar=Avatar-Cache aktivieren
|
||||
config.mail_notify=E-Mail-Benachrichtigung
|
||||
config.disable_key_size_check=Prüfung der Mindestschlüssellänge deaktiveren
|
||||
config.enable_captcha=Captcha aktivieren
|
||||
@@ -1022,9 +1037,11 @@ notices.delete_success=Systemmitteilungen wurden erfolgreich gelöscht.
|
||||
|
||||
[action]
|
||||
create_repo=hat Repository <a href="%s">%s</a> erstellt
|
||||
rename_repo=das Repository wurde umbenannt von <code>%[1]s</code> zu <a href="%[2]s">%[3]s</a>
|
||||
rename_repo=hat das Repository von <code>%[1]s</code> zu <a href="%[2]s">%[3]s</a> umbenannt
|
||||
commit_repo=hat nach <a href="%[1]s/src/%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> gepusht
|
||||
create_issue=`hat Issue <a href="%s/issues/%s">%s#%[2]s</a> eröffnet`
|
||||
close_issue=`hat Issue <a href="%s/issues/%s">%s#%[2]s</a> geschlossen`
|
||||
reopen_issue=`hat Issue <a href="%s/issues/%s">%s#%[2]s</a> wiedereröffnet`
|
||||
create_pull_request=`Pull-Anforderung erstellt <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`hat Issue <a href="%s/issues/%s">%s#%[2]s</a> kommentiert`
|
||||
merge_pull_request=`Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> zuammengeführt`
|
||||
|
||||
@@ -38,7 +38,7 @@ settings = Settings
|
||||
your_profile = Your Profile
|
||||
your_settings = Your Settings
|
||||
|
||||
news_feed = News Feed
|
||||
activities = Activities
|
||||
pull_requests = Pull Requests
|
||||
issues = Issues
|
||||
|
||||
@@ -65,7 +65,7 @@ db_name = Database Name
|
||||
db_helper = Please use INNODB engine with utf8_general_ci charset for MySQL.
|
||||
ssl_mode = SSL Mode
|
||||
path = Path
|
||||
sqlite_helper = The file path of SQLite3 or TiDB database.
|
||||
sqlite_helper = The file path of SQLite3 or TiDB database. <br>Please use absolute path when you start as service.
|
||||
err_empty_db_path = SQLite3 or TiDB database path cannot be empty.
|
||||
err_invalid_tidb_name = TiDB database name does not allow characters "." and "-".
|
||||
no_admin_and_disable_registration = You cannot disable registration without creating an admin account.
|
||||
@@ -86,6 +86,8 @@ http_port = HTTP Port
|
||||
http_port_helper = Port number which application will listen on.
|
||||
app_url = Application URL
|
||||
app_url_helper = This affects HTTP/HTTPS clone URL and somewhere in email.
|
||||
log_root_path = Log Path
|
||||
log_root_path_helper = Directory to write log files to.
|
||||
|
||||
optional_title = Optional Settings
|
||||
email_title = Email Service Settings
|
||||
@@ -122,6 +124,7 @@ run_user_not_match = Run user isn't the current user: %s -> %s
|
||||
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.
|
||||
invalid_log_root_path = Log root path is invalid: %v
|
||||
|
||||
[home]
|
||||
uname_holder = Username or email
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken = Repository name has already been taken.
|
||||
org_name_been_taken = Organization name has already been taken.
|
||||
team_name_been_taken = Team name has already been taken.
|
||||
email_been_used = Email address has already been used.
|
||||
illegal_team_name = Team name contains illegal characters.
|
||||
username_password_incorrect = Username or password is not correct.
|
||||
enterred_invalid_repo_name = Please make sure that the repository name you entered is correct.
|
||||
enterred_invalid_owner_name = Please make sure that the owner name you entered is correct.
|
||||
@@ -217,7 +219,7 @@ auth_failed = Authentication failed: %v
|
||||
|
||||
still_own_repo = Your account still has ownership over at least one repository, you have to delete or transfer them first.
|
||||
still_has_org = Your account still has membership in at least one organization, you have to leave or delete your memberships first.
|
||||
org_still_own_repo = This organization still have ownership of repository, you have to delete or transfer them first.
|
||||
org_still_own_repo = This organization still has ownership of repositories, you must delete or transfer them first.
|
||||
|
||||
still_own_user = This authentication is still in use by at least one user, please remove them from the authentication and try again.
|
||||
|
||||
@@ -230,8 +232,10 @@ join_on = Joined on
|
||||
repositories = Repositories
|
||||
activity = Public Activity
|
||||
followers = Followers
|
||||
starred = Starred
|
||||
starred = Starred repositories
|
||||
following = Following
|
||||
follow = Follow
|
||||
unfollow = Unfollow
|
||||
|
||||
form.name_reserved = Username '%s' is reserved.
|
||||
form.name_pattern_not_allowed = Username pattern '%s' is not allowed.
|
||||
@@ -294,8 +298,8 @@ add_key = Add Key
|
||||
ssh_desc = This is a list of SSH keys associated with your account. As these keys allow anyone using them to gain access to your repositories, it is highly important that you make sure you recognize them.
|
||||
ssh_helper = <strong>Don't know how?</strong> Check out GitHub's guide to <a href="%s">create your own SSH keys</a> or solve <a href="%s">common problems</a> you might encounter using SSH.
|
||||
add_new_key = Add SSH Key
|
||||
ssh_key_been_used = Public key content has been used.
|
||||
ssh_key_name_used = Public key with same name has already existed.
|
||||
ssh_key_been_used = Public key content has been used.
|
||||
ssh_key_name_used = Public key with same name has already existed.
|
||||
key_name = Key Name
|
||||
key_content = Content
|
||||
add_key_success = New SSH key '%s' has been added successfully!
|
||||
@@ -375,7 +379,7 @@ 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
|
||||
|
||||
mirror_from = mirror from
|
||||
mirror_from = mirror of
|
||||
forked_from = forked from
|
||||
fork_from_self = You cannot fork a repository you already own!
|
||||
copy_link = Copy
|
||||
@@ -492,6 +496,7 @@ issues.label_modify = Label Modification
|
||||
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
|
||||
|
||||
pulls.new = New Pull Request
|
||||
pulls.compare_changes = Compare Changes
|
||||
@@ -523,7 +528,7 @@ milestones.new = New Milestone
|
||||
milestones.open_tab = %d Open
|
||||
milestones.close_tab = %d Closed
|
||||
milestones.closed = Closed %s
|
||||
milestones.no_due_date = No due date
|
||||
milestones.no_due_date = No due date
|
||||
milestones.open = Open
|
||||
milestones.close = Close
|
||||
milestones.new_subheader = Create milestones to organize your issues.
|
||||
@@ -573,23 +578,28 @@ settings.wiki_desc = Enable wiki to allow people write documents
|
||||
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 builtin lightweight issue tracker
|
||||
settings.use_external_issue_tracker = Use external issue tracker
|
||||
settings.tracker_url_format = External Issue Tracker URL Format
|
||||
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
|
||||
settings.new_owner_has_same_repo = The new owner already has a repository with same name. Please choose another name.
|
||||
settings.convert = Convert To Regular Repository
|
||||
settings.convert_desc = You can convert this mirror to a regular repository. This cannot be reversed.
|
||||
settings.convert_notices_1 = - This operation will convert this repository mirror into a regular repository and cannot be undone.
|
||||
settings.convert_confirm = Confirm Conversion
|
||||
settings.convert_succeed = Repository has been converted to regular type successfully.
|
||||
settings.transfer = Transfer Ownership
|
||||
settings.transfer_desc = Transfer this repository to another user or to an organization in which you have admin rights.
|
||||
settings.new_owner_has_same_repo = The new owner already has a repository with same name. Please choose another name.
|
||||
settings.delete = Delete This Repository
|
||||
settings.delete_desc = Once you delete a repository, there is no going back. Please be certain.
|
||||
settings.transfer_notices_1 = - You will lose access if new owner is a individual user.
|
||||
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 = Please enter following information to confirm your operation:
|
||||
settings.transfer_form_title = Please enter following information to confirm your operation:
|
||||
settings.delete = Delete This Repository
|
||||
settings.delete_desc = Once you delete a repository, there is no going back. Please be certain.
|
||||
settings.delete_notices_1 = - This operation <strong>CANNOT</strong> be undone.
|
||||
settings.delete_notices_2 = - This operation will permanently delete the everything of this repository, including Git data, issues, comments and accesses of collaborators.
|
||||
settings.delete_notices_fork_1 = - If this repository is public, all forks will be became independent after deletion.
|
||||
settings.delete_notices_fork_1 = - If this repository is public, all forks will become independent after deletion.
|
||||
settings.delete_notices_fork_2 = - If this repository is private, all forks will be removed at the same time.
|
||||
settings.delete_notices_fork_3 = - If you want to keep all forks after deletion, please change visibility of this repository to public first.
|
||||
settings.deletion_success = Repository has been deleted successfully!
|
||||
@@ -602,6 +612,7 @@ settings.add_collaborator = Add New Collaborator
|
||||
settings.add_collaborator_success = New collaborator has been added.
|
||||
settings.remove_collaborator_success = Collaborator has been removed.
|
||||
settings.search_user_placeholder = Search user...
|
||||
settings.org_not_allowed_to_be_collaborator = Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member = User is organization member who cannot be added as a collaborator.
|
||||
settings.add_webhook = Add Webhook
|
||||
settings.hooks_desc = Webhooks are much like basic HTTP POST event triggers. Whenever something occurs in Gogs, we will handle the notification to the target host you specify. Learn more in this <a target="_blank" href="%s">Webhooks Guide</a>.
|
||||
@@ -610,7 +621,7 @@ settings.webhook_deletion_desc = Delete this webhook will remove its information
|
||||
settings.webhook_deletion_success = Webhook has been deleted successfully!
|
||||
settings.webhook.test_delivery = Test Delivery
|
||||
settings.webhook.test_delivery_desc = Send a fake push event delivery to test your webhook settings
|
||||
settings.webhook.test_delivery_success = Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
|
||||
settings.webhook.test_delivery_success = Test webhook has been added to delivery queue. It may take few seconds before it shows up in the delivery history.
|
||||
settings.webhook.request = Request
|
||||
settings.webhook.response = Response
|
||||
settings.webhook.headers = Headers
|
||||
@@ -650,8 +661,8 @@ settings.slack_domain = Domain
|
||||
settings.slack_channel = Channel
|
||||
settings.deploy_keys = Deploy Keys
|
||||
settings.add_deploy_key = Add Deploy Key
|
||||
settings.deploy_key_desc = Deploy key only has read-only access. It is not same as personal account SSH keys.
|
||||
settings.no_deploy_keys = You haven't added any deploy key.
|
||||
settings.deploy_key_desc = Deploy keys have read-only access. They are not the same as personal account SSH keys.
|
||||
settings.no_deploy_keys = You haven't added any deploy keys.
|
||||
settings.title = Title
|
||||
settings.deploy_key_content = Content
|
||||
settings.key_been_used = Deploy key content has been used.
|
||||
@@ -666,6 +677,8 @@ diff.parent = parent
|
||||
diff.commit = commit
|
||||
diff.data_not_available = Diff Data Not Available.
|
||||
diff.show_diff_stats = Show Diff Stats
|
||||
diff.show_split_view = Split View
|
||||
diff.show_unified_view = Unified View
|
||||
diff.stats_desc = <strong> %d changed files</strong> with <strong>%d additions</strong> and <strong>%d deletions</strong>
|
||||
diff.bin = BIN
|
||||
diff.view_file = View File
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys = Rewrite '.ssh/authorized_keys' file (caution: non
|
||||
dashboard.resync_all_sshkeys_success = All public keys have been rewritten successfully.
|
||||
dashboard.resync_all_update_hooks = Rewrite all update hook of repositories (needed when custom config path is changed)
|
||||
dashboard.resync_all_update_hooks_success = All repositories' update hook have been rewritten successfully.
|
||||
dashboard.reinit_missing_repos = Reinitialize all repository records that lost Git files
|
||||
dashboard.reinit_missing_repos_success = All repository records that lost Git files have been reinitialized successfully.
|
||||
|
||||
dashboard.server_uptime = Server Uptime
|
||||
dashboard.current_goroutine = Current Goroutines
|
||||
@@ -836,7 +851,7 @@ dashboard.mspan_structures_obtained = MSpan Structures Obtained
|
||||
dashboard.mcache_structures_usage = MCache Structures Usage
|
||||
dashboard.mcache_structures_obtained = MCache Structures Obtained
|
||||
dashboard.profiling_bucket_hash_table_obtained = Profiling Bucket Hash Table Obtained
|
||||
dashboard.gc_metadata_obtained = GC Metadada Obtained
|
||||
dashboard.gc_metadata_obtained = GC Metadata Obtained
|
||||
dashboard.other_system_allocation_obtained = Other System Allocation Obtained
|
||||
dashboard.next_gc_recycle = Next GC Recycle
|
||||
dashboard.last_gc_time = Since Last GC Time
|
||||
@@ -907,6 +922,7 @@ auths.attribute_username_placeholder = Leave empty to use sign-in form field val
|
||||
auths.attribute_name = First name attribute
|
||||
auths.attribute_surname = Surname attribute
|
||||
auths.attribute_mail = Email attribute
|
||||
auths.attributes_in_bind = Fetch attributes in Bind DN context
|
||||
auths.filter = User Filter
|
||||
auths.admin_filter = Admin Filter
|
||||
auths.ms_ad_sa = Ms Ad SA
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm = Require Email Confirmation
|
||||
config.disable_register = Disable Registration
|
||||
config.show_registration_button = Show Register Button
|
||||
config.require_sign_in_view = Require Sign In View
|
||||
config.enable_cache_avatar = Enable Cache Avatar
|
||||
config.mail_notify = Mail Notification
|
||||
config.disable_key_size_check = Disable Minimum Key Size Check
|
||||
config.enable_captcha = Enable Captcha
|
||||
@@ -1025,6 +1040,8 @@ create_repo = created repository <a href="%s">%s</a>
|
||||
rename_repo = renamed repository from <code>%[1]s</code> to <a href="%[2]s">%[3]s</a>
|
||||
commit_repo = pushed to <a href="%[1]s/src/%[2]s">%[3]s</a> at <a href="%[1]s">%[4]s</a>
|
||||
create_issue = `opened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue = `closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue = `reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request = `created pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue = `commented on issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request = `merged pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
@@ -1056,5 +1073,5 @@ raw_minutes = minutes
|
||||
[dropzone]
|
||||
default_message = Drop files here or click to upload.
|
||||
invalid_input_type = You can't upload files of this type.
|
||||
file_too_big = File size({{filesize}} MB) exceeds maximum size({{maxFilesize}} MB).
|
||||
file_too_big = File size ({{filesize}} MB) exceeds maximum size ({{maxFilesize}} MB).
|
||||
remove_file = Remove file
|
||||
|
||||
@@ -38,7 +38,7 @@ settings=Configuraciones
|
||||
your_profile=Tu perfil
|
||||
your_settings=Tu configuración
|
||||
|
||||
news_feed=Feed de noticias
|
||||
activities=Actividad
|
||||
pull_requests=Pull Requests
|
||||
issues=Incidencias
|
||||
|
||||
@@ -65,7 +65,7 @@ db_name=Nombre de la base de datos
|
||||
db_helper=Por favor utilice el motor INNODB con la configuración de caracteres utf8_general_ci para MySQL.
|
||||
ssl_mode=Modo SSL
|
||||
path=Ruta
|
||||
sqlite_helper=Ruta del archivo con la base de datos SQLite3 o TiDB.
|
||||
sqlite_helper=Ruta al archivo de base de datos SQLite3 o TiDB. <br>Por favor, usa una ruta absoluta cuando inicies como servicio.
|
||||
err_empty_db_path=La ruta a la base de datos SQLite3 o TiDB no puede estar vacía.
|
||||
err_invalid_tidb_name=El nombre de la base de datos TiDB no puede contener los caracteres "." ni "-".
|
||||
no_admin_and_disable_registration=No puede deshabilitar el registro sin crear una cuenta de administrador.
|
||||
@@ -86,6 +86,8 @@ http_port=Puerto HTTP
|
||||
http_port_helper=Puerto en el que escuchará la aplicación.
|
||||
app_url=URL de la aplicación
|
||||
app_url_helper=Esto afecta a las URLs para clonar por HTTP/HTTPS y a algunos correos electrónicos.
|
||||
log_root_path=Ruta del registro
|
||||
log_root_path_helper=Directorio donde almacenar los registros.
|
||||
|
||||
optional_title=Configuración Opcional
|
||||
email_title=Configuración del Servicio de Correo
|
||||
@@ -122,15 +124,16 @@ run_user_not_match=El usuario que está ejecutando la aplicación no es el usuar
|
||||
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.
|
||||
invalid_log_root_path=La ruta para los registros es inválida: %v
|
||||
|
||||
[home]
|
||||
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
|
||||
my_repos=Mis repositorios
|
||||
collaborative_repos=Repositorios Colaborativos
|
||||
my_orgs=Mis Organizaciones
|
||||
my_mirrors=Mis Mirrors
|
||||
my_orgs=Mis organizaciones
|
||||
my_mirrors=Mis réplicas
|
||||
view_home=Ver %s
|
||||
|
||||
issues.in_your_repos=En tus repositorios
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken=Ya existe un repositorio con este nombre.
|
||||
org_name_been_taken=Ya existe una organización con este nombre.
|
||||
team_name_been_taken=Ya existe un equipo con este nombre.
|
||||
email_been_used=Esta dirección de correo electrónico ya está en uso.
|
||||
illegal_team_name=El nombre del equipo contiene caracteres inválidos.
|
||||
username_password_incorrect=Nombre de usuario o contraseña incorrectos.
|
||||
enterred_invalid_repo_name=Por favor, asegúrate de que has introducido correctamente el nombre del repositorio.
|
||||
enterred_invalid_owner_name=Por favor, asegúrate de que has introducido correctamente el nombre del propietario.
|
||||
@@ -232,6 +234,8 @@ activity=Actividad pública
|
||||
followers=Seguidores
|
||||
starred=Destacados
|
||||
following=Siguiendo
|
||||
follow=Seguir
|
||||
unfollow=Dejar de seguir
|
||||
|
||||
form.name_reserved=El usuario '%s' está reservado.
|
||||
form.name_pattern_not_allowed=El patrón de nombre de usuario '%s' no está permitido.
|
||||
@@ -243,7 +247,7 @@ ssh_keys=Claves SSH
|
||||
social=Redes Sociales
|
||||
applications=Aplicaciones
|
||||
orgs=Organizaciones
|
||||
delete=Eliminar Cuenta
|
||||
delete=Eliminar cuenta
|
||||
uid=UUID
|
||||
|
||||
public_profile=Perfil Público
|
||||
@@ -281,8 +285,8 @@ email_desc=Tu dirección de correo principal se utilizará para las notificacion
|
||||
primary=Principal
|
||||
primary_email=Marcar como principal
|
||||
delete_email=Eliminar
|
||||
email_deletion=Eliminación de Correo Electrónico
|
||||
email_deletion_desc=Al eliminar esta dirección de correo electrónico se eliminará toda la información asociada a esta dirección de correo electrónico. ¿Deseas continuar?
|
||||
email_deletion=Eliminar correo electrónico
|
||||
email_deletion_desc=Al eliminar esta dirección de correo electrónico se eliminará toda la información asociada a esta. ¿Deseas continuar?
|
||||
email_deletion_success=¡El correo electrónico ha sido eliminado correctamente!
|
||||
add_new_email=Añadir nueva dirección de correo electrónico
|
||||
add_email=Añadir correo electrónico
|
||||
@@ -334,7 +338,7 @@ delete_account_desc=Esta cuenta se va a eliminar permanentemente, ¿quieres cont
|
||||
|
||||
[repo]
|
||||
owner=Propietario
|
||||
repo_name=Nombre del Repositorio
|
||||
repo_name=Nombre del repositorio
|
||||
repo_name_helper=Los grandes nombres de repositorios son cortos, memorables y <strong>únicos</strong>.
|
||||
visibility=Visibilidad
|
||||
visiblity_helper=Este repositorio es <span class="ui red text">Privado</span>
|
||||
@@ -345,7 +349,7 @@ fork_repo=Hacer Fork del repositorio
|
||||
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=Lenguaje
|
||||
repo_lang_helper=Seleccione archivo .gitignore
|
||||
license=Licencia
|
||||
license_helper=Selecciona un fichero de licencia
|
||||
@@ -354,7 +358,7 @@ 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_interval=Intervalo de mirror(en horas)
|
||||
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.
|
||||
watchers=Seguidores
|
||||
@@ -367,7 +371,7 @@ form.name_pattern_not_allowed=El patrón del nombre del repositorio '%s' no est
|
||||
|
||||
need_auth=Requiere Autorización
|
||||
migrate_type=Tipo de Migración
|
||||
migrate_type_helper=Este repositorio será un <span class="text blue">mirror</span>
|
||||
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.
|
||||
@@ -379,7 +383,7 @@ mirror_from=espejo de
|
||||
forked_from=forked de
|
||||
fork_from_self=Eres el propietario del repositorio, ¡no puedes hacer fork!
|
||||
copy_link=Copiar
|
||||
copy_link_success=Copiado!
|
||||
copy_link_success=¡Copiado!
|
||||
copy_link_error=Presione ⌘ + C o Ctrl-C para copiar
|
||||
copied=Copiado correctamente
|
||||
unwatch=Dejar de vigilar
|
||||
@@ -492,6 +496,7 @@ issues.label_modify=Edición de Etiqueta
|
||||
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
|
||||
|
||||
pulls.new=Nuevo Pull Request
|
||||
pulls.compare_changes=Comparar Cambios
|
||||
@@ -540,7 +545,7 @@ milestones.cancel=Cancelar
|
||||
milestones.modify=Modificar Milestone
|
||||
milestones.edit_success=¡Los cambios al milestone '%s' se han guardado con éxito!
|
||||
milestones.deletion=Borrar milestone
|
||||
milestones.deletion_desc=El borrado de este milestone eliminará su información y las incidencias asociadas. ¿Desea continuar?
|
||||
milestones.deletion_desc=Eliminar este Milestone eliminará su información y las incidencias asociadas. ¿Desea continuar?
|
||||
milestones.deletion_success=¡El milestone ha sido eliminado con éxito!
|
||||
|
||||
wiki=Wiki
|
||||
@@ -565,8 +570,8 @@ settings.collaboration=Colaboración
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Git Hooks
|
||||
settings.basic_settings=Configuración Básica
|
||||
settings.site=Sitio Oficial
|
||||
settings.update_settings=Actualizar Configuración
|
||||
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
|
||||
@@ -576,17 +581,22 @@ settings.external_wiki_url_desc=Los visitantes serán redireccionados a la URL c
|
||||
settings.issues_desc=Habilitar tracker ligero de incidencias
|
||||
settings.use_external_issue_tracker=Usar tracker externo de incidencias
|
||||
settings.tracker_url_format=Formato URL del tracker de incidencias externo
|
||||
settings.tracker_url_format_desc=Puedes usar las plantillas <code>{user} {repo} {index}</code> para el nombre de usuario, nombre del repositorio e índice del issue.
|
||||
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
|
||||
settings.transfer=Transferir la Propiedad
|
||||
settings.transfer_desc=Transferir este repositorio a otro usuario u organización donde tengas permisos de administración.
|
||||
settings.new_owner_has_same_repo=El nuevo propietario tiene un repositorio con el mismo nombre.
|
||||
settings.delete=Eliminar este Repositorio
|
||||
settings.delete_desc=Una vez has eliminado un repositorio, no hay vuelta atrás. Por favor, asegúrate de que es lo que quieres.
|
||||
settings.convert=Convertir en un repositorio normal
|
||||
settings.convert_desc=Puedes convertir este repositorio en un repositorio normal. Este cambio no se puede deshacer.
|
||||
settings.convert_notices_1=- Esta operación convertirá este repositorio espejo en un repositorio normal y no podrá deshacerse.
|
||||
settings.convert_confirm=Confirmar conversión
|
||||
settings.convert_succeed=El repositorio ha sido convertido en normal satisfactoriamente.
|
||||
settings.transfer=Transferir la propiedad
|
||||
settings.transfer_desc=Transferir este repositorio a otro usuario u organización donde tengas permisos de administración.
|
||||
settings.transfer_notices_1=- Perderá el permiso de acceso si el nuevo propietario es otro usuario.
|
||||
settings.transfer_notices_2=- Conservará el privilegio de acceso si el nuevo propietario es una organización y usted es uno de los propietarios de dicha organización.
|
||||
settings.transfer_form_title=Por favor introduzca esta información para confirmar la operación:
|
||||
settings.delete=Eliminar este repositorio
|
||||
settings.delete_desc=Una vez has eliminado un repositorio, no hay vuelta atrás. Por favor, asegúrate de que es lo que quieres.
|
||||
settings.delete_notices_1=- Esta operación <strong>NO PUEDE</strong> revertirse.
|
||||
settings.delete_notices_2=- Esta operación eliminará de manera permanente todo el contenido de este repositorio, incluyendo los datos de git, las incidencias, los comentarios y los permisos de acceso de los colaboradores.
|
||||
settings.delete_notices_fork_1=- Si este repositorio es público, todos los forks se convertirán en repositorios independientes tras el borrado.
|
||||
@@ -597,11 +607,12 @@ settings.update_settings_success=Las opciones del repositorio se han actualizado
|
||||
settings.transfer_owner=Nuevo Propietario
|
||||
settings.make_transfer=Transferir
|
||||
settings.transfer_succeed=La propiedad del repositorio ha sido transferida exitosamente.
|
||||
settings.confirm_delete=Confirmar Eliminación
|
||||
settings.confirm_delete=Confirmar eliminación
|
||||
settings.add_collaborator=Añadir Nuevo Colaborador
|
||||
settings.add_collaborator_success=Se ha añadido el nuevo colaborador.
|
||||
settings.remove_collaborator_success=Se ha eliminado el colaborador.
|
||||
settings.search_user_placeholder=Buscar usuario...
|
||||
settings.org_not_allowed_to_be_collaborator=Las organizaciones no tiene permitido ser añadidas como colaboradores.
|
||||
settings.user_is_org_member=El usuario es miembro de la organización, no puede ser añadido como colaborador.
|
||||
settings.add_webhook=Añadir Webhook
|
||||
settings.hooks_desc=Los Webhooks permiten a servicios externos recibir notificaciones cuando sucedan ciertos eventos en Gogs. Cuando sucedan los eventos especificados, enviaremos una petición POST a cada una de las URLs indicadas. Para obtener más información, consulta nuestra <a target="_blank" href="%s">Guía de Webhooks</a>.
|
||||
@@ -666,6 +677,8 @@ diff.parent=padre
|
||||
diff.commit=commit
|
||||
diff.data_not_available=Los datos del Diff no están disponibles.
|
||||
diff.show_diff_stats=Mostrar Estadísticas de Diff
|
||||
diff.show_split_view=Dividir vista
|
||||
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
|
||||
@@ -692,10 +705,10 @@ release.prerelease_desc=Esta es una pre-release
|
||||
release.prerelease_helper=Esta release está marcada como no apta para producción.
|
||||
release.cancel=Cancelar
|
||||
release.publish=Publicar Release
|
||||
release.save_draft=Guardar Borrador
|
||||
release.save_draft=Guardar borrador
|
||||
release.edit_release=Editar Release
|
||||
release.delete_release=Borrar este Release
|
||||
release.deletion=Eliminación de Release
|
||||
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.
|
||||
@@ -728,15 +741,15 @@ settings.options=Opciones
|
||||
settings.full_name=Nombre Completo
|
||||
settings.website=Página Web
|
||||
settings.location=Localización
|
||||
settings.update_settings=Actualizar Configuración
|
||||
settings.update_setting_success=La configuración de la Organización se ha actualizado correctamente.
|
||||
settings.update_settings=Actualizar configuración
|
||||
settings.update_setting_success=La configuración de la organización se ha actualizado correctamente.
|
||||
settings.change_orgname_prompt=Este cambio afectará a los enlaces que hacen referencia a la organización.
|
||||
settings.update_avatar_success=La configuración de avatar de la organización ha sido actualizada con éxito.
|
||||
settings.delete=Eliminar Organización
|
||||
settings.delete_account=Eliminar esta Organización
|
||||
settings.delete=Eliminar organización
|
||||
settings.delete_account=Eliminar esta organización
|
||||
settings.delete_prompt=Esta operación eliminará esta organización de manera permanente, y ¡<strong>NO PUEDE</strong> deshacerse!
|
||||
settings.confirm_delete_account=Confirmar Eliminación
|
||||
settings.delete_org_title=Eliminación de la Organización
|
||||
settings.confirm_delete_account=Confirmar eliminación
|
||||
settings.delete_org_title=Eliminación de la organización
|
||||
settings.delete_org_desc=Esta organización se va a eliminar permanentemente, ¿quieres continuar?
|
||||
settings.hooks_desc=Añadir webhooks que serán ejecutados para <strong>todos los repositorios</strong> de esta organización.
|
||||
|
||||
@@ -765,7 +778,7 @@ teams.no_desc=Este equipo no tiene descripción
|
||||
teams.settings=Configuración
|
||||
teams.owners_permission_desc=Los propietarios tienen acceso completo a <strong>todos los repositorios</strong> y tienen <strong>derechos de administración</strong> en la organización.
|
||||
teams.members=Miembros del Equipo
|
||||
teams.update_settings=Actualizar Configuración
|
||||
teams.update_settings=Actualizar configuración
|
||||
teams.delete_team=Borrar este Equipo
|
||||
teams.add_team_member=Añadir Miembro al Equipo
|
||||
teams.delete_team_title=Eliminar Equipo
|
||||
@@ -787,7 +800,7 @@ organizations=Organizaciones
|
||||
repositories=Repositorios
|
||||
authentication=Autenticaciones
|
||||
config=Configuración
|
||||
notices=Avisos del Sistema
|
||||
notices=Notificaciones del sistema
|
||||
monitor=Monitorización
|
||||
first_page=Primera
|
||||
last_page=Última
|
||||
@@ -814,16 +827,18 @@ dashboard.resync_all_sshkeys=Reescribir el fichero '.ssh/authorized_keys'(atenci
|
||||
dashboard.resync_all_sshkeys_success=Todas las claves públicas se han reescrito correctamente.
|
||||
dashboard.resync_all_update_hooks=Reescribir todos los hooks de actualización de los repositorios (necesario cuando se modifica la ruta de configuración personalizada)
|
||||
dashboard.resync_all_update_hooks_success=Todos los hooks de actualización de los repositorios se han reescrito correctamente.
|
||||
dashboard.reinit_missing_repos=Reinicializar todos los registros del repositorio que tienen archivos Git eliminados
|
||||
dashboard.reinit_missing_repos_success=Todos los registros del repositorio con archivos Git eliminados han sido reinicializados con éxito.
|
||||
|
||||
dashboard.server_uptime=Uptime del Servidor
|
||||
dashboard.current_goroutine=Gorutinas Actuales
|
||||
dashboard.current_memory_usage=Uso de Memoria Actual
|
||||
dashboard.server_uptime=Tiempo de actividad del servidor
|
||||
dashboard.current_goroutine=Gorutinas actuales
|
||||
dashboard.current_memory_usage=Uso de memoria actual
|
||||
dashboard.total_memory_allocated=Total de Memoria Reservada
|
||||
dashboard.memory_obtained=Memoria Obtenida
|
||||
dashboard.pointer_lookup_times=Tiempos de Búsqueda de Punteros
|
||||
dashboard.memory_allocate_times=Tiempos de Reserva de Memoria
|
||||
dashboard.memory_free_times=Tiempos de Liberado de Memoria
|
||||
dashboard.current_heap_usage=Uso de Heap Actual
|
||||
dashboard.current_heap_usage=Uso de Heap actual
|
||||
dashboard.heap_memory_obtained=Memoria de Heap Obtenida
|
||||
dashboard.heap_memory_idle=Memoria de Heap Inactiva
|
||||
dashboard.heap_memory_in_use=Memoria de Heap en Uso
|
||||
@@ -886,8 +901,8 @@ repos.watches=Vigilantes
|
||||
repos.stars=Estrellas
|
||||
repos.issues=Incidencias
|
||||
|
||||
auths.auth_manage_panel=Panel de Administración de Autenticación
|
||||
auths.new=Añadir Nuevo Origen
|
||||
auths.auth_manage_panel=Panel de administración de autenticación
|
||||
auths.new=Añadir nuevo origen
|
||||
auths.name=Nombre
|
||||
auths.type=Tipo
|
||||
auths.enabled=Activo
|
||||
@@ -902,11 +917,12 @@ auths.bind_password=Contraseña Bind
|
||||
auths.bind_password_helper=Advertencia: La contraseña se almacena como texto plano. No utilice una cuenta con privilegios elevados.
|
||||
auths.user_base=Base de Búsqueda de Usuarios
|
||||
auths.user_dn=DN de Usuario
|
||||
auths.attribute_username=Username attribute
|
||||
auths.attribute_username=Atributo de nombre de usuario
|
||||
auths.attribute_username_placeholder=Dejar vacío para usar el campo de inicio de sesión como nombre de usuario.
|
||||
auths.attribute_name=Atributo nombre
|
||||
auths.attribute_surname=Atributo apellido
|
||||
auths.attribute_mail=Atributo correo electrónico
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
auths.filter=Filtro de Usuario
|
||||
auths.admin_filter=Filtro de Aministrador
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -924,9 +940,9 @@ auths.edit=Editar la Configuración de Autenticación
|
||||
auths.activated=Esta autenticación ha sido activada
|
||||
auths.new_success=¡La autenticación '%s' ha sido añadida con éxito!
|
||||
auths.update_success=La configuración de autenticación ha sido actualizada con éxito.
|
||||
auths.update=Actualizar la Configuración de Autenticación
|
||||
auths.update=Actualizar la configuración de autenticación
|
||||
auths.delete=Eliminar Autenticación
|
||||
auths.delete_auth_title=Borrado de Autenticación
|
||||
auths.delete_auth_title=Borrado de autenticación
|
||||
auths.delete_auth_desc=Esta autenticación será eliminada. ¿Deseas continuar?
|
||||
auths.deletion_success=¡La autenticación ha sido eliminada con éxito!
|
||||
|
||||
@@ -938,7 +954,7 @@ config.domain=Dominio
|
||||
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.run_mode=Modo de ejecución
|
||||
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
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm=Solicitar Confirmación por Correo Electrónico
|
||||
config.disable_register=Deshabilitar el Registro
|
||||
config.show_registration_button=Mostrar Botón de Registro
|
||||
config.require_sign_in_view=Solicitar la Vista de Inicio de Sesión
|
||||
config.enable_cache_avatar=Activar la Caché de Avatar
|
||||
config.mail_notify=Notificación por Correo Electrónico
|
||||
config.disable_key_size_check=Deshabilitar la comprobación de Tamaño Mínimo de Clave
|
||||
config.enable_captcha=Activar Captcha
|
||||
@@ -998,10 +1013,10 @@ config.log_mode=Modo del Log
|
||||
monitor.cron=Tareas de Cron
|
||||
monitor.name=Nombre
|
||||
monitor.schedule=Agenda
|
||||
monitor.next=Próxima Vez
|
||||
monitor.previous=Vez Anterior
|
||||
monitor.next=Siguiente
|
||||
monitor.previous=Anterior
|
||||
monitor.execute_times=Ejecuciones
|
||||
monitor.process=Procesos en Ejecución
|
||||
monitor.process=Procesos en ejecución
|
||||
monitor.desc=Descripción
|
||||
monitor.start=Hora de Inicio
|
||||
monitor.execute_time=Tiempo de ejecución
|
||||
@@ -1021,10 +1036,12 @@ notices.op=Op.
|
||||
notices.delete_success=Las notificaciones del sistema han sido eliminadas satisfactoriamente.
|
||||
|
||||
[action]
|
||||
create_repo=repositorio creado <a href="%s">%s</a>
|
||||
create_repo=creó el repositorio <a href="%s">%s</a>
|
||||
rename_repo=repositorio renombrado de <code>%[1]s</code> a <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=hizo push a <a href="%[1]s/src/%[2]s">%[3]s</a> en <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`incidencia abierta <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue=`cerró la incidencia <a href="%s/issues/%s">%s#%[2]s"</a>`
|
||||
reopen_issue=`reabrió la incidencia <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`creado pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`comentó en la incidencia <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`fusionado pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
|
||||
@@ -6,9 +6,9 @@ explore=Explorer
|
||||
help=Aide
|
||||
sign_in=Connexion
|
||||
sign_out=Déconnexion
|
||||
sign_up=Créer un compte
|
||||
register=Inscription
|
||||
website=Site Web
|
||||
sign_up=Inscription
|
||||
register=S'inscrire
|
||||
website=Site web
|
||||
version=Version
|
||||
page=Page
|
||||
template=Modèle
|
||||
@@ -26,21 +26,21 @@ captcha=Captcha
|
||||
repository=Dépôt
|
||||
organization=Organisation
|
||||
mirror=Miroir
|
||||
new_repo=Nouveau Dépôt
|
||||
new_migrate=Nouvelle Migration
|
||||
new_repo=Nouveau dépôt
|
||||
new_migrate=Nouvelle migration
|
||||
new_mirror=Nouveau miroir
|
||||
new_fork=Nouvel embranchement
|
||||
new_org=Nouvelle Organisation
|
||||
manage_org=Gérer les Organisations
|
||||
new_fork=Nouveau fork
|
||||
new_org=Nouvelle organisation
|
||||
manage_org=Gérer les organisations
|
||||
admin_panel=Administration
|
||||
account_settings=Paramètres du Compte
|
||||
account_settings=Paramètres du compte
|
||||
settings=Paramètres
|
||||
your_profile=Votre profil
|
||||
your_settings=Vos paramètres
|
||||
|
||||
news_feed=Flux d'actualités
|
||||
activities=Activités
|
||||
pull_requests=Pull Requests
|
||||
issues=Problèmes
|
||||
issues=Tickets
|
||||
|
||||
cancel=Annuler
|
||||
|
||||
@@ -48,7 +48,7 @@ cancel=Annuler
|
||||
search=Rechercher...
|
||||
repository=Dépôt
|
||||
user=Utilisateur
|
||||
issue=Problème
|
||||
issue=Ticket
|
||||
code=Code
|
||||
|
||||
[install]
|
||||
@@ -57,49 +57,51 @@ title=Instructions pour la première exécution
|
||||
docker_helper=Si vous exécutez Gogs grâce à Docker, merci de lire la <a target="_blank" href="%s">procédure</a> attentivement avant de modifier quoi que ce soit sur cette page !
|
||||
requite_db_desc=Gogs requiert MySQL, PostgreSQL, SQLite3 ou TiDB.
|
||||
db_title=Paramètres de la base de données
|
||||
db_type=Type de Base de Données
|
||||
db_type=Type de base de données
|
||||
host=Hôte
|
||||
user=Utilisateur
|
||||
password=Mot De Passe
|
||||
db_name=Nom de la Base de Données
|
||||
password=Mot de passe
|
||||
db_name=Nom de base de données
|
||||
db_helper=Veuillez utiliser le moteur INNODB avec le jeu de caractères utf8_general_ci pour MySQL.
|
||||
ssl_mode=Mode SSL
|
||||
path=Chemin
|
||||
sqlite_helper=Le chemin du fichier de la base de données SQLite3 ou TiDB.
|
||||
sqlite_helper=Le chemin du fichier de base de données SQLite3 ou TiDB. <br>Utilisez un chemin absolu lorsque vous démarrez en tant que service.
|
||||
err_empty_db_path=Le chemin de la base de données SQLite3 ou TiDB ne peut être vide.
|
||||
err_invalid_tidb_name=Le nom de la base de données TiDB ne peut contenir les caractères "." ou "-".
|
||||
no_admin_and_disable_registration=Vous ne pouvez pas désactiver l'enregistrement sans créer un compte administrateur.
|
||||
err_empty_admin_password=Le mot de passe du compte administrateur ne peut être vide.
|
||||
|
||||
general_title=Paramètres Généraux de Gogs
|
||||
app_name=Nom de l'Application
|
||||
general_title=Paramètres généraux de Gogs
|
||||
app_name=Nom de l'application
|
||||
app_name_helper=Inscrivez fièrement le nom de votre organisation ici !
|
||||
repo_path=Emplacement Racine du Dépôt
|
||||
repo_path_helper=Tous les Dépôts Git distants seront sauvegardés ici.
|
||||
run_user=Entrer un Utilisateur
|
||||
run_user_helper=L'utilisateur doit avoir accès à la Racine du Référentiel et éxécuter Gogs.
|
||||
repo_path=Emplacement racine des dépôts
|
||||
repo_path_helper=Tous les dépôts Git distants seront sauvegardés ici.
|
||||
run_user=Entrer un utilisateur
|
||||
run_user_helper=L'utilisateur doit avoir accès à la racine des dépôts et exécuter Gogs.
|
||||
domain=Domaine
|
||||
domain_helper=Cela affecte les doublons d'URL SSH.
|
||||
ssh_port=Port SSH
|
||||
ssh_port_helper=C'est le numéro de port qui est utilisé par votre serveur SSH, le laisser vide pour désactiver la fonctionnalité.
|
||||
ssh_port_helper=Numéro de port utilisé par votre serveur SSH, le laisser vide pour désactiver la fonctionnalité.
|
||||
http_port=Port HTTP
|
||||
http_port_helper=Numéro de port que l'application écoutera.
|
||||
app_url=URL de l'Application
|
||||
app_url=URL de l'application
|
||||
app_url_helper=Cela affecte les doublons d'URL HTTP/HTTPS et le contenu d'e-mail.
|
||||
log_root_path=Chemin des fichiers log
|
||||
log_root_path_helper=Répertoire d'écriture des fichiers de log.
|
||||
|
||||
optional_title=Paramètres facultatifs
|
||||
email_title=Paramètres du Service de Messagerie
|
||||
smtp_host=Hôte SMTP
|
||||
smtp_from=Provenant de
|
||||
smtp_from_helper=Adresse de l'expéditeur, RFC 5322. Soit une adresse courriel simple, soit au format "Nom" <email@example.com>.
|
||||
mailer_user=E-mail de l'Expéditeur
|
||||
mailer_password=Mot de Passe de l'Expéditeur
|
||||
register_confirm=Activer la Confirmation d'Enregistrement
|
||||
mail_notify=Activer la Notification des Mails reçus
|
||||
mailer_user=E-mail de l'expéditeur
|
||||
mailer_password=Mot de passe de l'expéditeur
|
||||
register_confirm=Activer la confirmation de l'inscription
|
||||
mail_notify=Activer la notification par e-mail
|
||||
server_service_title=Paramètres du serveur et des autres services
|
||||
offline_mode=Activer le Mode hors connexion
|
||||
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=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.
|
||||
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.
|
||||
@@ -107,28 +109,29 @@ enable_captcha=Activez le Captcha
|
||||
enable_captcha_popup=Demande la validation Captcha pour l'auto-enregistrement de l'utilisateur.
|
||||
require_sign_in_view=Demander une connexion pour afficher des pages
|
||||
require_sign_in_view_popup=Seules les personnes connectées peuvent voir les pages. Les visiteurs anonymes ne pourront voir que les pages de connexion/enregistrement.
|
||||
admin_setting_desc=Vous n'avez pas besoin de créer un compte admin. L'utilisateur ayant l'ID = 1 se verra automatiquement attribuer l'accès administrateur.
|
||||
admin_title=Paramètres du Compte Administrateur
|
||||
admin_name=Nom d'Utilisateur
|
||||
admin_password=Mot de Passe
|
||||
confirm_password=Confirmez le Mot de Passe
|
||||
admin_setting_desc=Vous n'avez pas besoin de créer un compte administrateur. L'utilisateur ayant l'ID = 1 aura automatiquement accès à l'administration.
|
||||
admin_title=Paramètres du compte administrateur
|
||||
admin_name=Nom d'utilisateur
|
||||
admin_password=Mot de passe
|
||||
confirm_password=Confirmez le mot de passe
|
||||
admin_email=E-mail de l'administrateur
|
||||
install_gogs=Installer Gogs
|
||||
test_git_failed=Tentative de commande "git" échouée : %v
|
||||
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 le répertoire racine invalide : %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
|
||||
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
|
||||
|
||||
[home]
|
||||
uname_holder=Nom d'Utilisateur ou E-mail
|
||||
password_holder=Mot de Passe
|
||||
password_holder=Mot de passe
|
||||
switch_dashboard_context=Basculer le Contexte du Tableau de Bord
|
||||
my_repos=Mes Référentiels
|
||||
collaborative_repos=Référentiels collaboratifs
|
||||
my_repos=Mes dépôts
|
||||
collaborative_repos=Dépôts collaboratifs
|
||||
my_orgs=Mes Organisations
|
||||
my_mirrors=Mes Miroirs
|
||||
view_home=Voir %s
|
||||
@@ -136,27 +139,27 @@ view_home=Voir %s
|
||||
issues.in_your_repos=Dans vos dépôts
|
||||
|
||||
[explore]
|
||||
repos=Référentiels
|
||||
repos=Dépôts
|
||||
|
||||
[auth]
|
||||
create_new_account=Créer un Nouveau Compte
|
||||
create_new_account=Créer un nouveau compte
|
||||
register_hepler_msg=Déjà enregistré ? Connectez-vous !
|
||||
social_register_hepler_msg=Possesseur d'un compte ? Associez-le !
|
||||
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.
|
||||
remember_me=Se souvenir de Moi
|
||||
remember_me=Se souvenir de moi
|
||||
forgot_password=Mot de Passe oublié
|
||||
forget_password=Mot de Passe oublié ?
|
||||
sign_up_now=Pas de compte ? Créer maintenant.
|
||||
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
|
||||
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 courriel (<b>%s</b>) n'a pas été confirmée. Si vous n'avez reçu aucun courriel de confirmation ou souhaitez renouveler l'envoi, appuyez sur le bouton ci-dessous.
|
||||
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é, code de confirmation invalide ou expiré.
|
||||
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.
|
||||
|
||||
@@ -173,11 +176,11 @@ no=Non
|
||||
modify=Modifier
|
||||
|
||||
[form]
|
||||
UserName=Nom d'Utilisateur
|
||||
UserName=Nom d'utilisateur
|
||||
RepoName=Nom du dépôt
|
||||
Email=Adresse E-mail
|
||||
Password=Mot de Passe
|
||||
Retype=Confirmez le Mot de Passe
|
||||
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
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken=Nom de dépôt déjà utilisé.
|
||||
org_name_been_taken=Nom d'organisation déjà pris.
|
||||
team_name_been_taken=Nom d'équipe déjà pris.
|
||||
email_been_used=Adresse e-mail déjà utilisée.
|
||||
illegal_team_name=Le nom de l'équipe contient des caractères interdits.
|
||||
username_password_incorrect=Nom d'utilisateur ou mot de passe incorrect.
|
||||
enterred_invalid_repo_name=Veuillez vérifier que le nom saisi du dépôt soit correct.
|
||||
enterred_invalid_owner_name=Veuillez vérifier que le nom du propriétaire saisi soit correct.
|
||||
@@ -225,13 +227,15 @@ target_branch_not_exist=La branche cible n'existe pas.
|
||||
|
||||
[user]
|
||||
change_avatar=Changez d'avatar via gravatar.com
|
||||
change_custom_avatar=Changer votre avatar dans les paramètres
|
||||
join_on=Adhéré le
|
||||
repositories=Référentiels
|
||||
change_custom_avatar=Changez votre avatar dans les paramètres
|
||||
join_on=Inscrit le
|
||||
repositories=Dépôts
|
||||
activity=Activités publiques
|
||||
followers=Abonnés
|
||||
starred=Votés
|
||||
following=Abonnements
|
||||
follow=Suivre
|
||||
unfollow=Ne plus suivre
|
||||
|
||||
form.name_reserved=Le nom '%s' est réservé.
|
||||
form.name_pattern_not_allowed=Motif '%s' interdit pour les noms d'utilisateur.
|
||||
@@ -246,10 +250,10 @@ orgs=Organisations
|
||||
delete=Supprimer le Compte
|
||||
uid=ID d'Utilisateur
|
||||
|
||||
public_profile=Profil Public
|
||||
public_profile=Profil public
|
||||
profile_desc=Votre adresse e-mail est publique et sera utilisée pour les notifications relatives au compte, ainsi que pour toute opération Web effectuée via le site.
|
||||
password_username_disabled=Les utilisateurs non-locaux n'ont pas le droit de modifier leur nom d'utilisateur.
|
||||
full_name=Nom Complet
|
||||
full_name=Nom complet
|
||||
website=Site Web
|
||||
location=Localisation
|
||||
update_profile=Valider les modifications
|
||||
@@ -282,7 +286,7 @@ primary=Principale
|
||||
primary_email=Définir comme principale
|
||||
delete_email=Supprimer
|
||||
email_deletion=Suppression de l'adresse mél
|
||||
email_deletion_desc=Supprimer cette adresse mél supprimera les informations associées à votre compte. Voulez-vous continuer ?
|
||||
email_deletion_desc=Supprimer cette adresse e-mail supprimera les informations associées à votre compte. Voulez-vous continuer ?
|
||||
email_deletion_success=L'adresse mél a été supprimée avec succès !
|
||||
add_new_email=Ajouter une nouvelle adresse courriel
|
||||
add_email=Ajouter un courriel
|
||||
@@ -307,7 +311,7 @@ add_on=Ajouté le
|
||||
last_used=Dernière utilisation le
|
||||
no_activity=Aucune activité récente
|
||||
key_state_desc=Cette clé a été utilisée durant les 7 derniers jours
|
||||
token_state_desc=Cette clé a été utilisée durant les 7 derniers jours
|
||||
token_state_desc=Ce jeton a été utilisé durant les 7 derniers jours
|
||||
|
||||
manage_social=Gérer les réseaux sociaux associés
|
||||
social_desc=Ceci est la liste des comptes de réseaux sociaux associés. Supprimez ceux que vous ne reconnaissez pas.
|
||||
@@ -326,24 +330,24 @@ 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.
|
||||
|
||||
delete_account=Supprimer le Compte
|
||||
delete_prompt=Votre compte sera supprimé définitivement et cette opération est <strong>IRRÉVERSIBLE</strong> !
|
||||
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
|
||||
delete_account_title=Suppression de compte
|
||||
delete_account_desc=Ce compte sera supprimé définitivement. Voulez-vous continuer ?
|
||||
|
||||
[repo]
|
||||
owner=Propriétaire
|
||||
repo_name=Nom du Référentiel
|
||||
repo_name=Nom du Dépôt
|
||||
repo_name_helper=Idéalement, le nom d'un dépot devrait être court, mémorable et <strong>unique</strong>.
|
||||
visibility=Visibilité
|
||||
visiblity_helper=Ce dépôt est <span class="ui red text"> privé</span>
|
||||
visiblity_helper_forced=L'administrateur du site a forcé tous les nouveaux dépôts à être <span class="ui red text">privés</span>
|
||||
visiblity_fork_helper=(Les changement de cette valeur affecteront tous les embranchements)
|
||||
visiblity_fork_helper=(Les changement de cette valeur affecteront tous les forks)
|
||||
clone_helper=Besoin d'aide pour dupliquer ? Visitez <a target="_blank" href="%s">l'aide</a> !
|
||||
fork_repo=Scinder le dépôt
|
||||
fork_from=Scission de
|
||||
fork_visiblity_helper=Un dépôt scindé ne peut pas changer sa visiblité
|
||||
fork_repo=Créer un fork du dépôt
|
||||
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
|
||||
@@ -359,7 +363,7 @@ mirror_address=Adresse du miroir
|
||||
mirror_address_desc=Veuillez inclure les informations d'identification nécessaires dans l'adresse.
|
||||
watchers=Observateurs
|
||||
stargazers=Stargazers
|
||||
forks=Embranchements
|
||||
forks=Forks
|
||||
|
||||
form.reach_limit_of_creation=Le propriétaire a atteint le nombre maximal de %d dépôts créés.
|
||||
form.name_reserved=Le nom de dépôt '%s' est réservé.
|
||||
@@ -377,7 +381,7 @@ migrate.failed=Echec de migration: %v
|
||||
|
||||
mirror_from=miroir de
|
||||
forked_from=scindé depuis
|
||||
fork_from_self=Vous nous ne pouvez pas scinder un dépôt que vous possédez déja !
|
||||
fork_from_self=Vous ne pouvez pas forker un dépôt que vous possédez déja !
|
||||
copy_link=Copier
|
||||
copy_link_success=Copié!
|
||||
copy_link_error=Appuyez sur ⌘-C ou Ctrl-C pour copier
|
||||
@@ -386,14 +390,14 @@ unwatch=Ne plus suivre
|
||||
watch=Suivre
|
||||
unstar=Retirer le vote
|
||||
star=Voter
|
||||
fork=Embranchement
|
||||
fork=Fork
|
||||
|
||||
no_desc=Aucune description
|
||||
quick_guide=Introduction rapide
|
||||
clone_this_repo=Cloner ce dépôt
|
||||
create_new_repo_command=Créer un nouveau dépôt en ligne de commande
|
||||
push_exist_repo=Soumettre un référentiel existant via la ligne de commande
|
||||
repo_is_empty=Ce référentiel est vide, veuillez revenir plus tard !
|
||||
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
|
||||
branch=Branche
|
||||
@@ -405,7 +409,7 @@ issues=Problèmes
|
||||
pulls=Pull Requests
|
||||
labels=Etiquettes
|
||||
milestones=Étapes
|
||||
commits=Commissions
|
||||
commits=Commits
|
||||
releases=Publications
|
||||
file_raw=Raw
|
||||
file_history=Historique
|
||||
@@ -455,24 +459,24 @@ issues.filter_sort.latest=Plus récent
|
||||
issues.filter_sort.oldest=Plus ancien/ne
|
||||
issues.filter_sort.recentupdate=Mis à jour récemment
|
||||
issues.filter_sort.leastupdate=Moins récemment mis à jour
|
||||
issues.filter_sort.mostcomment=Plus commentés
|
||||
issues.filter_sort.leastcomment=Moins commenté
|
||||
issues.opened_by=Ouvrir %[1]s by <a href="%[2]s">%[3]s</a>
|
||||
issues.filter_sort.mostcomment=Les plus commentés
|
||||
issues.filter_sort.leastcomment=Les moins commentés
|
||||
issues.opened_by=Créé %[1]s par <a href="%[2]s">%[3]s</a>
|
||||
issues.opened_by_fake=ouvert %[1]s par %[2]s
|
||||
issues.previous=Page Précédente
|
||||
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=`commenté à <a id="%[1]s" href="#%[1]s"> %[2]s</a>`
|
||||
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.reopened_at='réouvert à <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.admin=Admin
|
||||
@@ -492,6 +496,7 @@ issues.label_modify=Modification du Label
|
||||
issues.label_deletion=Suppression du Label
|
||||
issues.label_deletion_desc=Cette opération supprimera également toutes les informations relatives aux problèmes. Voulez-vous continuer ?
|
||||
issues.label_deletion_success=Label supprimé avec succès !
|
||||
issues.num_participants=%d Participants
|
||||
|
||||
pulls.new=Nouvelle Pull Request
|
||||
pulls.compare_changes=Comparer les changements
|
||||
@@ -511,7 +516,7 @@ pulls.tab_files=Fichiers modifiés
|
||||
pulls.reopen_to_merge=Veuillez rouvrir cette demande de Pull Request pour effectuer l'opération de fusion.
|
||||
pulls.merged=Fusionné
|
||||
pulls.has_merged=Cette Pull Request a été fusionnée avec succès !
|
||||
pulls.data_broken=Les données de cette demande de rattachement ont été compromise en raison de la suppression d'informations sur l'embranchement.
|
||||
pulls.data_broken=Les données de cette pull request ont été compromises en raison de la suppression d'informations sur le fork.
|
||||
pulls.is_checking=La recherche de conflits est toujours en cours, veuillez rafraichir la page dans quelques instants.
|
||||
pulls.can_auto_merge_desc=Cette pull request peut être fusionnée automatiquement.
|
||||
pulls.cannot_auto_merge_desc=Cette pull request ne peut être fusionnée automatiquement à cause de conflits.
|
||||
@@ -552,7 +557,7 @@ wiki.filter_page=Filtrer la page
|
||||
wiki.new_page=Créer une nouvelle page
|
||||
wiki.default_commit_message=Écrire une note concernant cette mise à jour (optionnel).
|
||||
wiki.save_page=Enregistrer la page
|
||||
wiki.last_commit_info=%s modifier cette page %s
|
||||
wiki.last_commit_info=%s a édité cette page %s
|
||||
wiki.edit_page_button=Modifier
|
||||
wiki.new_page_button=Nouvelle Page
|
||||
wiki.page_already_exists=Une page de wiki avec le même nom existe déjà.
|
||||
@@ -568,7 +573,7 @@ settings.basic_settings=Paramètres de base
|
||||
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.advanced_settings=Paramètres avancés
|
||||
settings.wiki_desc=Activer le wiki pour permettre l'écriture de documents
|
||||
settings.use_external_wiki=Utiliser un wiki externe
|
||||
settings.external_wiki_url=URL Wiki externe
|
||||
@@ -579,19 +584,24 @@ settings.tracker_url_format=Format d'URL du bug tracker
|
||||
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
|
||||
settings.transfer=Transférer les propriétés
|
||||
settings.transfer_desc=Transfèrer ce dépôt à un autre utilisateur ou une organisation dont vous possédez des droits d'administrateur.
|
||||
settings.new_owner_has_same_repo=Le nouveau propriétaire a déjà un dépôt nommé ainsi.
|
||||
settings.delete=Supprimer ce Référentiel
|
||||
settings.delete_desc=Attention, action irréversible. Soyez sûr de vous.
|
||||
settings.convert=Convertir en dépôt ordinaire
|
||||
settings.convert_desc=Vous pouvez convertir ce miroir en dépôt ordinaire. Cela ne peut pas être inversée.
|
||||
settings.convert_notices_1=- This operation will convert this repository mirror into a regular repository and cannot be undone.
|
||||
settings.convert_confirm=Confirmer la conversion
|
||||
settings.convert_succeed=Le dépôt a été converti avec succès en dépôt ordinaire.
|
||||
settings.transfer=Changer de propriétaire
|
||||
settings.transfer_desc=Transférer ce dépôt à un autre utilisateur ou une organisation dont vous possédez des droits d'administrateur.
|
||||
settings.transfer_notices_1=-Vous perdrez l'accès si le nouveau propriétaire est un utilisateur individuel.
|
||||
settings.transfer_notices_2=-Vous préserverez l'accès si le nouveau propriétaire est une organisation et si vous y appartenez.
|
||||
settings.transfer_notices_2=- Vous conserverez l'accès si le nouveau propriétaire est une organisation et que vous y appartenez.
|
||||
settings.transfer_form_title=Veuillez recopier le texte suivant afin de confirmer votre opération :
|
||||
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, problèmes, commentaires et accès des collaborateurs.
|
||||
settings.delete_notices_fork_1=-Si ce dépôt est public, tous les embranchements vont devenir indépendants après la suppression.
|
||||
settings.delete_notices_fork_2=-Si ce dépôt est privé, tous les embranchements seront supprimés en même temps.
|
||||
settings.delete_notices_fork_3=-Si vous souhaitez conserver tous les embranchements après suppression, veuillez tout d'abord modifier la visibilité de ce dépôt en public.
|
||||
settings.delete_notices_2=- Cette opération supprimera définitivement le dépôt, y compris les données Git, les issues, les commentaires et les accès des collaborateurs.
|
||||
settings.delete_notices_fork_1=- Si ce dépôt est public, tous les forks vont devenir indépendant après sa suppression.
|
||||
settings.delete_notices_fork_2=-Si ce dépôt est privé, tous les forks seront supprimés en même temps.
|
||||
settings.delete_notices_fork_3=-Si vous souhaitez conserver tous les forks après suppression, veuillez tout d'abord modifier la visibilité de ce dépôt en public.
|
||||
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
|
||||
@@ -602,13 +612,14 @@ settings.add_collaborator=Ajouter un collaborateur
|
||||
settings.add_collaborator_success=Nouveau collaborateur ajouté.
|
||||
settings.remove_collaborator_success=Collaborateur supprimé.
|
||||
settings.search_user_placeholder=Rechercher un utilisateur...
|
||||
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member=Cet utilisateur ne peut pas être ajouté en tant que collaborateur car il fait partie d'une organisation.
|
||||
settings.add_webhook=Ajouter un Webhook
|
||||
settings.hooks_desc=Les Webhooks sont des déclencheurs de POST HTTP . Lorsque qu'un événement se produit dans Gogs, une notification sera envoyée vers l'hôte cible préalablement spécifié. Apprenez-en davantage dans le <a target="_blank" href="%s">Guide des Webhooks</a>.
|
||||
settings.webhook_deletion=Supprimer le Webhook
|
||||
settings.webhook_deletion_desc=Supprimer ce webhook va supprimer ses informations et l'historique de livraison. Voulez-vous continuer ?
|
||||
settings.webhook_deletion_success=Le webhook a été supprimé avec succès !
|
||||
settings.webhook.test_delivery=Tester la publication
|
||||
settings.webhook.test_delivery=Tester la version
|
||||
settings.webhook.test_delivery_desc=Envoyer un faux push pour tester la configuration des webhooks
|
||||
settings.webhook.test_delivery_success=Le webhook de test a été ajouté à la file d'attente de livraison. L'affichage dans l'historique de livraison peut prendre quelques secondes.
|
||||
settings.webhook.request=Requête
|
||||
@@ -666,6 +677,8 @@ diff.parent=Parent
|
||||
diff.commit=commit
|
||||
diff.data_not_available=Données Diff indisponibles.
|
||||
diff.show_diff_stats=Afficher les stats Diff
|
||||
diff.show_split_view=Vue séparée
|
||||
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
|
||||
@@ -677,7 +690,7 @@ release.prerelease=Pré-publication
|
||||
release.stable=Stable
|
||||
release.edit=Éditer
|
||||
release.ahead=<strong>%d</strong> commits jusqu'à %s depuis cette publication
|
||||
release.source_code=Code Source
|
||||
release.source_code=Code source
|
||||
release.new_subheader=Publier une version pour itérer sur le produit.
|
||||
release.edit_subheader=Un changelog détaillé peut aider les utilisateurs à comprendre ce qui a été amélioré.
|
||||
release.tag_name=Nom du tag
|
||||
@@ -693,12 +706,12 @@ release.prerelease_helper=Nous soulignerons que cette version est considérée c
|
||||
release.cancel=Annuler
|
||||
release.publish=Publier
|
||||
release.save_draft=Sauvegarder le Brouillon
|
||||
release.edit_release=Éditer la publication
|
||||
release.edit_release=Modifier la version
|
||||
release.delete_release=Supprimer Cette Version
|
||||
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 publication avec ce nom de tag existe déjà.
|
||||
release.tag_name_already_exist=Une version avec ce nom de tag existe déjà.
|
||||
release.downloads=Téléchargements
|
||||
|
||||
[org]
|
||||
@@ -711,7 +724,7 @@ people=Contacts
|
||||
invite_someone=Inviter quelqu'un
|
||||
teams=Équipes
|
||||
lower_members=Membres
|
||||
lower_repositories=Référentiels
|
||||
lower_repositories=dépôts
|
||||
create_new_team=Créer une Nouvelle Équipe
|
||||
org_desc=Description
|
||||
team_name=Nom d'Équipe
|
||||
@@ -738,7 +751,7 @@ settings.delete_prompt=Cela supprimera cette organisation définitivement. Cette
|
||||
settings.confirm_delete_account=Confirmez la suppression
|
||||
settings.delete_org_title=Suppression d'organisation
|
||||
settings.delete_org_desc=Cette organisation sera définitivement supprimée. Continuer ?
|
||||
settings.hooks_desc=Ajoute des Webhooks qui seront activés pour <strong>tous les Référentiels</strong> de cette organisation.
|
||||
settings.hooks_desc=Ajoute des vebhooks qui seront activés pour <strong>tous les dépôts</strong> de cette organisation.
|
||||
|
||||
members.membership_visibility=Visibilité des membres:
|
||||
members.public=Public
|
||||
@@ -756,14 +769,14 @@ members.invite_now=Envoyer une invitation
|
||||
teams.join=Rejoindre
|
||||
teams.leave=Quitter
|
||||
teams.read_access=Accès en Lecture
|
||||
teams.read_access_helper=Cette équipe aura la possibilité de voir et dupliquer ses Référentiels.
|
||||
teams.read_access_helper=Cette équipe aura la possibilité de voir et cloner ses dépôts.
|
||||
teams.write_access=Accès en Écriture
|
||||
teams.write_access_helper=Cette équipe possèdera aussi bien des droits de lecture que d'écriture sur ses Référentiels.
|
||||
teams.write_access_helper=Cette équipe possèdera aussi bien des droits de lecture que d'écriture sur ses dépôts.
|
||||
teams.admin_access=Accès Administrateur
|
||||
teams.admin_access_helper=Cette équipe possèdera des droits de lecture, d'écriture, ainsi que le pouvoir d'ajouter des collaborateurs.
|
||||
teams.no_desc=Aucune description
|
||||
teams.settings=Paramètres
|
||||
teams.owners_permission_desc=Les propriétaires possèdent <strong>les droits d'administrateur</strong> et disposent d'un accès complet à <strong>tous les Référentiels</strong> de l'organisation.
|
||||
teams.owners_permission_desc=Les propriétaires possèdent <strong>les droits d'administrateur</strong> et disposent d'un accès complet à <strong>tous les dépôts</strong> de l'organisation.
|
||||
teams.members=Membres de L'Équipe
|
||||
teams.update_settings=Valider
|
||||
teams.delete_team=Supprimer cette Équipe
|
||||
@@ -771,10 +784,10 @@ teams.add_team_member=Ajouter un Membre
|
||||
teams.delete_team_title=Suppression de l'équipe
|
||||
teams.delete_team_desc=Cette équipe sera supprimée. Les membres pourraient perdre leurs accès à certains dépôts.
|
||||
teams.delete_team_success=Équipe supprimée avec succès.
|
||||
teams.read_permission_desc=Cette équipe permet l'accès en <strong>lecture</strong> : les membres peuvent voir et dupliquer ses Référentiels.
|
||||
teams.write_permission_desc=Cette équipe permet l'accès en <strong>écriture</strong> : les membres peuvent participer à ses Référentiels.
|
||||
teams.admin_permission_desc=Cette équipe permet l'accès en <strong>administrateur</strong> : les membres peuvent voir, participer et ajouter des collaborateurs à ses Référentiels.
|
||||
teams.repositories=Référentiels de l'Équipe
|
||||
teams.read_permission_desc=Cette équipe permet l'accès en <strong>lecture</strong> : les membres peuvent voir et dupliquer ses dépôts.
|
||||
teams.write_permission_desc=Cette équipe permet l'accès en <strong>écriture</strong> : les membres peuvent participer à ses dépôts.
|
||||
teams.admin_permission_desc=Cette équipe permet l'accès en <strong>administrateur</strong> : les membres peuvent voir, participer et ajouter des collaborateurs à ses dépôts.
|
||||
teams.repositories=Dépôts de l'Équipe
|
||||
teams.search_repo_placeholder=Rechercher dans le dépôt...
|
||||
teams.add_team_repository=Ajouter un Dépôt à l'Équipe
|
||||
teams.remove_repo=Supprimer
|
||||
@@ -784,19 +797,19 @@ teams.add_nonexistent_repo=Dépôt inexistant, veuillez d'abord le créer.
|
||||
dashboard=Tableau de bord
|
||||
users=Utilisateurs
|
||||
organizations=Organisations
|
||||
repositories=Référentiels
|
||||
repositories=Dépôts
|
||||
authentication=Authentifications
|
||||
config=Configuration
|
||||
notices=Notes Systèmes
|
||||
monitor=Supervision
|
||||
monitor=Surveillance
|
||||
first_page=Première
|
||||
last_page=Dernière
|
||||
total=Total : %d
|
||||
|
||||
dashboard.statistic=Statistiques
|
||||
dashboard.operations=Opérations
|
||||
dashboard.system_status=État du Moniteur Système
|
||||
dashboard.statistic_info=La base de données Gogs contient <b>%d</b> utilisateurs, <b>%d</b> organisations, <b>%d</b> clés publiques, <b>%d</b> Référentiels, <b>%d</b> suivis, <b>%d</b> votes, <b>%d</b> actions, <b>%d</b> accès, <b>%d</b> problèmes, <b>%d</b> commentaires, <b>%d</b> comptes de réseaux sociaux, <b>%d</b> abonnements, <b>%d</b> miroirs, <b>%d</b> publications, <b>%d</b> connexions d'origine, <b>%d</b> webhooks, <b>%d</b> milestones, <b>%d</b> labels, <b>%d</b> tâches hook, <b>%d</b> équipes, <b>%d</b> tâches de mise à jour, <b>%d</b> fichiers.
|
||||
dashboard.system_status=État du système
|
||||
dashboard.statistic_info=La base de données Gogs contient <b>%d</b> utilisateurs, <b>%d</b> organisations, <b>%d</b> clés publiques, <b>%d</b> dépôts, <b>%d</b> surveillances de dépôts, <b>%d</b> votes, <b>%d</b> actions, <b>%d</b> accès, <b>%d</b> problèmes, <b>%d</b> commentaires, <b>%d</b> comptes de réseaux sociaux, <b>%d</b> abonnements, <b>%d</b> miroirs, <b>%d</b> versions, <b>%d</b> connexions d'origine, <b>%d</b> webhooks, <b>%d</b> versions, <b>%d</b> labels, <b>%d</b> tâches hook, <b>%d</b> équipes, <b>%d</b> tâches de mise à jour, <b>%d</b> fichiers.
|
||||
dashboard.operation_name=Nom de l'Opération
|
||||
dashboard.operation_switch=Basculer
|
||||
dashboard.operation_run=Exécuter
|
||||
@@ -804,16 +817,18 @@ dashboard.clean_unbind_oauth=Nettoyer les associations OAuthes
|
||||
dashboard.clean_unbind_oauth_success=Tous unbind OAuthes ont été supprimés avec succès.
|
||||
dashboard.delete_inactivate_accounts=Supprimer tous les comptes inactifs
|
||||
dashboard.delete_inactivate_accounts_success=Tous les comptes inactifs ont été supprimés avec succès.
|
||||
dashboard.delete_repo_archives=Supprimer toutes les archives de référentiels
|
||||
dashboard.delete_repo_archives_success=Toutes les archives des référentiels ont été supprimées avec succès.
|
||||
dashboard.delete_repo_archives=Supprimer toutes les archives des dépôts
|
||||
dashboard.delete_repo_archives_success=Toutes les archives des dépôts ont été supprimées avec succès.
|
||||
dashboard.delete_missing_repos=Supprimer tous les dépôts ayant perdu leurs fichiers Git
|
||||
dashboard.delete_missing_repos_success=Tous les dépôts ayant perdu leurs fichiers Git ont été supprimés avec succès.
|
||||
dashboard.git_gc_repos=Collecter les déchets des référentiels
|
||||
dashboard.git_gc_repos=Collecter les déchets des dépôts
|
||||
dashboard.git_gc_repos_success=Tous les dépôts ont effectué la collecte avec succès.
|
||||
dashboard.resync_all_sshkeys=Ré-écrire le fichier '.ssh/authorized_keys' (attention : les clés hors-Gogs vont être perdues)
|
||||
dashboard.resync_all_sshkeys_success=Toutes les clés publiques ont été ré-écrites avec succès.
|
||||
dashboard.resync_all_update_hooks=Ré-écrire tous les hooks de mises à jour des dépôts (requis quand le chemin de la configuration personnalisé est modifié)
|
||||
dashboard.resync_all_update_hooks_success=Les mises à jour de hook des référentiels ont toutes été réécrites avec succès.
|
||||
dashboard.resync_all_update_hooks_success=Tous les hooks de mises à jour des dépôts ont été ré-écris avec succès.
|
||||
dashboard.reinit_missing_repos=Réinitialiser tous les dépôts qui ont perdu des fichiers Git
|
||||
dashboard.reinit_missing_repos_success=Tous les enregistrements de dépôts qui ont perdu des fichiers Git ont été réinitialisés avec succès.
|
||||
|
||||
dashboard.server_uptime=Durée de Marche Serveur
|
||||
dashboard.current_goroutine=Goroutines actuelles
|
||||
@@ -870,7 +885,7 @@ users.allow_import_local=Ce compte dispose des permissions nécessaire à l'impo
|
||||
users.update_profile=Mettre à jour le profil
|
||||
users.delete_account=Supprimer ce Compte
|
||||
users.still_own_repo=Ce compte possède toujours des dépôts. Vous devez d'abord les supprimer ou les transférer.
|
||||
users.still_has_org=Ce compte a toujours membres de l'organisation, vous avez à gauche ou supprimez tout d'abord.
|
||||
users.still_has_org=Ce compte est toujours membre d'une ou plusieurs organisations. Vous devez d'abord les supprimer ou en retirer ce compte.
|
||||
users.deletion_success=Le compte a été supprimé avec succès !
|
||||
|
||||
orgs.org_manage_panel=Gestion des Organisations
|
||||
@@ -907,6 +922,7 @@ auths.attribute_username_placeholder=Laisser vide pour utiliser la valeur du for
|
||||
auths.attribute_name=Attribut du prénom
|
||||
auths.attribute_surname=Attribut du nom de famille
|
||||
auths.attribute_mail=Attribut de l'e-mail
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
auths.filter=Filtre utilisateur
|
||||
auths.admin_filter=Filtre administrateur
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -931,16 +947,16 @@ auths.delete_auth_desc=Cette authentification va être supprimée. voulez-vous c
|
||||
auths.deletion_success=L'authentification a été supprimée avec succès !
|
||||
|
||||
config.server_config=Configuration du Serveur
|
||||
config.app_name=Nom de l'Application
|
||||
config.app_ver=Version de l'Application
|
||||
config.app_url=URL de l'Application
|
||||
config.app_name=Nom de l'application
|
||||
config.app_ver=Version de l'application
|
||||
config.app_url=URL de l'application
|
||||
config.domain=Domaine
|
||||
config.offline_mode=Mode hors-ligne
|
||||
config.disable_router_log=Désactiver la Journalisation du Routeur
|
||||
config.run_user=Entrer un Utilisateur
|
||||
config.run_mode=Mode d'Éxécution
|
||||
config.repo_root_path=Emplacement des Dépôts
|
||||
config.static_file_root_path=Emplacement Racine du Fichier Statique
|
||||
config.static_file_root_path=Chemin statique des fichiers racines
|
||||
config.log_file_root_path=Emplacement Racine du Fichier Journal
|
||||
config.script_type=Type de Script
|
||||
config.reverse_auth_user=Annuler l'Authentification de l'Utilisateur
|
||||
@@ -955,10 +971,9 @@ 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 courriel
|
||||
config.disable_register=Désactiver l'Enregistrement
|
||||
config.disable_register=Désactiver les inscriptions
|
||||
config.show_registration_button=Afficher le bouton d'enregistrement
|
||||
config.require_sign_in_view=Connexion Obligatoire pour Visualiser
|
||||
config.enable_cache_avatar=Activer le Cache d'Avatar
|
||||
config.require_sign_in_view=Connexion obligatoire pour visualiser
|
||||
config.mail_notify=Mailer les Notifications
|
||||
config.disable_key_size_check=Désactiver la vérification de la taille de clé minimale
|
||||
config.enable_captcha=Activez le Captcha
|
||||
@@ -980,20 +995,20 @@ 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=Configurer le Fournisseur
|
||||
config.cookie_name=Nom du Cookie
|
||||
config.enable_set_cookie=Activer les Cookies
|
||||
config.session_config=Configuration de session
|
||||
config.session_provider=Fournisseur de session
|
||||
config.provider_config=Configuration du fournisseur
|
||||
config.cookie_name=Nom du cookie
|
||||
config.enable_set_cookie=Activer les cookies
|
||||
config.gc_interval_time=Intervals GC
|
||||
config.session_life_time=Durée de Session
|
||||
config.session_life_time=Durée des sessions
|
||||
config.https_only=HTTPS uniquement
|
||||
config.cookie_life_time=Expiration du Cookie
|
||||
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.log_config=Configuration du Journal
|
||||
config.log_mode=Mode du Journal
|
||||
config.log_mode=Mode du journal
|
||||
|
||||
monitor.cron=Tâches Cron
|
||||
monitor.name=Nom
|
||||
@@ -1001,7 +1016,7 @@ monitor.schedule=Planification
|
||||
monitor.next=Suivant
|
||||
monitor.previous=Précédent
|
||||
monitor.execute_times=Nombre d'Éxécutions
|
||||
monitor.process=Processus en cours d'Éxécution
|
||||
monitor.process=Processus en cours d'éxécution
|
||||
monitor.desc=Description
|
||||
monitor.start=Heure de Démarrage
|
||||
monitor.execute_time=Heure d'Éxécution
|
||||
@@ -1021,15 +1036,17 @@ notices.op=Opération
|
||||
notices.delete_success=Notifications système supprimées avec succès.
|
||||
|
||||
[action]
|
||||
create_repo=a crée le dépôt <a href="%s">%s</a>
|
||||
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> chez <a href="%[1]s">%[4]s</a>
|
||||
commit_repo=a soumis à <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=`closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`pull request créée le <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`a commenté le problème <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`pull request fusionné le <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
transfer_repo=a transféré le dépôt <code>%s</code> à <a href="%s">%s</a>
|
||||
push_tag=a soumis le tag <a href="%s/src/%s">%[2]s</a> à <a href="%[1]s">%[3]s</a>
|
||||
push_tag=a soumis le tag <a href="%s/src/%s">%[2]s</a> sur <a href="%[1]s">%[3]s</a>
|
||||
compare_commits=Comparer ces %d commits
|
||||
|
||||
[tool]
|
||||
|
||||
@@ -28,18 +28,18 @@ organization=Organizzazione
|
||||
mirror=Mirror
|
||||
new_repo=Nuovo Repository
|
||||
new_migrate=Nuova Migrazione
|
||||
new_mirror=New Mirror
|
||||
new_mirror=Nuovo Mirror
|
||||
new_fork=Nuovo Fork Repository
|
||||
new_org=Nuova organizzazione
|
||||
manage_org=Gestisci le organizzazioni
|
||||
admin_panel=Pannello di amministrazione
|
||||
account_settings=Impostazioni dell'account
|
||||
settings=Impostazioni
|
||||
your_profile=Profilo
|
||||
your_profile=Il tuo profilo
|
||||
your_settings=Impostazioni
|
||||
|
||||
news_feed=Notizie
|
||||
pull_requests=Pull Requests
|
||||
activities=Activities
|
||||
pull_requests=Pull Request
|
||||
issues=Problemi
|
||||
|
||||
cancel=Annulla
|
||||
@@ -65,7 +65,7 @@ db_name=Nome del database
|
||||
db_helper=Utilizza il motore INNODB con codifica utf8_general_ci per MySQL.
|
||||
ssl_mode=Modalità SSL
|
||||
path=Percorso
|
||||
sqlite_helper=Il percorso file del database SQLite3 o TiDB.
|
||||
sqlite_helper=The file path of SQLite3 or TiDB database. <br>Please use absolute path when you start as service.
|
||||
err_empty_db_path=Il percorso file del database SQLite3 o TiDB non può essere vuoto.
|
||||
err_invalid_tidb_name=Il nome del database TiDB non ammette caratteri "." e "-".
|
||||
no_admin_and_disable_registration=Non puoi disabilitare la registrazione senza aver creato un amministratore.
|
||||
@@ -86,6 +86,8 @@ http_port=Porta HTTP
|
||||
http_port_helper=Porta di ascolto dell'applicazione.
|
||||
app_url=URL Applicazione
|
||||
app_url_helper=Questo influisce sugli URL per il clonaggio via HTTP/HTTPS e da qualche parte nella posta elettronica.
|
||||
log_root_path=Log Path
|
||||
log_root_path_helper=Directory to write log files to.
|
||||
|
||||
optional_title=Impostazioni Facoltative
|
||||
email_title=Impostazioni E-mail
|
||||
@@ -122,6 +124,7 @@ run_user_not_match=Run user non è l'utente corrente: %s -> %s
|
||||
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.
|
||||
invalid_log_root_path=Log root path is invalid: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Nome Utente o E-mail
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken=Il nome del Repository è già utilizzato.
|
||||
org_name_been_taken=Il nome dell'Organizzazione è già utlizzato.
|
||||
team_name_been_taken=Il nome del Team è già utilizzato.
|
||||
email_been_used=L'indirizzo E-mail è già utilizzato.
|
||||
illegal_team_name=Il nome del Team contiene caratteri non validi.
|
||||
username_password_incorrect=Nome utente o password incorretti.
|
||||
enterred_invalid_repo_name=Si prega di assicurarsi che il nome del repository inserito sia corretto.
|
||||
enterred_invalid_owner_name=Si prega di assicurarsi che il nome del proprietario inserito sia corretto.
|
||||
@@ -232,6 +234,8 @@ activity=Attività pubblica
|
||||
followers=Seguaci
|
||||
starred=Votate
|
||||
following=Seguiti
|
||||
follow=Segui
|
||||
unfollow=Non seguire più
|
||||
|
||||
form.name_reserved=L'username '%s' è riservato.
|
||||
form.name_pattern_not_allowed=La struttura del nome utente '%s' non è consentita.
|
||||
@@ -248,7 +252,7 @@ uid=Uid
|
||||
|
||||
public_profile=Profilo pubblico
|
||||
profile_desc=Il tuo indirizzo e-mail è pubblico e sarà usato per ogni notifica inerente al tuo account, e per qualsiasi operazione web effettuata attraverso il sito.
|
||||
password_username_disabled=Non-local type users are not allowed to change their username.
|
||||
password_username_disabled=Gli utenti non locali non possono cambiare il proprio nome utente.
|
||||
full_name=Nome Completo
|
||||
website=Sito web
|
||||
location=Posizione
|
||||
@@ -273,7 +277,7 @@ new_password=Nuova Password
|
||||
retype_new_password=Re-inserisci la password
|
||||
password_incorrect=La Password attuale non è corretta.
|
||||
change_password_success=La tua password è stata cambiata con successo. Ora puoi accedere usando la nuova password.
|
||||
password_change_disabled=Non-local type users are not allowed to change their password.
|
||||
password_change_disabled=Gli utenti non locali non possono cambiare la propria password.
|
||||
|
||||
emails=Indirizzi e-mail
|
||||
manage_emails=Gestisci indirizzi email
|
||||
@@ -301,7 +305,7 @@ key_content=Contenuto
|
||||
add_key_success=La nuova chiave SSH '%s' è stata aggiunta con successo!
|
||||
delete_key=Elimina
|
||||
ssh_key_deletion=Eliminazione chiave SSH
|
||||
ssh_key_deletion_desc=Delete this SSH key will remove all related accesses for your account. Do you want to continue?
|
||||
ssh_key_deletion_desc=Cancellare la chiave SSH rimuoverà tutti i relativi accessi per il tuo account. Vuoi continuare?
|
||||
ssh_key_deletion_success=La chiave SSH e' stata cancellata con successo!
|
||||
add_on=Aggiunto il
|
||||
last_used=Ultimo accesso il
|
||||
@@ -316,15 +320,15 @@ unbind_success=Account sociale disassociato.
|
||||
|
||||
manage_access_token=Gestisci i Token di Accesso Personale
|
||||
generate_new_token=Genera Nuovo Token
|
||||
tokens_desc=Tokens you have generated that can be used to access the Gogs APIs.
|
||||
tokens_desc=I Token che hai generato e che possono essere utilizzati per accedere alle API Gogs.
|
||||
new_token_desc=Da questo momento, ogni token avrà pieno accesso al tuo account.
|
||||
token_name=Nome Token
|
||||
generate_token=Genera Token
|
||||
generate_token_succees=Nuovo token di accesso generato con successo! Assicurarsi di copiare il nuovo token di accesso personale ora: non sarà possibile visualizzarlo nuovamente!
|
||||
delete_token=Elimina
|
||||
access_token_deletion=Eliminazione Token di accesso personale
|
||||
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.
|
||||
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.
|
||||
|
||||
delete_account=Elimina Account
|
||||
delete_prompt=L'operazione eliminerà permanentemente l'account e <strong>NON POTRÀ</strong> essere annullata!
|
||||
@@ -337,9 +341,9 @@ owner=Proprietario
|
||||
repo_name=Nome Repository
|
||||
repo_name_helper=I migliori nomi dei repository sono brevi, facili da memorizzare e <strong>univoci</strong>.
|
||||
visibility=Visibilità
|
||||
visiblity_helper=This repository is <span class="ui red text">Private</span>
|
||||
visiblity_helper_forced=Site admin has forced all new repositories to be <span class="ui red text">Private</span>
|
||||
visiblity_fork_helper=(Change of this value will affect all forks)
|
||||
visiblity_helper=Questo repository è <span class="ui red text"> privato</span>
|
||||
visiblity_helper_forced=L'amministratore del sito ha deciso che tutti i nuovi repository devono essere <span class="ui red text">privati</span>
|
||||
visiblity_fork_helper=(La modifica di questo valore avrà effetto su tutti i fork)
|
||||
clone_helper=Hai bisogno di aiuto per la clonazione? Visita <a target="_blank" href="%s">Aiuto</a>!
|
||||
fork_repo=Forka Repository
|
||||
fork_from=Forka da
|
||||
@@ -351,36 +355,36 @@ license=Licenza
|
||||
license_helper=Selezionare un file di licenza
|
||||
readme=Readme
|
||||
readme_helper=Seleziona un template per il readme
|
||||
auto_init=Initialize this repository with selected files and template
|
||||
auto_init=Inizializzare questo repository con i file e il modello selezionati
|
||||
create_repo=Crea Repository
|
||||
default_branch=Ramo (Branch) predefinito
|
||||
mirror_interval=Intervallo Mirror (in ore)
|
||||
mirror_address=Mirror Address
|
||||
mirror_address_desc=Please include necessary user credentials in the address.
|
||||
watchers=Watchers
|
||||
stargazers=Stargazers
|
||||
forks=Forks
|
||||
mirror_address=Indirizzo del mirror
|
||||
mirror_address_desc=Si prega di includere nell'indirizzo le credenziali utente necessarie.
|
||||
watchers=Osservatori
|
||||
stargazers=Fan
|
||||
forks=Fork
|
||||
|
||||
form.reach_limit_of_creation=The owner has reached maximum creation limit of %d repositories.
|
||||
form.reach_limit_of_creation=Il proprietario ha raggiunto il limite massimo di %d repository creati.
|
||||
form.name_reserved=Il nome repository %s è riservato.
|
||||
form.name_pattern_not_allowed=La struttura del nome del repository %s non è consentita.
|
||||
|
||||
need_auth=Richiesta di autorizzazione
|
||||
migrate_type=Tipo di migrazione
|
||||
migrate_type_helper=This repository will be a <span class="text blue">mirror</span>
|
||||
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=This can be a HTTP/HTTPS/GIT URL or local server path.
|
||||
migrate.permission_denied=You are not allowed to import local repositories.
|
||||
migrate.clone_address_desc=Può essere un URL HTTP/HTTPS/GIT o il percorso del server locale.
|
||||
migrate.permission_denied=Non è consentito importare repository locali.
|
||||
migrate.invalid_local_path=Percorso locale non valido, non esiste o non è una cartella.
|
||||
migrate.failed=Migration failed: %v
|
||||
migrate.failed=Migrazione non riuscita: %v
|
||||
|
||||
mirror_from=mirror from
|
||||
mirror_from=mirror da
|
||||
forked_from=forkato da
|
||||
fork_from_self=Non puoi forkare il tuo stesso repository!
|
||||
copy_link=Copia
|
||||
copy_link_success=Copiato!
|
||||
copy_link_error=Press ⌘-C or Ctrl-C to copy
|
||||
copy_link_error=Premere ⌘-C o Ctrl-C per copiare
|
||||
copied=OK copiato
|
||||
unwatch=Non seguire più
|
||||
watch=Segui
|
||||
@@ -393,12 +397,12 @@ quick_guide=Guida rapida
|
||||
clone_this_repo=Clona questo repository
|
||||
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=This repository is empty, please come back later!
|
||||
repo_is_empty=Questo repository è vuoto, si prega di tornare più tardi!
|
||||
|
||||
code=Code
|
||||
code=Codice
|
||||
branch=Ramo (Branch)
|
||||
tree=Albero (Tree)
|
||||
filter_branch_and_tag=Filter branch or tag
|
||||
filter_branch_and_tag=Filtra per branch o tag
|
||||
branches=Rami (Branch)
|
||||
tags=Tag
|
||||
issues=Problemi
|
||||
@@ -426,62 +430,62 @@ issues.new.labels=Etichette
|
||||
issues.new.no_label=Nessuna etichetta
|
||||
issues.new.clear_labels=Pulisci le etichette
|
||||
issues.new.milestone=Traguardo
|
||||
issues.new.no_milestone=No Milestone
|
||||
issues.new.clear_milestone=Clear milestone
|
||||
issues.new.open_milestone=Open Milestones
|
||||
issues.new.closed_milestone=Closed Milestones
|
||||
issues.new.no_milestone=Nessuna milestone
|
||||
issues.new.clear_milestone=Milestone pulita
|
||||
issues.new.open_milestone=Apri Milestone
|
||||
issues.new.closed_milestone=Milestone chiuse
|
||||
issues.new.assignee=Assegnatario
|
||||
issues.new.clear_assignee=Clear assignee
|
||||
issues.new.no_assignee=No assignee
|
||||
issues.create=Create Issue
|
||||
issues.new.clear_assignee=Cancella l'assegnatario
|
||||
issues.new.no_assignee=Nessun assegnatario
|
||||
issues.create=Crea Problema
|
||||
issues.new_label=Nuova etichetta
|
||||
issues.new_label_placeholder=Nome dell'etichetta...
|
||||
issues.create_label=Create Label
|
||||
issues.create_label=Crea Etichetta
|
||||
issues.open_tab=%d Aperti
|
||||
issues.close_tab=%d Chiusi
|
||||
issues.filter_label=Etichetta
|
||||
issues.filter_label_no_select=Nessuna etichetta selezionata
|
||||
issues.filter_milestone=Traguardo
|
||||
issues.filter_milestone_no_select=No selected milestone
|
||||
issues.filter_milestone_no_select=Nessuna Milestone selezionata
|
||||
issues.filter_assignee=Assegnatario
|
||||
issues.filter_assginee_no_select=No selected Assignee
|
||||
issues.filter_assginee_no_select=Nessun Assegnatario selezionato
|
||||
issues.filter_type=Tipo
|
||||
issues.filter_type.all_issues=Tutti i problemi
|
||||
issues.filter_type.assigned_to_you=Assegnati a te
|
||||
issues.filter_type.created_by_you=Creati da te
|
||||
issues.filter_type.mentioning_you=Che ti riguardano
|
||||
issues.filter_sort=Ordina
|
||||
issues.filter_sort.latest=Newest
|
||||
issues.filter_sort.oldest=Oldest
|
||||
issues.filter_sort.recentupdate=Recently updated
|
||||
issues.filter_sort.leastupdate=Least recently updated
|
||||
issues.filter_sort.mostcomment=Most commented
|
||||
issues.filter_sort.leastcomment=Least commented
|
||||
issues.opened_by=opened %[1]s by <a href="%[2]s">%[3]s</a>
|
||||
issues.opened_by_fake=opened %[1]s by %[2]s
|
||||
issues.filter_sort.latest=Più recenti
|
||||
issues.filter_sort.oldest=Più vecchi
|
||||
issues.filter_sort.recentupdate=Aggiornati di recente
|
||||
issues.filter_sort.leastupdate=Aggiornati tempo fa
|
||||
issues.filter_sort.mostcomment=I più commentati
|
||||
issues.filter_sort.leastcomment=I meno commentati
|
||||
issues.opened_by=aperto %[1]s da <a href="/%[2]s">%[3]s</a>
|
||||
issues.opened_by_fake=aperto %[1]s da %[2]s
|
||||
issues.previous=Pagina precedente
|
||||
issues.next=Pagina successiva
|
||||
issues.open_title=Open
|
||||
issues.closed_title=Closed
|
||||
issues.num_comments=%d comments
|
||||
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.no_content=There is no content yet.
|
||||
issues.close_issue=Chiudi
|
||||
issues.close_comment_issue=Comment and close
|
||||
issues.reopen_issue=Reopen
|
||||
issues.reopen_comment_issue=Comment and reopen
|
||||
issues.close_comment_issue=Commenta e chiudi
|
||||
issues.reopen_issue=Riapri
|
||||
issues.reopen_comment_issue=Commenta e riapri
|
||||
issues.create_comment=Commento
|
||||
issues.closed_at=`closed <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.reopened_at=`reopened <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.commit_ref_at=`referenced this issue from a commit <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.poster=Poster
|
||||
issues.poster=Autore
|
||||
issues.admin=Amministratore
|
||||
issues.owner=Proprietario
|
||||
issues.sign_up_for_free=Registrati gratuitamente
|
||||
issues.sign_in_require_desc=to join this conversation. Already have an account? <a href="%s">Sign in to comment</a>
|
||||
issues.edit=Edit
|
||||
issues.edit=Modifica
|
||||
issues.cancel=Cancel
|
||||
issues.save=Save
|
||||
issues.save=Salva
|
||||
issues.label_title=Nome etichetta
|
||||
issues.label_color=Colore etichetta
|
||||
issues.label_count=%d etichette
|
||||
@@ -492,34 +496,35 @@ issues.label_modify=Modifica Etichetta
|
||||
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 Participants
|
||||
|
||||
pulls.new=New Pull Request
|
||||
pulls.compare_changes=Compare Changes
|
||||
pulls.compare_changes_desc=Compare two branches and make a pull request for changes.
|
||||
pulls.new=Nuova Pull Request
|
||||
pulls.compare_changes=Confronta le modifiche
|
||||
pulls.compare_changes_desc=Confronta due branch e fai una pull request per le modifiche.
|
||||
pulls.compare_base=base
|
||||
pulls.compare_compare=compare
|
||||
pulls.compare_compare=confronta
|
||||
pulls.filter_branch=Filter branch
|
||||
pulls.no_results=No results found.
|
||||
pulls.no_results=Nessun risultato trovato.
|
||||
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.create=Crea Pull Request
|
||||
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
|
||||
pulls.tab_conversation=Conversation
|
||||
pulls.tab_conversation=Conversazione
|
||||
pulls.tab_commits=Commits
|
||||
pulls.tab_files=Files changed
|
||||
pulls.reopen_to_merge=Please reopen this pull request to perform merge operation.
|
||||
pulls.tab_files=File modificati
|
||||
pulls.reopen_to_merge=Riapri questa pull request per effettuare il merge.
|
||||
pulls.merged=Merged
|
||||
pulls.has_merged=This pull request has been merged successfully!
|
||||
pulls.data_broken=Data of this pull request has been broken due to deletion of fork information.
|
||||
pulls.is_checking=The conflict checking is still in progress, please refresh page in few moments.
|
||||
pulls.can_auto_merge_desc=This pull request can be merged automatically.
|
||||
pulls.cannot_auto_merge_desc=This pull request can't be merged automatically because there are conflicts.
|
||||
pulls.cannot_auto_merge_helper=Please merge manually in order to resolve the conflicts.
|
||||
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.`
|
||||
|
||||
milestones.new=New Milestone
|
||||
milestones.new=Nuova Milestone
|
||||
milestones.open_tab=%d Open
|
||||
milestones.close_tab=%d Closed
|
||||
milestones.closed=Closed %s
|
||||
@@ -527,37 +532,37 @@ milestones.no_due_date=No due date
|
||||
milestones.open=Open
|
||||
milestones.close=Close
|
||||
milestones.new_subheader=Create milestones to organize your issues.
|
||||
milestones.create=Create Milestone
|
||||
milestones.title=Title
|
||||
milestones.desc=Description
|
||||
milestones.due_date=Due Date (optional)
|
||||
milestones.create=Crea Milestone
|
||||
milestones.title=Titolo
|
||||
milestones.desc=Descrizione
|
||||
milestones.due_date=Data di scadenza (opzionale)
|
||||
milestones.clear=Clear
|
||||
milestones.invalid_due_date_format=Due date format is invalid, must be 'yyyy-mm-dd'.
|
||||
milestones.create_success=Milestone '%s' has been created successfully!
|
||||
milestones.edit=Edit Milestone
|
||||
milestones.edit_subheader=Use a better description for milestones so people won't be confused.
|
||||
milestones.cancel=Cancel
|
||||
milestones.modify=Modify Milestone
|
||||
milestones.edit_success=Changes of milestone '%s' has been saved successfully!
|
||||
milestones.deletion=Milestone Deletion
|
||||
milestones.deletion_desc=Deleting this milestone will remove its information in all related issues. Do you want to continue?
|
||||
milestones.deletion_success=Milestone has been deleted successfully!
|
||||
milestones.invalid_due_date_format=Il formato della data di scadenza non è valido, deve essere 'yyyy-mm-dd'.
|
||||
milestones.create_success=La Milestone '%s' è stata creata con successo!
|
||||
milestones.edit=Modifica Milestone
|
||||
milestones.edit_subheader=Scrivi una descrizione della Milestone, così la gente non si confonderà.
|
||||
milestones.cancel=Annulla
|
||||
milestones.modify=Modifica Milestone
|
||||
milestones.edit_success=Le modifiche alla milestone '%s' sono state salvate con successo!
|
||||
milestones.deletion=Cancellazione Milestone
|
||||
milestones.deletion_desc=L'eliminazione di questa Milestone rimuoverà le sue informazioni in tutti i problemi correlati. Si desidera continuare?
|
||||
milestones.deletion_success=La milestone è stata cancellata con successo!
|
||||
|
||||
wiki=Wiki
|
||||
wiki.welcome=Welcome to Wiki!
|
||||
wiki.welcome_desc=Wiki is the place where you would like to document your project together and make it better.
|
||||
wiki.create_first_page=Create the first page
|
||||
wiki.page=Page
|
||||
wiki.filter_page=Filter page
|
||||
wiki.new_page=Create New Page
|
||||
wiki.default_commit_message=Write a note about this update (optional).
|
||||
wiki.save_page=Save Page
|
||||
wiki.last_commit_info=%s edited this page %s
|
||||
wiki.edit_page_button=Edit
|
||||
wiki.new_page_button=New Page
|
||||
wiki.page_already_exists=Wiki page with same name already exists.
|
||||
wiki.pages=Pages
|
||||
wiki.last_updated=Last updated %s
|
||||
wiki.welcome=Benvenuto nel Wiki!
|
||||
wiki.welcome_desc=Wiki è il posto dove puoi documentare collaborativamente il tuo progetto così da renderlo migliore.
|
||||
wiki.create_first_page=Crea la prima pagina
|
||||
wiki.page=Pagina
|
||||
wiki.filter_page=Filtra pagina
|
||||
wiki.new_page=Crea nuova pagina
|
||||
wiki.default_commit_message=Scrivere una nota su questo aggiornamento (opzionale).
|
||||
wiki.save_page=Salva pagina
|
||||
wiki.last_commit_info=%s ha modificato questa pagina %s
|
||||
wiki.edit_page_button=Modifica
|
||||
wiki.new_page_button=Nuova pagina
|
||||
wiki.page_already_exists=Esiste già una pagina Wiki con questo stesso nome.
|
||||
wiki.pages=Pagine
|
||||
wiki.last_updated=Ultimo aggiornamento: %s
|
||||
|
||||
settings=Impostazioni
|
||||
settings.options=Opzioni
|
||||
@@ -567,32 +572,37 @@ settings.githooks=Git Hooks
|
||||
settings.basic_settings=Impostazioni di Base
|
||||
settings.site=Sito Ufficiale
|
||||
settings.update_settings=Aggiorna Impostazioni
|
||||
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.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.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.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=Enable builtin lightweight issue tracker
|
||||
settings.use_external_issue_tracker=Use external issue tracker
|
||||
settings.use_external_issue_tracker=Utilizza gestore di problemi esterno
|
||||
settings.tracker_url_format=External Issue Tracker URL Format
|
||||
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=Zona Pericolosa
|
||||
settings.new_owner_has_same_repo=Il nuovo proprietario ha già un repository con lo stesso nome. Per favore scegli un altro nome.
|
||||
settings.convert=Convert To Regular Repository
|
||||
settings.convert_desc=You can convert this mirror to a regular repository. This cannot be reversed.
|
||||
settings.convert_notices_1=- This operation will convert this repository mirror into a regular repository and cannot be undone.
|
||||
settings.convert_confirm=Confirm Conversion
|
||||
settings.convert_succeed=Repository has been converted to regular type successfully.
|
||||
settings.transfer=Trasferisci proprietà
|
||||
settings.transfer_desc=Trasferisci questa repository a un altro utente o a un'organizzazione nella quale hai diritti d'amministratore.
|
||||
settings.new_owner_has_same_repo=Il nuovo proprietario ha già un repository con lo stesso nome. Per favore scegli un altro nome.
|
||||
settings.delete=Elimina questo repository
|
||||
settings.delete_desc=Una volta che hai cancellato il repository, non puoi tornare indietro. Si prega di fare attenzione.
|
||||
settings.transfer_notices_1=- You will lose access if new owner is a individual user.
|
||||
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=Please enter following information to confirm your operation:
|
||||
settings.delete_notices_1=- This operation <strong>CANNOT</strong> be undone.
|
||||
settings.delete_notices_2=- This operation will permanently delete the everything of this repository, including Git data, issues, comments and accesses of collaborators.
|
||||
settings.delete_notices_fork_1=- If this repository is public, all forks will be became independent after deletion.
|
||||
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
|
||||
settings.transfer_form_title=Per favore inserisci le informazioni seguenti per confermare l'operazione:
|
||||
settings.delete=Elimina questo repository
|
||||
settings.delete_desc=Una volta che hai cancellato il repository, non puoi tornare indietro. Si prega di fare attenzione.
|
||||
settings.delete_notices_1=-Questa operazione <strong>NON PUÒ</strong> essere annullata.
|
||||
settings.delete_notices_2=-Questa operazione eliminerà definitivamente il tutto il contenuto del repository, inclusi i dati di Git, incidenti, commenti e accessi dei collaboratori.
|
||||
settings.delete_notices_fork_1=-Se questo repository è pubblico, tutti i fork diventeranno indipendenti dopo la sua cancellazione.
|
||||
settings.delete_notices_fork_2=-Se questo repository è privato, tutti fork verranno rimossi assieme ad esso.
|
||||
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
|
||||
settings.deletion_success=Repository has been deleted successfully!
|
||||
settings.deletion_success=Il repository è stato eliminato con successo!
|
||||
settings.update_settings_success=Le opzioni repository sono state aggiornate con successo.
|
||||
settings.transfer_owner=Nuovo Proprietario
|
||||
settings.make_transfer=Trasferisci
|
||||
@@ -601,16 +611,17 @@ settings.confirm_delete=Conferma eliminazione
|
||||
settings.add_collaborator=Aggiungi nuovo collaboratore
|
||||
settings.add_collaborator_success=Il nuovo collaboratore è stato aggiunto.
|
||||
settings.remove_collaborator_success=Il collaboratore è stato rimosso.
|
||||
settings.search_user_placeholder=Search user...
|
||||
settings.search_user_placeholder=Cerca utente...
|
||||
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member=L'utente è un membro dell'organizzazione che non può essere aggiunto come collaboratore.
|
||||
settings.add_webhook=Aggiungi Webhook
|
||||
settings.hooks_desc=I Webhooks sono molto simili a un basilare evento trigger HTTP POST. Ogni volta che qualcosa si verifica in Gogs, tratteremo la notifica all'host di destinazione specificato. Ulteriori informazioni in questa <a target="_blank" href="%s">Guida ai Webhooks</a>.
|
||||
settings.webhook_deletion=Delete Webhook
|
||||
settings.webhook_deletion=Elimina Webhook
|
||||
settings.webhook_deletion_desc=Delete this webhook will remove its information and all delivery history. Do you want to continue?
|
||||
settings.webhook_deletion_success=Webhook has been deleted successfully!
|
||||
settings.webhook.test_delivery=Test Delivery
|
||||
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
|
||||
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
|
||||
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may take few seconds before it shows up in the delivery history.
|
||||
settings.webhook.request=Request
|
||||
settings.webhook.response=Response
|
||||
settings.webhook.headers=Headers
|
||||
@@ -626,7 +637,7 @@ settings.payload_url=Payload URL
|
||||
settings.content_type=Content Type
|
||||
settings.secret=Secret
|
||||
settings.slack_username=Username
|
||||
settings.slack_icon_url=Icon URL
|
||||
settings.slack_icon_url=URL icona
|
||||
settings.slack_color=Color
|
||||
settings.event_desc=Quali eventi dovrebbero innescare questo webhook?
|
||||
settings.event_push_only=Solo l'evento <code>push</code>.
|
||||
@@ -650,8 +661,8 @@ settings.slack_domain=Dominio
|
||||
settings.slack_channel=Canale
|
||||
settings.deploy_keys=Dispiega Chiavi
|
||||
settings.add_deploy_key=Add Deploy Key
|
||||
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
|
||||
settings.no_deploy_keys=You haven't added any deploy key.
|
||||
settings.deploy_key_desc=Deploy keys have read-only access. They are not the same as personal account SSH keys.
|
||||
settings.no_deploy_keys=You haven't added any deploy keys.
|
||||
settings.title=Title
|
||||
settings.deploy_key_content=Content
|
||||
settings.key_been_used=Deploy key content has been used.
|
||||
@@ -666,6 +677,8 @@ diff.parent=parent
|
||||
diff.commit=commit
|
||||
diff.data_not_available=Diff Data non disponibile.
|
||||
diff.show_diff_stats=Mostra Diff Stats
|
||||
diff.show_split_view=Split View
|
||||
diff.show_unified_view=Unified View
|
||||
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
|
||||
@@ -699,7 +712,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=Un rilascio con questo tag esiste già.
|
||||
release.downloads=Downloads
|
||||
release.downloads=Download
|
||||
|
||||
[org]
|
||||
org_name_holder=Nome dell'Organizzazione
|
||||
@@ -750,7 +763,7 @@ members.owner=Proprietario
|
||||
members.member=Membro
|
||||
members.remove=Rimuovere
|
||||
members.leave=Abbandona
|
||||
members.invite_desc=Add a new member to %s:
|
||||
members.invite_desc=Aggiungi un nuovo membro a %s:
|
||||
members.invite_now=Invita ora
|
||||
|
||||
teams.join=Iscriviti
|
||||
@@ -791,7 +804,7 @@ notices=Avvisi di sistema
|
||||
monitor=Monitoraggio
|
||||
first_page=First
|
||||
last_page=Last
|
||||
total=Total: %d
|
||||
total=Totale: %d
|
||||
|
||||
dashboard.statistic=Statistiche
|
||||
dashboard.operations=Operazioni
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys=Riscrivi il file '.ssh/authorized_keys' (attenzione
|
||||
dashboard.resync_all_sshkeys_success=Tutte le chiavi pubbliche riscritte con successo.
|
||||
dashboard.resync_all_update_hooks=Riscrivere tutti gli update hook dei repository (necessario quando il percorso di configurazione personalizzata viene modificato)
|
||||
dashboard.resync_all_update_hooks_success=Tutti gli update hook dei repository riscritti con successo.
|
||||
dashboard.reinit_missing_repos=Reinitialize all repository records that lost Git files
|
||||
dashboard.reinit_missing_repos_success=All repository records that lost Git files have been reinitialized successfully.
|
||||
|
||||
dashboard.server_uptime=Tempo in Attività del Server
|
||||
dashboard.current_goroutine=Goroutine Correnti
|
||||
@@ -853,7 +868,7 @@ users.admin=Amministratore
|
||||
users.repos=Repo
|
||||
users.created=Creato
|
||||
users.send_register_notify=Send Registration Notification To User
|
||||
users.new_success=New account '%s' has been created successfully.
|
||||
users.new_success=Il nuovo account '%s' è stato creato correttamente.
|
||||
users.edit=Modifica
|
||||
users.auth_source=Authentication Source
|
||||
users.local=Locale
|
||||
@@ -866,12 +881,12 @@ users.max_repo_creation_desc=(Set -1 to use global default limit)
|
||||
users.is_activated=Questo account è attivato
|
||||
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=This account has permissions to import local repositories
|
||||
users.allow_import_local=Questo account dispone delle autorizzazioni per importare repository locali
|
||||
users.update_profile=Aggiornare Profilo Account
|
||||
users.delete_account=Elimina Questo Account
|
||||
users.still_own_repo=Questo account possiede ancora almeno un repository, devi prima cancellarli o trasferirli.
|
||||
users.still_has_org=Questo account appartiene ancora ad almeno un'organizzazione, è necessario prima abbandonarle o eliminale.
|
||||
users.deletion_success=Account has been deleted successfully!
|
||||
users.deletion_success=Account eliminato correttamente!
|
||||
|
||||
orgs.org_manage_panel=Pannello Gestione Organizzazioni
|
||||
orgs.name=Nome
|
||||
@@ -907,6 +922,7 @@ auths.attribute_username_placeholder=Leave empty to use sign-in form field value
|
||||
auths.attribute_name=Attributo Nome
|
||||
auths.attribute_surname=Attributo Cognome
|
||||
auths.attribute_mail=Attributo Email
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
auths.filter=User Filter
|
||||
auths.admin_filter=Admin Filter
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -916,7 +932,7 @@ auths.smtpport=Porta SMTP
|
||||
auths.allowed_domains=Allowed Domains
|
||||
auths.allowed_domains_helper=Leave it empty to not restrict any domains. Multiple domains should be separated by comma ','.
|
||||
auths.enable_tls=Abilitare Crittografia TLS
|
||||
auths.skip_tls_verify=Skip TLS Verify
|
||||
auths.skip_tls_verify=Salta verifica TLS
|
||||
auths.pam_service_name=Nome del Servizio PAM
|
||||
auths.enable_auto_register=Abilitare Registrazione Automatica
|
||||
auths.tips=Consigli
|
||||
@@ -958,10 +974,9 @@ config.register_email_confirm=Richiedono Conferma dell'Email
|
||||
config.disable_register=Disabilita Registrazione
|
||||
config.show_registration_button=Mostra Pulsane Registrazione
|
||||
config.require_sign_in_view=Richiesto Accesso per Vedere
|
||||
config.enable_cache_avatar=Abilitare Cache dell'Avatar
|
||||
config.mail_notify=Email di Notifica
|
||||
config.disable_key_size_check=Disable Minimum Key Size Check
|
||||
config.enable_captcha=Enable Captcha
|
||||
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
|
||||
@@ -1022,9 +1037,11 @@ notices.delete_success=System notices have been deleted successfully.
|
||||
|
||||
[action]
|
||||
create_repo=ha creato il repository <a href="%s">%s</a>
|
||||
rename_repo=renamed repository from <code>%[1]s</code> to <a href="%[2]s">%[3]s</a>
|
||||
rename_repo=repository rinominato da <code>%[1]s</code> a <a href="%[2]s">[3]s</a>
|
||||
commit_repo=ha pushato nel <a href="%[1]s/src/%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`ha aperto il problema <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue=`closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`creata pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`ha commentato il problema <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`merged pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
@@ -1056,6 +1073,6 @@ raw_minutes=minuti
|
||||
[dropzone]
|
||||
default_message=Drop files here or click to upload.
|
||||
invalid_input_type=You can't upload files of this type.
|
||||
file_too_big=File size({{filesize}} MB) exceeds maximum size({{maxFilesize}} MB).
|
||||
file_too_big=File size ({{filesize}} MB) exceeds maximum size ({{maxFilesize}} MB).
|
||||
remove_file=Remove file
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ organization=組織
|
||||
mirror=ミラー
|
||||
new_repo=新しいリポジトリ
|
||||
new_migrate=新しい移行
|
||||
new_mirror=New Mirror
|
||||
new_mirror=新しいミラー
|
||||
new_fork=新しいフォークのリポジトリ
|
||||
new_org=新しい組織
|
||||
manage_org=組織を管理
|
||||
@@ -38,7 +38,7 @@ settings=設定
|
||||
your_profile=あなたのプロファイル
|
||||
your_settings=あなたの設定
|
||||
|
||||
news_feed=ニュースのフィード
|
||||
activities=Activities
|
||||
pull_requests=プルリクエスト
|
||||
issues=課題
|
||||
|
||||
@@ -65,10 +65,10 @@ db_name=データベース名
|
||||
db_helper=Mysql INNODB エンジン utf8_general_ci の文字セットを使用してください。
|
||||
ssl_mode=SSL モード
|
||||
path=パス
|
||||
sqlite_helper=SQLite3 または TiDB のデータベースのファイル パス。
|
||||
sqlite_helper=The file path of SQLite3 or TiDB database. <br>Please use absolute path when you start as service.
|
||||
err_empty_db_path=SQLite3 または TiDB データベースのパスを空にすることはできません。
|
||||
err_invalid_tidb_name=TiDB データベース名は文字"."と"-"を許可しない。
|
||||
no_admin_and_disable_registration=You cannot disable registration without creating an admin account.
|
||||
no_admin_and_disable_registration=管理者アカウントを作成せずに登録を無効にすることはできません。
|
||||
err_empty_admin_password=管理者パスワードは空白にできません。
|
||||
|
||||
general_title=Gogs の全般設定
|
||||
@@ -86,6 +86,8 @@ http_port=HTTP ポート
|
||||
http_port_helper=アプリケーションが待ち受けするポート番号。
|
||||
app_url=アプリケーションの URL
|
||||
app_url_helper=この設定は、HTTP / HTTPSのクローンURLおよび、一部のメールボックスへのリンクに影響を与えます。
|
||||
log_root_path=Log Path
|
||||
log_root_path_helper=Directory to write log files to.
|
||||
|
||||
optional_title=オプション設定
|
||||
email_title=E-mailサービス設定
|
||||
@@ -122,6 +124,7 @@ run_user_not_match=実行ユーザーは、現在のユーザーではない: %s
|
||||
save_config_failed=構成の保存に失敗した: %v
|
||||
invalid_admin_setting=管理者アカウントの設定が無効です: %v
|
||||
install_success=ようこそ!我々はあなたが Gogs を選んでくれて嬉しいです!楽しみましょう!
|
||||
invalid_log_root_path=Log root path is invalid: %v
|
||||
|
||||
[home]
|
||||
uname_holder=ユーザー名またはEメール
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken=リポジトリ名は既に使用されています。
|
||||
org_name_been_taken=組織名は既に使用されています。
|
||||
team_name_been_taken=チーム名は既に使用されています。
|
||||
email_been_used=電子メール アドレスは既に使用されています。
|
||||
illegal_team_name=チーム名に無効な文字が含まれています。
|
||||
username_password_incorrect=ユーザー名またはパスワードが正しくありません。
|
||||
enterred_invalid_repo_name=入力したリポジトリの名前が正しいかどうかを確認してください。
|
||||
enterred_invalid_owner_name=入力された所有者名が正しいかどうかを確認してください。
|
||||
@@ -232,6 +234,8 @@ activity=パブリック・アクティビティ
|
||||
followers=フォロワー
|
||||
starred=スター
|
||||
following=フォロー
|
||||
follow=フォロー
|
||||
unfollow=フォロー解除
|
||||
|
||||
form.name_reserved=ユーザー名 '%s' は予約されています。
|
||||
form.name_pattern_not_allowed=ユーザ名のパターン '%s' は許可されていません。
|
||||
@@ -248,7 +252,7 @@ uid=Uid
|
||||
|
||||
public_profile=パブリック プロフィール
|
||||
profile_desc=あなたのメールアドレスは公開され、任意のアカウント関連の通知に使用されます。また、Webベースの操作はサイトを介して行います。
|
||||
password_username_disabled=Non-local type users are not allowed to change their username.
|
||||
password_username_disabled=ローカルユーザ以外はユーザ名を変更できません。
|
||||
full_name=フルネーム
|
||||
website=WEBサイト
|
||||
location=ロケーション
|
||||
@@ -273,7 +277,7 @@ new_password=新しいパスワード
|
||||
retype_new_password=新しいパスワードを再入力します。
|
||||
password_incorrect=現在のパスワードが正しくありません。
|
||||
change_password_success=パスワードが正常に変更されました。今すぐ新しいパスワード経由でサインインすることができます。
|
||||
password_change_disabled=Non-local type users are not allowed to change their password.
|
||||
password_change_disabled=ローカルユーザ以外はパスワードを変更できません。
|
||||
|
||||
emails=E-mail アドレス
|
||||
manage_emails=E-mail アドレスを管理
|
||||
@@ -355,7 +359,7 @@ auto_init=選択されたファイルおよびテンプレートでリポジト
|
||||
create_repo=リポジトリを作成
|
||||
default_branch=デフォルトのブランチ
|
||||
mirror_interval=ミラー 間隔(時)
|
||||
mirror_address=Mirror Address
|
||||
mirror_address=ミラー アドレス
|
||||
mirror_address_desc=Please include necessary user credentials in the address.
|
||||
watchers=ウォッチャー
|
||||
stargazers=Stargazers
|
||||
@@ -375,7 +379,7 @@ migrate.permission_denied=ローカル リポジトリをインポートする
|
||||
migrate.invalid_local_path=ローカルパスが無効です。存在しないかディレクトリではありません。
|
||||
migrate.failed=移行に失敗しました: %v
|
||||
|
||||
mirror_from=mirror from
|
||||
mirror_from=mirror of
|
||||
forked_from=フォーク元
|
||||
fork_from_self=すでにあなたの所有しているリポジトリはフォークできません
|
||||
copy_link=コピー
|
||||
@@ -454,7 +458,7 @@ issues.filter_sort=並べ替え
|
||||
issues.filter_sort.latest=最新
|
||||
issues.filter_sort.oldest=最も古い
|
||||
issues.filter_sort.recentupdate=最近更新された
|
||||
issues.filter_sort.leastupdate=Least recently updated
|
||||
issues.filter_sort.leastupdate=つい最近更新
|
||||
issues.filter_sort.mostcomment=一番多いコメント
|
||||
issues.filter_sort.leastcomment=一番少ないコメント
|
||||
issues.opened_by=opened %[1]s by <a href="%[2]s">%[3]s</a>
|
||||
@@ -492,6 +496,7 @@ issues.label_modify=ラベルの変更
|
||||
issues.label_deletion=ラベルの削除
|
||||
issues.label_deletion_desc=ラベルを削除すると、関連するすべての問題の情報が削除されます。続行しますか。
|
||||
issues.label_deletion_success=ラベルは正常に削除されました。
|
||||
issues.num_participants=%d Participants
|
||||
|
||||
pulls.new=新しいプルリクエスト
|
||||
pulls.compare_changes=変更を比較
|
||||
@@ -515,7 +520,7 @@ pulls.data_broken=Data of this pull request has been broken due to deletion of f
|
||||
pulls.is_checking=The conflict checking is still in progress, please refresh page in few moments.
|
||||
pulls.can_auto_merge_desc=This pull request can be merged automatically.
|
||||
pulls.cannot_auto_merge_desc=This pull request can't be merged automatically because there are conflicts.
|
||||
pulls.cannot_auto_merge_helper=Please merge manually in order to resolve the conflicts.
|
||||
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.`
|
||||
|
||||
@@ -545,7 +550,7 @@ milestones.deletion_success=マイルス トーンは正常に削除されまし
|
||||
|
||||
wiki=Wiki
|
||||
wiki.welcome=Wiki へようこそ!
|
||||
wiki.welcome_desc=Wiki is the place where you would like to document your project together and make it better.
|
||||
wiki.welcome_desc=Wikiとは、あなたのプロジェクトを文書化し、複数人で一緒に編集する場所です。
|
||||
wiki.create_first_page=最初のページを作成する。
|
||||
wiki.page=ページ
|
||||
wiki.filter_page=フィルターページ
|
||||
@@ -569,27 +574,32 @@ settings.site=公式サイト
|
||||
settings.update_settings=設定の更新
|
||||
settings.change_reponame_prompt=この変更はリンクがリポジトリに関連付ける方法に影響します。
|
||||
settings.advanced_settings=拡張設定
|
||||
settings.wiki_desc=Enable wiki to allow people write documents
|
||||
settings.use_external_wiki=Use external wiki
|
||||
settings.external_wiki_url=External Wiki URL
|
||||
settings.wiki_desc=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=Enable builtin lightweight issue tracker
|
||||
settings.issues_desc=組み込み簡易課題トラッカーを有効
|
||||
settings.use_external_issue_tracker=外部課題トラッキングシステムを使用
|
||||
settings.tracker_url_format=外部課題トラッキングツール URLのフォーマット
|
||||
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=危険地帯
|
||||
settings.new_owner_has_same_repo=新しいオーナーは、既に同じ名前のリポジトリを持っています。
|
||||
settings.convert=Convert To Regular Repository
|
||||
settings.convert_desc=You can convert this mirror to a regular repository. This cannot be reversed.
|
||||
settings.convert_notices_1=- This operation will convert this repository mirror into a regular repository and cannot be undone.
|
||||
settings.convert_confirm=Confirm Conversion
|
||||
settings.convert_succeed=Repository has been converted to regular type successfully.
|
||||
settings.transfer=オーナー移転
|
||||
settings.transfer_desc=リポジトリをあなたが管理者権限を持っている別のユーザーまた組織に移譲します。
|
||||
settings.new_owner_has_same_repo=新しいオーナーは、既に同じ名前のリポジトリを持っています。
|
||||
settings.delete=このリポジトリを削除
|
||||
settings.delete_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.delete=このリポジトリを削除
|
||||
settings.delete_desc=リポジトリを削除すると元に戻せません。確実に確認してください。
|
||||
settings.delete_notices_1=-この操作は<strong>元に戻せません</strong> 。
|
||||
settings.delete_notices_2=- This operation will permanently delete the everything of this repository, including Git data, issues, comments and accesses of collaborators.
|
||||
settings.delete_notices_fork_1=- If this repository is public, all forks will be became independent after deletion.
|
||||
settings.delete_notices_fork_1=- If this repository is public, all forks will become independent after deletion.
|
||||
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
|
||||
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
|
||||
settings.deletion_success=Repository has been deleted successfully!
|
||||
@@ -602,15 +612,16 @@ settings.add_collaborator=新しい共同編集者を追加
|
||||
settings.add_collaborator_success=新しい共同編集者が追加されました。
|
||||
settings.remove_collaborator_success=共同編集者が削除されました。
|
||||
settings.search_user_placeholder=Search users
|
||||
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member=ユーザーは組織の一員なので、共同編集者として追加することはできません。
|
||||
settings.add_webhook=Webhook を追加
|
||||
settings.hooks_desc=Webhooksは、Gogsで特定のイベントの発生時に指定された外部サービスに通知を許可します。イベントが発生すると、それぞれ指定されたUrlに、POSTリクエストが送られます。詳細はこちらのの <a target="_blank"href="%s"> Webhooks ガイド</a>をご覧ください。
|
||||
settings.webhook_deletion=Webhook を削除
|
||||
settings.webhook_deletion_desc=このwebhookを削除すると、すべての情報と配信履歴が削除されます。続行しますか?
|
||||
settings.webhook_deletion_success=Webhook が正常に削除されました。
|
||||
settings.webhook.test_delivery=Test Delivery
|
||||
settings.webhook.test_delivery=テスト配信
|
||||
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
|
||||
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
|
||||
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may take few seconds before it shows up in the delivery history.
|
||||
settings.webhook.request=リクエスト
|
||||
settings.webhook.response=レスポンス
|
||||
settings.webhook.headers=ヘッダ
|
||||
@@ -666,6 +677,8 @@ diff.parent=親
|
||||
diff.commit=コミット
|
||||
diff.data_not_available=差分データは利用できません。
|
||||
diff.show_diff_stats=差分情報を表示
|
||||
diff.show_split_view=Split View
|
||||
diff.show_unified_view=Unified View
|
||||
diff.stats_desc=共有<strong>%d 個のファイルを変更した</strong>、<strong>%d 個の追加</strong> と <strong>%d 個の削除</strong>を含む
|
||||
diff.bin=BIN
|
||||
diff.view_file=ファイルの表示
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys='.ssh/ authorized_keys' ファイルを再生成し
|
||||
dashboard.resync_all_sshkeys_success=すべての公開鍵が正常に書き換えられました。
|
||||
dashboard.resync_all_update_hooks=リポジトリの update フックをすべて再更新する(カスタムの設定パスが変更されたときに必要)
|
||||
dashboard.resync_all_update_hooks_success=リポジトリの update フックがすべて正常に再更新されました。
|
||||
dashboard.reinit_missing_repos=Reinitialize all repository records that lost Git files
|
||||
dashboard.reinit_missing_repos_success=All repository records that lost Git files have been reinitialized successfully.
|
||||
|
||||
dashboard.server_uptime=サーバーの稼働時間
|
||||
dashboard.current_goroutine=現在のGoroutine
|
||||
@@ -907,6 +922,7 @@ auths.attribute_username_placeholder=Leave empty to use sign-in form field value
|
||||
auths.attribute_name=名前属性
|
||||
auths.attribute_surname=名字属性
|
||||
auths.attribute_mail=Eメール属性
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
auths.filter=User フィルター
|
||||
auths.admin_filter=Admin フィルター
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm=電子メールの確認を必要
|
||||
config.disable_register=登録を無効にする
|
||||
config.show_registration_button=登録ボタンを表示します。
|
||||
config.require_sign_in_view=サインインを要求
|
||||
config.enable_cache_avatar=アバターのキャッシュを有効にします。
|
||||
config.mail_notify=メール通知
|
||||
config.disable_key_size_check=最小キー サイズ チェックを無効にします
|
||||
config.enable_captcha=Captchaを有効にする
|
||||
@@ -1018,19 +1033,21 @@ notices.type=タイプ
|
||||
notices.type_1=リポジトリ
|
||||
notices.desc=説明
|
||||
notices.op=Op。
|
||||
notices.delete_success=System notices have been deleted successfully.
|
||||
notices.delete_success=システム通知が正常に削除されました。
|
||||
|
||||
[action]
|
||||
create_repo=リポジトリ <a href="%s"> %s</a>を作成しました
|
||||
rename_repo=<code>%[1]s</code> から <a href="%[2]s">[3]s</a> にリポジトリ名を変更した
|
||||
commit_repo=<a href="%[1]s">%[4]s</a>を<a href="%[1]s/src/%[2]s">%[3]s</a>にプッシュしました
|
||||
create_issue=`問題 <a href="%s/issues/%s">%s#%[2]s</a> を開きました`
|
||||
close_issue=`closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`プルリクエスト <a href="%s/pulls/%s"> %s[2]s</a>を作成`
|
||||
comment_issue=`問題 <a href="%s/issues/%s">%s#%[2]s</a> のコメント`
|
||||
merge_pull_request=`プルリクエスト <a href="%s/pulls/%s"> %s[2]s</a>をマージしました`
|
||||
transfer_repo=リポジトリ <code>%s</code> を <a href="%s">%s</a> へ転送しました
|
||||
push_tag=<a href="%[1]s">%[3]s</a> に タグ <a href="%[1]s/src/%[2]s">%[2]s</a> をプッシュしました
|
||||
compare_commits=View comparison for these %d commits
|
||||
compare_commits=これらの %d コミットの比較を表示
|
||||
|
||||
[tool]
|
||||
ago=前
|
||||
|
||||
@@ -28,7 +28,7 @@ organization=Organizācija
|
||||
mirror=Spogulis
|
||||
new_repo=Jauns repozitorijs
|
||||
new_migrate=Jauna migrācija
|
||||
new_mirror=New Mirror
|
||||
new_mirror=Jauns spogulis
|
||||
new_fork=Jauns atdalītais repozitorijs
|
||||
new_org=Jauna organizācija
|
||||
manage_org=Pārvaldīt organizācijas
|
||||
@@ -38,7 +38,7 @@ settings=Iestatījumi
|
||||
your_profile=Tavs profils
|
||||
your_settings=Tavi iestatījumi
|
||||
|
||||
news_feed=Jaunumu plūsma
|
||||
activities=Activities
|
||||
pull_requests=Izmaiņu pieprasījumi
|
||||
issues=Problēmas
|
||||
|
||||
@@ -65,7 +65,7 @@ db_name=Datu bāzes nosaukums
|
||||
db_helper=Nepieciešams izmantot MySQL INNODB dzini ar rakstzīmju kopu utf8_general_ci.
|
||||
ssl_mode=SSL režīms
|
||||
path=Ceļš
|
||||
sqlite_helper=SQLite3 vai TiDB datu bāzes faila atrašanās vieta.
|
||||
sqlite_helper=The file path of SQLite3 or TiDB database. <br>Please use absolute path when you start as service.
|
||||
err_empty_db_path=Nepieciešams norādīt SQLite3 vai TiDB datu bāzes atrašanās vietu.
|
||||
err_invalid_tidb_name=TiDB datu bāzes nosaukums nevar saturēt simbolus "." un "-".
|
||||
no_admin_and_disable_registration=Reģistrāciju nevar atslēgt, kamēr nav izveidots administratora konts.
|
||||
@@ -86,6 +86,8 @@ http_port=HTTP ports
|
||||
http_port_helper=Porta numurs pēc kura lietojumprogrammai būs iespējams pieslēgties.
|
||||
app_url=Lietotnes URL
|
||||
app_url_helper=Tas ietekmē HTTP/HTTPS klonēšanas URL un e-pasta saturā izsūtītās saites.
|
||||
log_root_path=Log Path
|
||||
log_root_path_helper=Directory to write log files to.
|
||||
|
||||
optional_title=Neobligātie iestatījumi
|
||||
email_title=E-pasta pakalpojuma iestatījumi
|
||||
@@ -122,6 +124,7 @@ run_user_not_match=Izpildes lietotājs nav pašreizējais lietotājs: %s -> %s
|
||||
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!
|
||||
invalid_log_root_path=Log root path is invalid: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Lietotājvārds vai e-pasts
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken=Repozitorija vārds ir jau aizņemts.
|
||||
org_name_been_taken=Organizācijas nosaukums ir jau aizņemts.
|
||||
team_name_been_taken=Komandas nosaukums ir jau aizņemts.
|
||||
email_been_used=E-pasta adrese jau tiek izmantota.
|
||||
illegal_team_name=Grupas nosaukums satur neatļautas rakstzīmes.
|
||||
username_password_incorrect=Lietotājvārds vai parole nav pareiza.
|
||||
enterred_invalid_repo_name=Lūdzu, pārliecinieties, vai ievadītā repozitorija nosaukums ir pareizs.
|
||||
enterred_invalid_owner_name=Lūdzu, pārliecinieties, vai ievadītā īpašnieka vārds ir pareizs.
|
||||
@@ -232,6 +234,8 @@ activity=Publiskā aktivitāte
|
||||
followers=Sekotāji
|
||||
starred=Atzīmēti ar zvaigznīti
|
||||
following=Seko
|
||||
follow=Sekot
|
||||
unfollow=Nesekot
|
||||
|
||||
form.name_reserved=Lietotāja vārds '%s' jau ir aizņemts.
|
||||
form.name_pattern_not_allowed=Lietotāja vārds '%s' nav atļauts.
|
||||
@@ -248,7 +252,7 @@ uid=Lietotāja ID
|
||||
|
||||
public_profile=Publiskais profils
|
||||
profile_desc=Jūsu e-pasta adrese ir publiska un tiks izmantota, lai nosūtītju Jums paziņojumus, kas saistīti ar Jūsu kontu vai darbībām veiktām caur šo mājas lapu.
|
||||
password_username_disabled=Non-local type users are not allowed to change their username.
|
||||
password_username_disabled=Ne-lokālie lietotāji nevar mainīt savus lietotājvārdus.
|
||||
full_name=Pilns vārds
|
||||
website=Mājas lapa
|
||||
location=Atrašanās vieta
|
||||
@@ -273,7 +277,7 @@ new_password=Jauna parole
|
||||
retype_new_password=Ievadīt paroli atkāroti
|
||||
password_incorrect=Ievadīta nepareiza pašreizējā parole.
|
||||
change_password_success=Parole tika veiksmīgi nomainīta. Tagad jūs varat pieraksītites, izmantojot jauno paroli.
|
||||
password_change_disabled=Non-local type users are not allowed to change their password.
|
||||
password_change_disabled=Ne-lokālie lietotāji nevar mainīt savas paroles.
|
||||
|
||||
emails=E-pasta adreses
|
||||
manage_emails=Pārvaldīt e-pasta adreses
|
||||
@@ -355,13 +359,13 @@ auto_init=Inicializēt šo repozitoriju ar izvēlētajiem failiem un sagatavi
|
||||
create_repo=Izveidot repozitoriju
|
||||
default_branch=Noklusējuma atzars
|
||||
mirror_interval=Spoguļošanas intervāls (stundās)
|
||||
mirror_address=Mirror Address
|
||||
mirror_address_desc=Please include necessary user credentials in the address.
|
||||
mirror_address=Spoguļa adrese
|
||||
mirror_address_desc=Lūdzu iekļaujiet adresē nepieciešamo lietotājvārdu/paroli.
|
||||
watchers=Novērotāji
|
||||
stargazers=Zvaigžņdevēji
|
||||
forks=Atdalītie repozitoriji
|
||||
|
||||
form.reach_limit_of_creation=The owner has reached maximum creation limit of %d repositories.
|
||||
form.reach_limit_of_creation=Īpašnieks sasniedza maksimālu pieļaujamo (%d) izveidoto repozitoriju skaitu.
|
||||
form.name_reserved=Repozitorija nosaukums '%s' ir rezervēts.
|
||||
form.name_pattern_not_allowed=Repozitorija nosaukums '%s' nav atļauts.
|
||||
|
||||
@@ -375,7 +379,7 @@ 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
|
||||
|
||||
mirror_from=mirror from
|
||||
mirror_from=spogulis no
|
||||
forked_from=atdalīts no
|
||||
fork_from_self=Nav iespējams atdalīt repozitoriju, kuram esat īpašnieks!
|
||||
copy_link=Kopēt
|
||||
@@ -395,7 +399,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=Code
|
||||
code=Kods
|
||||
branch=Atzars
|
||||
tree=Koks
|
||||
filter_branch_and_tag=Filtrēt atzarus vai tagus
|
||||
@@ -492,6 +496,7 @@ issues.label_modify=Etiķetes labošana
|
||||
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 Participants
|
||||
|
||||
pulls.new=Jauns izmaiņu pieprasījums
|
||||
pulls.compare_changes=Salīdzināt izmaiņas
|
||||
@@ -513,9 +518,9 @@ pulls.merged=Sapludināts
|
||||
pulls.has_merged=Šo izmaiņu pieprasījums tika veiksmīgi sapludināts!
|
||||
pulls.data_broken=Nepieejami izmaiņu pieprasījuma dati, jo dzēsta informācija no atdalītā repozitorija.
|
||||
pulls.is_checking=Notiek konfliktu pārbaude, mirkli uzgaidiet un atjaunojiet lapu.
|
||||
pulls.can_auto_merge_desc=This pull request can be merged automatically.
|
||||
pulls.cannot_auto_merge_desc=This pull request can't be merged automatically because there are conflicts.
|
||||
pulls.cannot_auto_merge_helper=Please merge manually in order to resolve the conflicts.
|
||||
pulls.can_auto_merge_desc=Šo izmaiņu pieprasījumu var automātiski saplūdināt.
|
||||
pulls.cannot_auto_merge_desc=Šis izmaiņu pieprasījums nevar tikt automātiski saplūdināts konfliktu dēļ.
|
||||
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.`
|
||||
|
||||
@@ -568,31 +573,36 @@ settings.basic_settings=Pamatiestatījumi
|
||||
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=Advanced Settings
|
||||
settings.wiki_desc=Enable wiki to allow people write documents
|
||||
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.use_external_issue_tracker=Use external issue tracker
|
||||
settings.tracker_url_format=External Issue Tracker URL Format
|
||||
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.advanced_settings=Papildu iestatījumi
|
||||
settings.wiki_desc=Iespējot vikivietni, lai atļautu cilvēkiem rakstīt dokumentus
|
||||
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.use_external_issue_tracker=Izmantot ārējo problēmu sekotāju
|
||||
settings.tracker_url_format=Ārējā problēmu sekotāja adreses formāts
|
||||
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
|
||||
settings.new_owner_has_same_repo=Jaunajam īpašniekam jau ir repozitorijs ar šādu nosaukumu.
|
||||
settings.convert=Convert To Regular Repository
|
||||
settings.convert_desc=You can convert this mirror to a regular repository. This cannot be reversed.
|
||||
settings.convert_notices_1=- This operation will convert this repository mirror into a regular repository and cannot be undone.
|
||||
settings.convert_confirm=Confirm Conversion
|
||||
settings.convert_succeed=Repository has been converted to regular type successfully.
|
||||
settings.transfer=Mainīt īpašnieku
|
||||
settings.transfer_desc=Mainīt šī repozitorija īpašnieku uz citu lietotāju vai organizāciju, kurai Jums ir administratora tiesībs.
|
||||
settings.new_owner_has_same_repo=Jaunajam īpašniekam jau ir repozitorijs ar šādu nosaukumu.
|
||||
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.transfer_notices_1=- Jūs pazaudēsiet piekļuvi, ja jaunais īpašnieks ir lietotājs.
|
||||
settings.transfer_notices_2=- Jūs saglabāsiet piekļuvi, ja jaunais īpašnieks ir organizācija un Jūs esat viens no tās īpašniekiem.
|
||||
settings.transfer_form_title=Lūdzu, ievadiet sekojošu informāciju, lai apstiprinātu šo darbību:
|
||||
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=- Ja repozitorijs ir publisks, visi atdalītie repozitoriji kļūs neatkarīgi.
|
||||
settings.delete_notices_fork_2=- Ja repozitorijs ir privāts, tiks dzēsti arī visi atdalītie repozitoriji.
|
||||
settings.delete_notices_fork_3=- Ja vēlaties saglabāt atdalīts repozitorijus pēc dzēšanas, sākumā nomainiet repozitorija redzamību uz publisku.
|
||||
settings.deletion_success=Repository has been deleted successfully!
|
||||
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
|
||||
settings.make_transfer=Mainīt
|
||||
@@ -602,15 +612,16 @@ settings.add_collaborator=Pievienot jaunu līdzstrādnieku
|
||||
settings.add_collaborator_success=Jauns līdzstrādnieks ir pievienots.
|
||||
settings.remove_collaborator_success=Līdzstrādnieks tika noņemts.
|
||||
settings.search_user_placeholder=Meklēt lietotāju...
|
||||
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member=Lietotājs ir organizācijas biedrs, kas nevar tikt pievienots kā līdzstrādnieks.
|
||||
settings.add_webhook=Pievienot tīmekļa āķi
|
||||
settings.hooks_desc=Tīmekļa āķi ļauj paziņot ārējiem servisiem par noteiktiem notikomiem, kas notiek Git servisā. Kad iestāsies kāds notikums, katram ārējā servisa URL tiks nosūtīts POST pieprasījums. Lai uzzinātu sīkāk skatieties <a target="_blank" href="%s">Tīmekļa āķu rokasgrāmatā</a>.
|
||||
settings.webhook_deletion=Dzēst tīmekļa āķi
|
||||
settings.webhook_deletion_desc=Dzēšot tīmekļa āķi tiks dzēsta visa ar to saistītā informācija un izpildes vēsture. Vai vēlaties turpināt?
|
||||
settings.webhook_deletion_success=Tīmekļa āķis tika veiksmīgi izdzēsts!
|
||||
settings.webhook.test_delivery=Test Delivery
|
||||
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
|
||||
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
|
||||
settings.webhook.test_delivery=Testa piegāde
|
||||
settings.webhook.test_delivery_desc=Veikt viltus push-notikuma piegādi lai notestētu Jūsu tīmekļa āķa iestatījumus
|
||||
settings.webhook.test_delivery_success=Testa web-āķis ir pievienots piegādes rindai. Var paiet dažas sekundes, kamēr tas parādīsies piegāžu vēsturē.
|
||||
settings.webhook.request=Pieprasījums
|
||||
settings.webhook.response=Atbilde
|
||||
settings.webhook.headers=Galvenes
|
||||
@@ -666,6 +677,8 @@ diff.parent=vecāks
|
||||
diff.commit=revīzija
|
||||
diff.data_not_available=Salīdzināšanas dati nav pieejami.
|
||||
diff.show_diff_stats=Rādīt salīdzināšanas statistiku
|
||||
diff.show_split_view=Dalītais skats
|
||||
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
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys=Pārrakstīt '.ssh/authorized_keys' failu (brīdin
|
||||
dashboard.resync_all_sshkeys_success=Visas publiskās atslēgas tika veiksmīgi pārrakstītas.
|
||||
dashboard.resync_all_update_hooks=Pārrakstīt visu repozitoriju izmaiņu āķus (nepieciešams, ja tiek mainīta konfigurācijas faila atrašanās vieta)
|
||||
dashboard.resync_all_update_hooks_success=Visu repozitoriju izmaiņu āķi tika veiksmīgi pārrakstīti.
|
||||
dashboard.reinit_missing_repos=Reinitialize all repository records that lost Git files
|
||||
dashboard.reinit_missing_repos_success=All repository records that lost Git files have been reinitialized successfully.
|
||||
|
||||
dashboard.server_uptime=Servera darbības laiks
|
||||
dashboard.current_goroutine=Izmantotās Gorutīnas
|
||||
@@ -861,8 +876,8 @@ users.auth_login_name=Autentifikācijas pieteikšanās vārds
|
||||
users.password_helper=Atstājiet tukšu, ja nevēlaties mainīt.
|
||||
users.update_profile_success=Konta profils tika veiksmīgi saglabāts.
|
||||
users.edit_account=Labot kontu
|
||||
users.max_repo_creation=Maximum Repository Creation Limit
|
||||
users.max_repo_creation_desc=(Set -1 to use global default limit)
|
||||
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.is_admin=Šim kontam ir administratora piekļuves tiesības
|
||||
users.allow_git_hook=Šim kontam ir tiesības pievienot/labot Git āķus
|
||||
@@ -907,6 +922,7 @@ auths.attribute_username_placeholder=Atstājiet tukšu, lai izmantotu lietotājv
|
||||
auths.attribute_name=Vārda atribūts
|
||||
auths.attribute_surname=Uzvārda atribūts
|
||||
auths.attribute_mail=E-pasta atribūts
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
auths.filter=Lietotāju filts
|
||||
auths.admin_filter=Administratoru filtrs
|
||||
auths.ms_ad_sa=MS Ad SA
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm=Pieprasīt e-pasta apstiprināšanu
|
||||
config.disable_register=Atspējot jaunu lietotāju reģistrāciju
|
||||
config.show_registration_button=Rādīt reģistrēšanās pogu
|
||||
config.require_sign_in_view=Nepieciešama autorizācija
|
||||
config.enable_cache_avatar=Glabāt profila attēlus kešatmiņā
|
||||
config.mail_notify=Pasta paziņojumi
|
||||
config.disable_key_size_check=Atspējot atslēgas minimālā garuma pārbaudi
|
||||
config.enable_captcha=Iespējot drošības kodu
|
||||
@@ -1007,30 +1022,32 @@ monitor.start=Sākuma laiks
|
||||
monitor.execute_time=Izpildes laiks
|
||||
|
||||
notices.system_notice_list=Sistēmas paziņojumi
|
||||
notices.view_detail_header=View Notice Detail
|
||||
notices.actions=Actions
|
||||
notices.select_all=Select All
|
||||
notices.deselect_all=Deselect All
|
||||
notices.inverse_selection=Inverse Selection
|
||||
notices.delete_selected=Delete Selected
|
||||
notices.delete_all=Delete All Notices
|
||||
notices.view_detail_header=Skatīt paziņojuma detaļas
|
||||
notices.actions=Darbības
|
||||
notices.select_all=Iezīmēt visu
|
||||
notices.deselect_all=Atcelt visa iezīmēšanu
|
||||
notices.inverse_selection=Apgriezeniskā iezīmēšana
|
||||
notices.delete_selected=Dzēst iezīmēto
|
||||
notices.delete_all=Dzēst visus paziņojumus
|
||||
notices.type=Veids
|
||||
notices.type_1=Repozitorijs
|
||||
notices.desc=Apraksts
|
||||
notices.op=Op.
|
||||
notices.delete_success=System notices have been deleted successfully.
|
||||
notices.delete_success=Sistēmas paziņojumi tika veiksmīgi izdzēstas.
|
||||
|
||||
[action]
|
||||
create_repo=izveidoja repozitoriju <a href="%s">%s</a>
|
||||
rename_repo=pārsauca repozitoriju no <code>%[1]s</code> uz <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=veica izmaiņu nosūtīšanu atzaram <a href="%[1]s/src/%[2]s">%[3]s</a> repozitorijā <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`reģistrēja problēmu <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue=`closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`izveidoja izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`pievienoja komentāru problēmai <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`sapludināja izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
transfer_repo=mainīja repozitorija <code>%s</code> īpašnieku uz <a href="%s">%s</a>
|
||||
push_tag=pievienoja tagu <a href="%s/src/%s">%[2]s</a> repozitorijam <a href="%[1]s">%[3]s</a>
|
||||
compare_commits=View comparison for these %d commits
|
||||
compare_commits=Salīdzināt šīs %d revīzijas
|
||||
|
||||
[tool]
|
||||
ago=atpakaļ
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
app_desc=Een eenvoudige zelfgehoste Git service geschreven in Go
|
||||
|
||||
home=Huis
|
||||
home=Home
|
||||
dashboard=Dashboard
|
||||
explore=Verkennen
|
||||
help=Help
|
||||
@@ -13,22 +13,22 @@ version=Versie
|
||||
page=Pagina
|
||||
template=Sjabloon
|
||||
language=Taal
|
||||
create_new=Create...
|
||||
create_new=Creëren...
|
||||
user_profile_and_more=Gebruikersprofiel en meer
|
||||
signed_in_as=Aangemeld als
|
||||
|
||||
username=Gebruikersnaam
|
||||
email=E-mail
|
||||
password=Wachttwoord
|
||||
password=Wachtwoord
|
||||
re_type=Verificatie
|
||||
captcha=CAPTCHA
|
||||
|
||||
repository=Repositorie
|
||||
repository=Repository
|
||||
organization=Organisatie
|
||||
mirror=Spiegel
|
||||
new_repo=Nieuwe repositorie
|
||||
new_migrate=Nieuwe migratie
|
||||
new_mirror=New Mirror
|
||||
new_mirror=Nieuwe Kopie
|
||||
new_fork=Nieuwe vork Repository
|
||||
new_org=Nieuwe organisatie
|
||||
manage_org=Beheer organisaties
|
||||
@@ -38,7 +38,7 @@ settings=Instellingen
|
||||
your_profile=Uw profiel
|
||||
your_settings=Uw instellingen
|
||||
|
||||
news_feed=Nieuwsfeed
|
||||
activities=Activities
|
||||
pull_requests=Pull-aanvragen
|
||||
issues=Kwesties
|
||||
|
||||
@@ -54,8 +54,8 @@ code=Code
|
||||
[install]
|
||||
install=Installatie
|
||||
title=Installatiestappen voor de eerste keer opstarten
|
||||
docker_helper=If you're running Gogs inside Docker, please read <a target="_blank" href="%s">Guidelines</a> carefully before you change anything in this page!
|
||||
requite_db_desc=Gogs requires MySQL, PostgreSQL, SQLite3 or TiDB.
|
||||
docker_helper=Als u gebruik maakt Gogs binnen Docker, lees dan de <a target="_blank" href="%s">richtlijnen</a> voordat u iets veranderen op deze pagina!
|
||||
requite_db_desc=Gogs vereist MySQL, PostgreSQL, SQite3 of TiDB.
|
||||
db_title=Database instellingen
|
||||
db_type=Database-type
|
||||
host=Host
|
||||
@@ -65,11 +65,11 @@ db_name=Database naam
|
||||
db_helper=Gebruik InnoDB engine met utf8_general_ci karakterset voor MySQL.
|
||||
ssl_mode=SSL-modus
|
||||
path=Pad
|
||||
sqlite_helper=The file path of SQLite3 or TiDB database.
|
||||
err_empty_db_path=SQLite3 or TiDB database path cannot be empty.
|
||||
err_invalid_tidb_name=TiDB database name does not allow characters "." and "-".
|
||||
no_admin_and_disable_registration=You cannot disable registration without creating an admin account.
|
||||
err_empty_admin_password=Admin password cannot be empty.
|
||||
sqlite_helper=The file path of SQLite3 or TiDB database. <br>Please use absolute path when you start as service.
|
||||
err_empty_db_path=SQLite3 of TiDB databankpad mag niet leeg.
|
||||
err_invalid_tidb_name=TiDB databank naam niet tekens kunnen "." en "-".
|
||||
no_admin_and_disable_registration=Je kunt niet de registratie uit te schakelen zonder een beheerders account.
|
||||
err_empty_admin_password=Beheerder wachtwoord kan niet leeg zijn.
|
||||
|
||||
general_title=Toepassing algemene instellingen
|
||||
app_name=Applicatienaam
|
||||
@@ -86,6 +86,8 @@ http_port=HTTP-poort
|
||||
http_port_helper=Poortnummer waar het programma naar luistert.
|
||||
app_url=Applicatie URL
|
||||
app_url_helper=Dit heeft invloed op de HTTP/HTTPS kloon urls en de urls die in de email worden gebruikt
|
||||
log_root_path=Log Path
|
||||
log_root_path_helper=Directory to write log files to.
|
||||
|
||||
optional_title=Optionele instellingen
|
||||
email_title=E-mail service instellingen
|
||||
@@ -103,8 +105,8 @@ disable_gravatar=Gravatar Service uitschakelen
|
||||
disable_gravatar_popup=Schakel Gravatar en andere bronnen uit, alle avatars worden door gebruikers geüpload of zijn standaard.
|
||||
disable_registration=Schakel zelfregistratie uit
|
||||
disable_registration_popup=Schakel zelfregistratie uit, alleen admins kunnen accounts maken.
|
||||
enable_captcha=Enable Captcha
|
||||
enable_captcha_popup=Require validate captcha for user self-registration.
|
||||
enable_captcha=Inschakelen Captcha
|
||||
enable_captcha_popup=Vereis captcha validatie voor zelf-registratie van gebruiker.
|
||||
require_sign_in_view=Schakel vereiste aanmelding om pagina's te zien in
|
||||
require_sign_in_view_popup=Alleen ingelogde gebruikers kunnen pagina's bekijken, bezoekers kunnen alleen de login/registratie pagina's zien.
|
||||
admin_setting_desc=U hoeft niet meteen een administratie account te maken, de gebruiker met ID=1 krijgt automatisch administratierechten.
|
||||
@@ -112,16 +114,17 @@ admin_title=Instellingen beheerdersaccount
|
||||
admin_name=Gebruikersnaam
|
||||
admin_password=Wachtwoord
|
||||
confirm_password=Verifieer wachtwoord
|
||||
admin_email=Admin Email
|
||||
admin_email=Beheerder E-mail
|
||||
install_gogs=Installeer Gogs
|
||||
test_git_failed=Git test niet gelukt: 'git' commando %v
|
||||
sqlite3_not_available=Uw versie biedt geen ondersteuning voor SQLite3, download de officiële binaire versie van %s, niet de gobuild versie.
|
||||
invalid_db_setting=Uw database instellingen zijn niet correct: %v
|
||||
invalid_repo_path=Repositorie basis pad is 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
|
||||
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
|
||||
invalid_log_root_path=Log root path is invalid: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Gebruikersnaam of e-mail
|
||||
@@ -161,11 +164,11 @@ reset_password_helper=Klik hier om uw wachtwoord opnieuw in te stellen.
|
||||
password_too_short=De lengte van uw wachtwoord moet minimaal zes karakters zijn.
|
||||
|
||||
[mail]
|
||||
activate_account=Please activate your account
|
||||
activate_email=Verify your email address
|
||||
reset_password=Reset your password
|
||||
register_success=Registration successful, welcome
|
||||
register_notify=Welcome on board
|
||||
activate_account=Activeer uw account
|
||||
activate_email=Verifieer je e-mailadres
|
||||
reset_password=Stel je wachtwoord opnieuw in
|
||||
register_success=Registratie succesvol, welkom
|
||||
register_notify=Welkom aan boord
|
||||
|
||||
[modal]
|
||||
yes=Ja
|
||||
@@ -174,7 +177,7 @@ modify=Aanpassen
|
||||
|
||||
[form]
|
||||
UserName=Gebruikersnaam
|
||||
RepoName=Repositorie naam
|
||||
RepoName=Naam van repository
|
||||
Email=e-mailadres
|
||||
Password=Wachtwoord
|
||||
Retype=Verifieer wachtwoord
|
||||
@@ -193,17 +196,16 @@ min_size_error=moet minimaal %s karakters bevatten.
|
||||
max_size_error=mag maximaal %s karakters bevatten.
|
||||
email_error=is niet een valide e-mail adres.
|
||||
url_error=is niet een valide URL.
|
||||
include_error=` must contain substring '%s'.`
|
||||
include_error=` moet substring '%s' bevatten.`
|
||||
unknown_error=Onbekende fout:
|
||||
captcha_incorrect=Captcha komt niet overeen.
|
||||
password_not_match=Wachtwoord en verificatie wachtwoord komen niet overeen.
|
||||
|
||||
username_been_taken=Gebruikersnaam is al in gebruik.
|
||||
repo_name_been_taken=Repositorie naam is al in gebruik.
|
||||
repo_name_been_taken=Deze naam is al in gebruik.
|
||||
org_name_been_taken=Organisatie naam is al in gebruik.
|
||||
team_name_been_taken=Team naam is al in gebruik.
|
||||
email_been_used=e-mailadres is al in gebruik.
|
||||
illegal_team_name=Team naam bevat illegale karakters.
|
||||
username_password_incorrect=Gebruikersnaam of wachtwoord is niet correct.
|
||||
enterred_invalid_repo_name=U heeft een onjuiste repositorie naam ingevoerd.
|
||||
enterred_invalid_owner_name=U heeft een onjuiste eigenaar ingevoerd.
|
||||
@@ -232,6 +234,8 @@ activity=Openbare activiteit
|
||||
followers=Volgers
|
||||
starred=Sterren
|
||||
following=Volgt
|
||||
follow=Volg
|
||||
unfollow=Niet meer volgen
|
||||
|
||||
form.name_reserved=De gebruikersnaam '%s' is gereserveerd.
|
||||
form.name_pattern_not_allowed=Het gebruikersnaam patroon '%s' is niet toegestaan.
|
||||
@@ -248,14 +252,14 @@ uid=uid
|
||||
|
||||
public_profile=Openbaar profiel
|
||||
profile_desc=Uw e-mailadres is openbaar en zal gebruikt worden voor alle account gerelateerde berichtgevingen en bewerkingingen die via de website worden gedaan.
|
||||
password_username_disabled=Non-local type users are not allowed to change their username.
|
||||
password_username_disabled=Extern opgeslagen gebruikers zijn niet toegestaan om hun gebruikersnaam veranderen.
|
||||
full_name=Volledige naam
|
||||
website=Website
|
||||
location=Locatie
|
||||
update_profile=Profile bijwerken
|
||||
update_profile_success=Uw profiel is succesvol bijgewerkt.
|
||||
change_username=Username veranderd
|
||||
change_username_prompt=This change will affect the way how links relate to your account.
|
||||
change_username_prompt=Deze verandering zal de weg links hebben betrekking op uw account beïnvloeden.
|
||||
continue=Doorgaan
|
||||
cancel=Annuleren
|
||||
|
||||
@@ -270,10 +274,10 @@ update_avatar_success=Instellingen voor avatar succesvol bijgewerkt.
|
||||
change_password=Verander wachtwoord
|
||||
old_password=Huidige wachtwoord
|
||||
new_password=Nieuw wachtwoord
|
||||
retype_new_password=Retype New Password
|
||||
retype_new_password=Herhaal Nieuw Wachtwoord
|
||||
password_incorrect=Huidig wachtwoord is niet correct.
|
||||
change_password_success=Wachtwoord is succesvol gewijzigd. U kunt nu met uw nieuwe wachtwoord inloggen.
|
||||
password_change_disabled=Non-local type users are not allowed to change their password.
|
||||
password_change_disabled=Extern opgeslagen gebruikers zijn niet toegestaan om hun wachtwoord te wijzigen.
|
||||
|
||||
emails=E-mailadressen
|
||||
manage_emails=E-mailadressen beheren
|
||||
@@ -281,9 +285,9 @@ email_desc=Uw primaire e-mailadres zal worden gebruikt voor meldingen en andere
|
||||
primary=Primair
|
||||
primary_email=Instellen als primair
|
||||
delete_email=Verwijder
|
||||
email_deletion=Email Deletion
|
||||
email_deletion_desc=Deleting this email address will remove related information from your account. Do you want to continue?
|
||||
email_deletion_success=Email has been deleted successfully!
|
||||
email_deletion=E-mail Verwijderen
|
||||
email_deletion_desc=Dit e-mailadres verwijdert, worden gerelateerde informatie van uw account te verwijderen. Wil je verdergaan?
|
||||
email_deletion_success=E-mail is succesvol verwijderd!
|
||||
add_new_email=Nieuw e-mailadres toevoegen
|
||||
add_email=E-mailadres toevoegen
|
||||
add_email_confirmation_sent=Een nieuwe bevestiging e-mail werd verstuurd naar '%s', gelieve uw inbox in de komende %d uren te controleren om het bevestigingsproces te voltooien.
|
||||
@@ -334,11 +338,11 @@ delete_account_desc=Dit account zal permanent worden verwijderd. Wilt u doorgaan
|
||||
|
||||
[repo]
|
||||
owner=Eigenaar
|
||||
repo_name=Repositorie naam
|
||||
repo_name_helper=Een goede repositorie naam is kort, memorabel en <strong>uniek</strong>.
|
||||
repo_name=Naam van repository
|
||||
repo_name_helper=Een goede repository-naam is kort, makkelijk te onthouden en <strong>uniek</strong>.
|
||||
visibility=Zichtbaarheid
|
||||
visiblity_helper=Deze repositorie is <span class="ui red text">privaat</span>
|
||||
visiblity_helper_forced=Site admin has forced all new repositories to be <span class="ui red text">Private</span>
|
||||
visiblity_helper_forced=Sitebeheerder heeft alle nieuwe repositories gedwongen <span class="ui red text">privé</span> te zijn
|
||||
visiblity_fork_helper=(Verandering van deze waarde zal van invloed zijn op alle forks)
|
||||
clone_helper=De behoeftehulp van klonen? Bezoek <a target="_blank" href="%s"> helpen</a>!
|
||||
fork_repo=Vork Repository
|
||||
@@ -352,16 +356,16 @@ license_helper=Selecteer een licentie bestand
|
||||
readme=Leesmij-bestand
|
||||
readme_helper=Selecteer een sjabloon voor het Leesmij-bestand
|
||||
auto_init=Initialiseer deze repositorie met de geselecteerde bestanden en sjabloon
|
||||
create_repo=Nieuwe Repositorie
|
||||
create_repo=Nieuwe repository
|
||||
default_branch=Standaard branch
|
||||
mirror_interval=Mirror interval(uur)
|
||||
mirror_address=Mirror Address
|
||||
mirror_address_desc=Please include necessary user credentials in the address.
|
||||
watchers=Watchers
|
||||
mirror_address=Kopie-adres
|
||||
mirror_address_desc=Gelieve noodzakelijke gebruikersgegevens in de adresbalk.
|
||||
watchers=Volgers
|
||||
stargazers=Stargazers
|
||||
forks=Forks
|
||||
|
||||
form.reach_limit_of_creation=The owner has reached maximum creation limit of %d repositories.
|
||||
form.reach_limit_of_creation=De eigenaar heeft maximale creatie limiet van %d repositories bereikt.
|
||||
form.name_reserved=Repositorienaam '%s' is gereserveerd.
|
||||
form.name_pattern_not_allowed=Repositorie naampatroon '%s' is niet toegestaan.
|
||||
|
||||
@@ -371,16 +375,16 @@ migrate_type_helper=Deze repositorie zal een <span class="text blue">mirror</spa
|
||||
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.permission_denied=You are not allowed to import local repositories.
|
||||
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=Migration failed: %v
|
||||
migrate.failed=Migratie is mislukt: %v
|
||||
|
||||
mirror_from=mirror from
|
||||
mirror_from=spiegel van
|
||||
forked_from=geforked van
|
||||
fork_from_self=U kunt geen repository forken die u al beheert!
|
||||
copy_link=Kopieer
|
||||
copy_link_success=Copied!
|
||||
copy_link_error=Press ⌘-C or Ctrl-C to copy
|
||||
copy_link_success=Gekopieerd!
|
||||
copy_link_error=Druk op ⌘-C of Ctrl-C om te kopiëren
|
||||
copied=Gekopieerd
|
||||
unwatch=Negeren
|
||||
watch=Volgen
|
||||
@@ -393,12 +397,12 @@ quick_guide=Snelstart gids
|
||||
clone_this_repo=Kloon deze repositorie
|
||||
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=This repository is empty, please come back later!
|
||||
repo_is_empty=Deze repositories is leeg is, probeer het later opnieuw!
|
||||
|
||||
code=Code
|
||||
branch=Aftakking
|
||||
tree=Boom
|
||||
filter_branch_and_tag=Filter branch or tag
|
||||
filter_branch_and_tag=Filter branch of tag
|
||||
branches=Aftakkingen
|
||||
tags=Labels
|
||||
issues=Kwesties
|
||||
@@ -492,8 +496,9 @@ issues.label_modify=Wijzig label
|
||||
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
|
||||
|
||||
pulls.new=New Pull Request
|
||||
pulls.new=Nieuwe Pull aanvraag
|
||||
pulls.compare_changes=Vergelijk veranderingen
|
||||
pulls.compare_changes_desc=Vergelijk twee vertakkingen en maak een pull verzoek voor wijzigingen.
|
||||
pulls.compare_base=base
|
||||
@@ -504,16 +509,16 @@ pulls.nothing_to_compare=Er is niets te vergelijken omdat base en head branches
|
||||
pulls.has_pull_request=' Er is al een pull-aanvraag tussen deze twee targets: <a href="%[1]s/pulls/%[3]d"> %[2]s #% [3]d</a>'
|
||||
pulls.create=Pull verzoek aanmaken
|
||||
pulls.title_desc=wil %[1]d commits van <code>%[2]s</code> samenvoegen met <code>%[3]s</code>
|
||||
pulls.merged_title_desc=merged %[1]d commits from <code>%[2]s</code> into <code>%[3]s</code> %[4]s
|
||||
pulls.merged_title_desc=%[1] commits samengevoegd van <code>%[2]s</code> naar <code>%[3]s</code> %[4]s
|
||||
pulls.tab_conversation=Discussie
|
||||
pulls.tab_commits=Commits
|
||||
pulls.tab_files=Bestanden gewijzigd
|
||||
pulls.reopen_to_merge=Please reopen this pull request to perform merge operation.
|
||||
pulls.merged=Merged
|
||||
pulls.has_merged=This pull request has been merged successfully!
|
||||
pulls.reopen_to_merge=Heropen deze pull request aub om een een merge actie uit te voeren.
|
||||
pulls.merged=Samengevoegd
|
||||
pulls.has_merged=Dit pull-request is samengevoegd!
|
||||
pulls.data_broken=Data of this pull request has been broken due to deletion of fork information.
|
||||
pulls.is_checking=The conflict checking is still in progress, please refresh page in few moments.
|
||||
pulls.can_auto_merge_desc=This pull request can be merged automatically.
|
||||
pulls.is_checking=Controle van conflicten is nog bezig, ververs deze pagina in enkele ogenblikken.
|
||||
pulls.can_auto_merge_desc=Dit pull-request kan automatisch samengevoegd worden.
|
||||
pulls.cannot_auto_merge_desc=This pull request can't be merged automatically because there are conflicts.
|
||||
pulls.cannot_auto_merge_helper=Please merge manually in order to resolve the conflicts.
|
||||
pulls.merge_pull_request=Samenvoegen van pull verzoek
|
||||
@@ -544,17 +549,17 @@ milestones.deletion_desc=Het verwijderen van dit label zal alle informatie in de
|
||||
milestones.deletion_success=Mijlpaal is met succes verwijderd!
|
||||
|
||||
wiki=Wiki
|
||||
wiki.welcome=Welcome to Wiki!
|
||||
wiki.welcome=Welkom op de Wiki!
|
||||
wiki.welcome_desc=Wiki is the place where you would like to document your project together and make it better.
|
||||
wiki.create_first_page=Create the first page
|
||||
wiki.page=Page
|
||||
wiki.filter_page=Filter page
|
||||
wiki.new_page=Create New Page
|
||||
wiki.default_commit_message=Write a note about this update (optional).
|
||||
wiki.save_page=Save Page
|
||||
wiki.last_commit_info=%s edited this page %s
|
||||
wiki.edit_page_button=Edit
|
||||
wiki.new_page_button=New Page
|
||||
wiki.create_first_page=Maak de eerste pagina
|
||||
wiki.page=Pagina
|
||||
wiki.filter_page=Filter pagina
|
||||
wiki.new_page=Maak nieuwe pagina
|
||||
wiki.default_commit_message=Schrijf een notitie over deze aanpassing (optioneel).
|
||||
wiki.save_page=Pagina opslaan
|
||||
wiki.last_commit_info=%s heeft deze pagina aangepast %s
|
||||
wiki.edit_page_button=Bewerken
|
||||
wiki.new_page_button=Nieuwe pagina
|
||||
wiki.page_already_exists=Wiki page with same name already exists.
|
||||
wiki.pages=Pages
|
||||
wiki.last_updated=Last updated %s
|
||||
@@ -568,7 +573,7 @@ settings.basic_settings=Basis instellingen
|
||||
settings.site=Officiële site
|
||||
settings.update_settings=Instellingen bewerken
|
||||
settings.change_reponame_prompt=This change will affect how links relate to the repository.
|
||||
settings.advanced_settings=Advanced Settings
|
||||
settings.advanced_settings=Geavanceerde opties
|
||||
settings.wiki_desc=Enable wiki to allow people write documents
|
||||
settings.use_external_wiki=Use external wiki
|
||||
settings.external_wiki_url=External Wiki URL
|
||||
@@ -579,20 +584,25 @@ settings.tracker_url_format=External Issue Tracker URL Format
|
||||
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=Gevaren zone
|
||||
settings.new_owner_has_same_repo=De nieuwe eigenaar heeft al een repositorie met deze naam
|
||||
settings.convert=Convert To Regular Repository
|
||||
settings.convert_desc=You can convert this mirror to a regular repository. This cannot be reversed.
|
||||
settings.convert_notices_1=- This operation will convert this repository mirror into a regular repository and cannot be undone.
|
||||
settings.convert_confirm=Confirm Conversion
|
||||
settings.convert_succeed=Repository has been converted to regular type successfully.
|
||||
settings.transfer=Eigendom overdragen
|
||||
settings.transfer_desc=Draag deze repo over aan een andere gebruiker of een organisatie waar u beheerders rechten heeft.
|
||||
settings.new_owner_has_same_repo=De nieuwe eigenaar heeft al een repositorie met deze naam
|
||||
settings.delete=Verwijder deze repositorie
|
||||
settings.delete_desc=Als u eenmaal een repositorie verwijderd is er geen weg terug. Gelieve zeker te zijn van uw acties.
|
||||
settings.transfer_notices_1=- You will lose access if new owner is a individual user.
|
||||
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=Please enter following information to confirm your operation:
|
||||
settings.delete=Verwijder deze repositorie
|
||||
settings.delete_desc=Als u eenmaal een repositorie verwijderd is er geen weg terug. Gelieve zeker te zijn van uw acties.
|
||||
settings.delete_notices_1=- This operation <strong>CANNOT</strong> be undone.
|
||||
settings.delete_notices_2=- This operation will permanently delete the everything of this repository, including Git data, issues, comments and accesses of collaborators.
|
||||
settings.delete_notices_fork_1=- If this repository is public, all forks will be became independent after deletion.
|
||||
settings.delete_notices_fork_1=- If this repository is public, all forks will become independent after deletion.
|
||||
settings.delete_notices_fork_2=- If this repository is private, all forks will be removed at the same time.
|
||||
settings.delete_notices_fork_3=- If you want to keep all forks after deletion, please change visibility of this repository to public first.
|
||||
settings.deletion_success=Repository has been deleted successfully!
|
||||
settings.deletion_success=Repository is succesvol verwijderd!
|
||||
settings.update_settings_success=Repositorie instellingen zijn succesvol bijgewerkt.
|
||||
settings.transfer_owner=Nieuwe eigenaar
|
||||
settings.make_transfer=Maak overdracht
|
||||
@@ -601,7 +611,8 @@ settings.confirm_delete=Bevestig verwijdering
|
||||
settings.add_collaborator=Nieuwe medewerker toevoegen
|
||||
settings.add_collaborator_success=medewerker is toegevoegd.
|
||||
settings.remove_collaborator_success=medewerker is verwijderd.
|
||||
settings.search_user_placeholder=Search user...
|
||||
settings.search_user_placeholder=Zoek gebruiker...
|
||||
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member=Gebruiker is lid van de organisatie die als een medewerker kan niet worden toegevoegd.
|
||||
settings.add_webhook=Webhook toevoegen
|
||||
settings.hooks_desc=Webhooks dat de externe diensten om kennisgevingen te ontvangen wanneer bepaalde gebeurtenissen op Gogs plaatsvinden. Wanneer de opgegeven gebeurtenissen plaatsvinden, sturen we een POST-aanvraag naar elk van de URL's die u opgeeft. Meer informatie vindt u in onze <a target="_blank" href="%s"> Webhooks gids</a>.
|
||||
@@ -610,7 +621,7 @@ settings.webhook_deletion_desc=Delete this webhook will remove its information a
|
||||
settings.webhook_deletion_success=Webhook has been deleted successfully!
|
||||
settings.webhook.test_delivery=Test Delivery
|
||||
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
|
||||
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
|
||||
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may take few seconds before it shows up in the delivery history.
|
||||
settings.webhook.request=Verzoek
|
||||
settings.webhook.response=Antwoord
|
||||
settings.webhook.headers=Headers
|
||||
@@ -650,7 +661,7 @@ settings.slack_domain=Slack domein
|
||||
settings.slack_channel=Slack kanaal
|
||||
settings.deploy_keys=Installeer sleutels
|
||||
settings.add_deploy_key=Toevoegen deploy sleutel
|
||||
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
|
||||
settings.deploy_key_desc=Deploy keys have read-only access. They are not the same as personal account SSH keys.
|
||||
settings.no_deploy_keys=U hebt nog geen deploy sleutels toegevoegd.
|
||||
settings.title=Titel
|
||||
settings.deploy_key_content=Inhoud
|
||||
@@ -666,6 +677,8 @@ diff.parent=bovenliggende
|
||||
diff.commit=commit
|
||||
diff.data_not_available=Diff gegevens niet beschikbaar.
|
||||
diff.show_diff_stats=Toon Diff Stats
|
||||
diff.show_split_view=Split View
|
||||
diff.show_unified_view=Unified View
|
||||
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
|
||||
@@ -683,7 +696,7 @@ release.edit_subheader=Detailed change log can help users understand what has be
|
||||
release.tag_name=Tagnaam
|
||||
release.target=Doel
|
||||
release.tag_helper=Kies een bestaande tag, of creëer een nieuwe tag bij publiceren.
|
||||
release.title=Title
|
||||
release.title=Titel
|
||||
release.content=Content
|
||||
release.write=Schrijf
|
||||
release.preview=Voorbeeld
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys=Herschrijf '.ssh/authorized_keys' (Let op: alle sle
|
||||
dashboard.resync_all_sshkeys_success=Alle publieke sleutels zijn herschreven.
|
||||
dashboard.resync_all_update_hooks=Herschrijf alle repositorie-hooks (nodig als de configuratie bestandslocatie is gewijzigd)
|
||||
dashboard.resync_all_update_hooks_success=Alle repositorie-hooks zijn herschreven.
|
||||
dashboard.reinit_missing_repos=Reinitialize all repository records that lost Git files
|
||||
dashboard.reinit_missing_repos_success=All repository records that lost Git files have been reinitialized successfully.
|
||||
|
||||
dashboard.server_uptime=Uptime server
|
||||
dashboard.current_goroutine=Huidige Goroutines
|
||||
@@ -907,6 +922,7 @@ auths.attribute_username_placeholder=Leave empty to use sign-in form field value
|
||||
auths.attribute_name=Voornaam attribuut
|
||||
auths.attribute_surname=Achternaam attribuut
|
||||
auths.attribute_mail=E-mail attribuut
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
auths.filter=User Filter
|
||||
auths.admin_filter=Admin Filter
|
||||
auths.ms_ad_sa=MS Ad SA
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm=E-mailbevestiging registreren
|
||||
config.disable_register=Registratie uitgeschakeld
|
||||
config.show_registration_button=Registeren knop weergeven
|
||||
config.require_sign_in_view=Inloggen vereist om te kunnen inzien
|
||||
config.enable_cache_avatar=Avatar Cache inschakelen
|
||||
config.mail_notify=E-mailnotificaties
|
||||
config.disable_key_size_check=Disable Minimum Key Size Check
|
||||
config.enable_captcha=Enable Captcha
|
||||
@@ -1025,6 +1040,8 @@ create_repo=repositorie aangemaakt in <a href="%s">%s</a>
|
||||
rename_repo=renamed repository from <code>%[1]s</code> to <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=push update naar <a href="%[1]s/src/%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`opende issue in <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue=`closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`created pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`reactie op issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`merged pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
|
||||
@@ -38,7 +38,7 @@ settings=Ustawienia
|
||||
your_profile=Twój profil
|
||||
your_settings=Twoje ustawienia
|
||||
|
||||
news_feed=Kanał aktualności
|
||||
activities=Activities
|
||||
pull_requests=Oczekujące zmiany
|
||||
issues=Problemy
|
||||
|
||||
@@ -65,7 +65,7 @@ db_name=Nazwa bazy danych
|
||||
db_helper=Proszę użyć silnika INNODB z kodowaniem utf8_general_ci dla MySQL.
|
||||
ssl_mode=Tryb SSL
|
||||
path=Ścieżka
|
||||
sqlite_helper=Ścieżka do pliku bazy danych SQLite3 lub TiDB.
|
||||
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 "-".
|
||||
no_admin_and_disable_registration=Rejestracji nie można wyłączyć bez tworzenia konta admina.
|
||||
@@ -86,6 +86,8 @@ http_port=Port HTTP
|
||||
http_port_helper=Numer portu na którym aplikacja jest dostępna.
|
||||
app_url=Adres URL aplikacji
|
||||
app_url_helper=To wpłynie na adresy klonowania HTTP/HTTPS i w wiadomościach e-mail.
|
||||
log_root_path=Log Path
|
||||
log_root_path_helper=Directory to write log files to.
|
||||
|
||||
optional_title=Ustawienia opcjonalne
|
||||
email_title=Ustawienia serwera e-mail
|
||||
@@ -122,6 +124,7 @@ run_user_not_match=Użytkownik aplikacji nie jest aktualnym użytkownikiem: %s -
|
||||
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.
|
||||
invalid_log_root_path=Log root path is invalid: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Nazwa użytkownika lub e-mail
|
||||
@@ -133,7 +136,7 @@ my_orgs=Moje organizacje
|
||||
my_mirrors=Moje kopie lustrzane
|
||||
view_home=Zobacz %s
|
||||
|
||||
issues.in_your_repos=W twoich repozytoriach
|
||||
issues.in_your_repos=W Twoich repozytoriach
|
||||
|
||||
[explore]
|
||||
repos=Repozytoria
|
||||
@@ -156,7 +159,7 @@ 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.
|
||||
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.
|
||||
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken=Nazwa repozytorium jest już zajęta.
|
||||
org_name_been_taken=Nazwa organizacji jest już zajęta.
|
||||
team_name_been_taken=Nazwa zespołu jest już zajęta.
|
||||
email_been_used=Adres e-mail jest już zarejestrowany.
|
||||
illegal_team_name=Nazwa zespołu zawiera niedozwolone znaki.
|
||||
username_password_incorrect=Nazwa użytkownika lub hasło nie jest prawidłowe.
|
||||
enterred_invalid_repo_name=Upewnij się, że wprowadzona nazwa repozytorium jest poprawna.
|
||||
enterred_invalid_owner_name=Upewnij się, że nazwa właściciela repozytorium jest poprawna.
|
||||
@@ -211,8 +213,8 @@ enterred_invalid_password=Proszę upewnij się, że wprowadzono hasło jest popr
|
||||
user_not_exist=Podany użytkownik nie istnieje.
|
||||
last_org_owner=Usuwany użytkownik jest ostatnim członkiem ekipy właścicieli. Musi być inny właściciel.
|
||||
|
||||
invalid_ssh_key=Niestety, nie jesteśmy stanie zweryfikować twojego klucza SSH: %s
|
||||
unable_verify_ssh_key=Gogs nie może zweryfikować twojego klucza SSH, ale zakładamy, że jest poprawny, proszę sprawdź to samodzielnie.
|
||||
invalid_ssh_key=Niestety, nie jesteśmy stanie zweryfikować Twojego klucza SSH: %s
|
||||
unable_verify_ssh_key=Gogs nie może zweryfikować Twojego klucza SSH, ale zakładamy, że jest poprawny, proszę sprawdź to samodzielnie.
|
||||
auth_failed=Uwierzytelnianie nie powiodło się: %v
|
||||
|
||||
still_own_repo=Twoje konto dalej posiada przynajmniej jedno repozytorium, które musisz usunąć lub przekazać.
|
||||
@@ -232,6 +234,8 @@ activity=Publiczna aktywność
|
||||
followers=Obserwujący
|
||||
starred=Polubionych
|
||||
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.
|
||||
@@ -301,7 +305,7 @@ key_content=Treść
|
||||
add_key_success=Pomyślnie dodano nowy klucz SSH '%s'!
|
||||
delete_key=Usuń
|
||||
ssh_key_deletion=Usunięcie klucza SSH
|
||||
ssh_key_deletion_desc=Usunięcie tego klucza SSH będzie skutkować usunięciem wszystkich powiązanych dostępów do twojego konta. Czy chcesz kontynuować?
|
||||
ssh_key_deletion_desc=Usunięcie tego klucza SSH będzie skutkować usunięciem wszystkich powiązanych dostępów do Twojego konta. Czy chcesz kontynuować?
|
||||
ssh_key_deletion_success=Klucz SSH został usunięty pomyślnie!
|
||||
add_on=Dodano
|
||||
last_used=Ostatnio użyto
|
||||
@@ -492,6 +496,7 @@ issues.label_modify=Modyfikacja etykiety
|
||||
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
|
||||
|
||||
pulls.new=Nowy pull request
|
||||
pulls.compare_changes=Porównaj zmiany
|
||||
@@ -579,14 +584,19 @@ settings.tracker_url_format=Format dla adresu URL zewnętrznego systemu
|
||||
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
|
||||
settings.new_owner_has_same_repo=Nowy właściciel już posiada repozytorium o tej samej nazwie.
|
||||
settings.convert=Convert To Regular Repository
|
||||
settings.convert_desc=You can convert this mirror to a regular repository. This cannot be reversed.
|
||||
settings.convert_notices_1=- This operation will convert this repository mirror into a regular repository and cannot be undone.
|
||||
settings.convert_confirm=Confirm Conversion
|
||||
settings.convert_succeed=Repository has been converted to regular type successfully.
|
||||
settings.transfer=Przeniesienie własności
|
||||
settings.transfer_desc=Przenieś to repozytorium do innego użytkownika lub organizacji gdzie masz uprawnienia administratora.
|
||||
settings.new_owner_has_same_repo=Nowy właściciel już posiada repozytorium o tej samej nazwie.
|
||||
settings.delete=Usuń to repozytorium
|
||||
settings.delete_desc=Po usunięciu repozytorium nie ma odwrotu. Upewnij się, że tego chcesz.
|
||||
settings.transfer_notices_1=- Stracisz dostęp jeśli nowy właściciel jest indywidualnym użytkownikiem.
|
||||
settings.transfer_notices_2=- Zachowasz dostęp jeśli nowym właścicielem jest organizacja, której jesteś współwłaścicielem.
|
||||
settings.transfer_form_title=Proszę wpisz co następuje w celu potwierdzenia operacji:
|
||||
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=- Jeśli to repozytorium jest publiczne, wszystkie forki staną się niezależne.
|
||||
@@ -602,6 +612,7 @@ settings.add_collaborator=Dodaj nowego współpracownika
|
||||
settings.add_collaborator_success=Został dodany nowy współpracownik.
|
||||
settings.remove_collaborator_success=Współpracownik został usunięty.
|
||||
settings.search_user_placeholder=Szukaj użytkownika...
|
||||
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member=Użytkownik jest członkiem organizacji, który nie może być dodany jako współpracownik.
|
||||
settings.add_webhook=Dodaj webhooka
|
||||
settings.hooks_desc=Webooki działają tak jak proste wywołania HTTP POST. Jeśli cokolwiek zdarzy się w Gogs, wyślemy powiadomienie do wybranego hosta. Więcej informacji można znaleźć w <a target="_blank" href="%s">przewodniku webhooków</a>.
|
||||
@@ -666,6 +677,8 @@ diff.parent=rodzic
|
||||
diff.commit=commit
|
||||
diff.data_not_available=Informacje nt. zmiany nie są dostępne.
|
||||
diff.show_diff_stats=Pokaż statystyki zmian
|
||||
diff.show_split_view=Widok podzielony
|
||||
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
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys=Przeładuj klucze publiczne w pliku '.ssh/authorize
|
||||
dashboard.resync_all_sshkeys_success=Przeładowanie kluczy publicznych zakończyło się sukcesem.
|
||||
dashboard.resync_all_update_hooks=Przepisz pliki update hook repozytoriów (wymagane przy zmianie ścieżki do pliku konfiguracji)
|
||||
dashboard.resync_all_update_hooks_success=Wszystkie pliki update hook repozytoriów zostały pomyślnie przepisane.
|
||||
dashboard.reinit_missing_repos=Ponownie inicjalizuj wszystkie repozytoria, które straciły pliki Git
|
||||
dashboard.reinit_missing_repos_success=Wszystkie repozytoria, które straciły pliki Git, zostały ponownie zainicjować pomyślnie.
|
||||
|
||||
dashboard.server_uptime=Uptime serwera
|
||||
dashboard.current_goroutine=Bieżące Goroutines
|
||||
@@ -907,6 +922,7 @@ auths.attribute_username_placeholder=Zostaw puste aby użyć wartości podanej p
|
||||
auths.attribute_name=Atrybut imienia
|
||||
auths.attribute_surname=Atrybut nazwiska
|
||||
auths.attribute_mail=Atrybut e-mail
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
auths.filter=Filtr użytkownika
|
||||
auths.admin_filter=Filtr administratora
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm=Wymagaj potwierdzenia e-mail
|
||||
config.disable_register=Wyłącz rejestrację
|
||||
config.show_registration_button=Pokazuj przycisk rejestracji
|
||||
config.require_sign_in_view=Wymagaj bycia zalogowanym
|
||||
config.enable_cache_avatar=Włącz cache awatarów
|
||||
config.mail_notify=Powiadomienia e-mail
|
||||
config.disable_key_size_check=Wyłącz sprawdzanie minimalnego rozmiaru klucza
|
||||
config.enable_captcha=Włącz Captcha
|
||||
@@ -1025,6 +1040,8 @@ create_repo=tworzy repozytorium <a href="%s">%s</a>
|
||||
rename_repo=zmienia nazwę repozytorium <code>%[1]s</code> na <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=wypycha do <a href="%[1]s/src/%[2]s">%[3]s</a> w <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`zgłasza problem <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue=`closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`tworzy pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`komentuje problem <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`scala pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
|
||||
@@ -28,7 +28,7 @@ organization=Organização
|
||||
mirror=Espelho
|
||||
new_repo=Novo Repositório
|
||||
new_migrate=Nova Migração
|
||||
new_mirror=New Mirror
|
||||
new_mirror=Novo espelho
|
||||
new_fork=Novo Fork de Repositório
|
||||
new_org=Nova Organização
|
||||
manage_org=Gerenciar Organizações
|
||||
@@ -38,8 +38,8 @@ settings=Configurações
|
||||
your_profile=Seu perfil
|
||||
your_settings=Suas configurações
|
||||
|
||||
news_feed=Feed de Notícias
|
||||
pull_requests=Solicitações de Pull
|
||||
activities=Atividades
|
||||
pull_requests=Pull Requests
|
||||
issues=Problemas
|
||||
|
||||
cancel=Cancelar
|
||||
@@ -53,30 +53,30 @@ code=Código
|
||||
|
||||
[install]
|
||||
install=Instalação
|
||||
title=Etapas de instalação para Primeira Execução
|
||||
title=Etapas de instalação para primeira execução
|
||||
docker_helper=Se você está rodando o Gogs dentro do Docker, por favor leia os <a target="_blank" href="%s">Guias</a> cuidadosamente antes de mudar qualquer coisa nesta página!
|
||||
requite_db_desc=Gogs requer MySQL, PostgreSQL, SQLite3 ou TiDB.
|
||||
db_title=Configurações de Banco de Dados
|
||||
db_type=Tipo do Banco de Dados
|
||||
db_type=Banco de bados
|
||||
host=Host
|
||||
user=Usuário
|
||||
password=Senha
|
||||
db_name=Nome do Banco de Dados
|
||||
db_name=Nome do banco de dados
|
||||
db_helper=Por favor, use o mecanismo INNODB com o conjunto de caracteres utf8_general_ci para MySQL.
|
||||
ssl_mode=Modo SSL
|
||||
path=Caminho
|
||||
sqlite_helper=O caminho do arquivo do banco de dados SQLite3 ou TiDB.
|
||||
sqlite_helper=O caminho do arquivo de banco de dados SQLite3 ou TiDB. <br>Por favor use o caminho absoluto quando você iniciar como serviço.
|
||||
err_empty_db_path=O Caminho do banco de dados SQLite3 ou TiDB não pode ser vazio.
|
||||
err_invalid_tidb_name=Nome do banco de dados TiDB não permite os caracteres "." e "-".
|
||||
no_admin_and_disable_registration=Você não pode desabilitar o registro sem criar uma conta de administrador.
|
||||
err_empty_admin_password=A senha de administrador não pode ser vazia.
|
||||
|
||||
general_title=Configurações Gerais do Gogs
|
||||
app_name=Nome do Aplicativo
|
||||
general_title=Configurações gerais do Gogs
|
||||
app_name=Nome do aplicativo
|
||||
app_name_helper=Coloque o nome da sua organização aqui!
|
||||
repo_path=Caminho da Raiz do Repositório
|
||||
repo_path=Caminho da raíz do repositório
|
||||
repo_path_helper=Todos os repositórios remotos do Git serão salvos neste diretório.
|
||||
run_user=Executar Usuário
|
||||
run_user=Usuário da execução
|
||||
run_user_helper=O usuário deve ter acesso ao caminho raiz do repositório e executar o Gogs
|
||||
domain=Domínio
|
||||
domain_helper=Isto afeta URLs para clonagem via SSH.
|
||||
@@ -84,35 +84,37 @@ ssh_port=Porta SSH
|
||||
ssh_port_helper=Número da porta que seu servidor SSH está usando, deixe vazio para desativar o recurso SSH.
|
||||
http_port=Porta HTTP
|
||||
http_port_helper=Número da porta em que a aplicação irá executar.
|
||||
app_url=URL do Aplicativo
|
||||
app_url=URL do aplicativo
|
||||
app_url_helper=Isto afeta a URL de clonagem via HTTP/HTTPs e também o email.
|
||||
log_root_path=Caminho do log
|
||||
log_root_path_helper=Pasta dos arquivos de log.
|
||||
|
||||
optional_title=Configurações Opcionais
|
||||
email_title=Configurações do Serviço de E-mail
|
||||
optional_title=Configurações opcionais
|
||||
email_title=Configurações do serviço de e-mail
|
||||
smtp_host=Host SMTP
|
||||
smtp_from=De
|
||||
smtp_from=De
|
||||
smtp_from_helper=O endereço de email deve atender a especificação RFC 5322. O formato deve ser um email ou "Nome" <email@example.com>.
|
||||
mailer_user=E-mail do Remetente
|
||||
mailer_password=Senha do Remetente
|
||||
register_confirm=Habilitar Confirmação de Registro
|
||||
mail_notify=Habilitar Notificação de Correio
|
||||
server_service_title=Configurações de Servidor e Outros Serviços
|
||||
offline_mode=Ativar Modo Offline
|
||||
mailer_user=E-mail do remetente
|
||||
mailer_password=Senha do remetente
|
||||
register_confirm=Habilitar confirmação de registro
|
||||
mail_notify=Habilitar notificação de e-mail
|
||||
server_service_title=Configurações de servidor e outros serviços
|
||||
offline_mode=Ativar modo off-line
|
||||
offline_mode_popup=Desative o CDN mesmo em modo de produção, todos os recursos serão disponibilizados localmente.
|
||||
disable_gravatar=Desativar Serviço Gravatar
|
||||
disable_gravatar=Desativar serviço Gravatar
|
||||
disable_gravatar_popup=Desabilitar o Gravatar e fontes personalizadas, todos os avatares são enviados por usuários ou padrão.
|
||||
disable_registration=Desativar auto-registro
|
||||
disable_registration_popup=Desativar o auto-registro de usuário, para que somente o administrador possa criar contas.
|
||||
enable_captcha=Habilitar Captcha
|
||||
enable_captcha=Habilitar captcha
|
||||
enable_captcha_popup=Obrigar validação por captcha para auto-registro de usuários.
|
||||
require_sign_in_view=Requerer login para a visualização de páginas
|
||||
require_sign_in_view=Obrigar login para a visualização de páginas
|
||||
require_sign_in_view_popup=Somente usuários autenticados podem ver todas as páginas, visitantes somente podem entrar ou se cadastrar.
|
||||
admin_setting_desc=Você não precisa criar uma conta de administrador agora, no entanto o primeiro usuário (ID=1) automaticamente terá acesso de administrador.
|
||||
admin_title=Configurações da Conta de Administrador
|
||||
admin_name=Nome de Usuário
|
||||
admin_title=Configurações da conta de administrador
|
||||
admin_name=Nome de usuário
|
||||
admin_password=Senha
|
||||
confirm_password=Confirmar Senha
|
||||
admin_email=E-mail do Administrador
|
||||
confirm_password=Confirmar senha
|
||||
admin_email=E-mail do administrador
|
||||
install_gogs=Instalar Gogs
|
||||
test_git_failed=Falha ao testar o comando 'git': %v
|
||||
sqlite3_not_available=Sua versão não suporta SQLite3, por favor faça o download da versão binária oficial em %s, NÃO da versão gobuild.
|
||||
@@ -122,6 +124,7 @@ run_user_not_match=O usuário da execução não é o usuário atual: %s -> %s
|
||||
save_config_failed=Falha ao salvar a configuração: %v
|
||||
invalid_admin_setting=Configuração da conta de administrador está inválida: %v
|
||||
install_success=Bem-vindo! Estamos contentes que você escolheu o Gogs, divirta-se e tenha cuidado.
|
||||
invalid_log_root_path=Pasta raíz do log é inválida: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Nome de Usuário ou E-mail
|
||||
@@ -188,7 +191,7 @@ AdminEmail=E-mail do Administrador
|
||||
require_error=` não pode estar vazio.`
|
||||
alpha_dash_error=` devem ser caracteres alfanuméricos ou hífen (-) ou sublinhado (_).`
|
||||
alpha_dash_dot_error=` devem ser caracteres alfanuméricos ou hífen (-) ou sublinhado (_).`
|
||||
size_error='deve ser o tamanho %s.'
|
||||
size_error=`deve ser do tamanho %s.`
|
||||
min_size_error=` deve conter pelo menos %s caracteres.`
|
||||
max_size_error=` deve conter no máximo %s caracteres.`
|
||||
email_error=` não é um endereço de e-mail válido.`
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken=Nome do repositório já foi tomado.
|
||||
org_name_been_taken=Nome da organização já foi tomado.
|
||||
team_name_been_taken=Nome da equipe já foi tomado.
|
||||
email_been_used=Endereço de e-mail já foi usado.
|
||||
illegal_team_name=O nome da equipe contém caracteres não permitidos.
|
||||
username_password_incorrect=Usuário ou senha incorretos.
|
||||
enterred_invalid_repo_name=Por favor certifique-se que informou o nome do repositório corretamente.
|
||||
enterred_invalid_owner_name=Por favor, verifique se o nome do proprietário está correto.
|
||||
@@ -232,6 +234,8 @@ activity=Atividade Pública
|
||||
followers=Seguidores
|
||||
starred=Favorito
|
||||
following=Seguindo
|
||||
follow=Seguir
|
||||
unfollow=Deixar de seguir
|
||||
|
||||
form.name_reserved=O nome de usuário '%s' não pode ser usado.
|
||||
form.name_pattern_not_allowed=Não é permitido usar o padrão '%s' para o nome de usuário.
|
||||
@@ -248,7 +252,7 @@ uid=Uid
|
||||
|
||||
public_profile=Perfil Público
|
||||
profile_desc=Seu endereço de E-mail é publico e será usado para qualquer notificação relacionada à conta, e qualquer operação na web feita através do site.
|
||||
password_username_disabled=Non-local type users are not allowed to change their username.
|
||||
password_username_disabled=Usuários do tipo não-local não são permitidos de mudarem seu nome de usuário.
|
||||
full_name=Nome Completo
|
||||
website=Site
|
||||
location=Localização
|
||||
@@ -273,7 +277,7 @@ new_password=Nova Senha
|
||||
retype_new_password=Digite novamente a nova senha
|
||||
password_incorrect=A senha atual não está correta.
|
||||
change_password_success=A senha está alterada com sucesso. Você pode agora entrar com a senha nova.
|
||||
password_change_disabled=Non-local type users are not allowed to change their password.
|
||||
password_change_disabled=Usuários do tipo não-local não são permitidos de mudarem sua senha.
|
||||
|
||||
emails=Endereços de E-mail
|
||||
manage_emails=Gerenciar endereços de e-mail
|
||||
@@ -361,7 +365,7 @@ watchers=Observadores
|
||||
stargazers=Usuários que estrelaram
|
||||
forks=Forks
|
||||
|
||||
form.reach_limit_of_creation=The owner has reached maximum creation limit of %d repositories.
|
||||
form.reach_limit_of_creation=O proprietário atingiu o limite máximo de criação de repositórios de %d.
|
||||
form.name_reserved=O nome de repositório '%s' não pode ser usado.
|
||||
form.name_pattern_not_allowed=Não é permitido usar o padrão '%s' para o nome de repositório.
|
||||
|
||||
@@ -492,6 +496,7 @@ issues.label_modify=Alteração de etiqueta
|
||||
issues.label_deletion=Exclusão de etiqueta
|
||||
issues.label_deletion_desc=Excluir uma etiqueta a retirará de todos os problemas que ela estiver marcando. Quer mesmo continuar?
|
||||
issues.label_deletion_success=A etiqueta foi excluída com sucesso!
|
||||
issues.num_participants=%d participantes
|
||||
|
||||
pulls.new=Novo Pull Request
|
||||
pulls.compare_changes=Comparar mudanças
|
||||
@@ -513,11 +518,11 @@ pulls.merged=Merge realizado
|
||||
pulls.has_merged=Este pull request foi mesclado com sucesso!
|
||||
pulls.data_broken=Dados deste pull request foram quebrados devido à deleção de informação do fork.
|
||||
pulls.is_checking=A verificação do conflito ainda está em progresso, por favor recarregue a página em instantes.
|
||||
pulls.can_auto_merge_desc=This pull request can be merged automatically.
|
||||
pulls.cannot_auto_merge_desc=This pull request can't be merged automatically because there are conflicts.
|
||||
pulls.cannot_auto_merge_helper=Please merge manually in order to resolve the conflicts.
|
||||
pulls.can_auto_merge_desc=Este pull request pode ser mesclado automaticamente.
|
||||
pulls.cannot_auto_merge_desc=Este pull request não pode ser mesclado automaticamente pois há conflitos.
|
||||
pulls.cannot_auto_merge_helper=Por favor, mescle manualmente para resolver os conflitos.
|
||||
pulls.merge_pull_request=Merge Pull Request
|
||||
pulls.open_unmerged_pull_exists=' Você não pode executar a operação de reabrir porque já existe uma solicitação de pull aberta (#%d) do mesmo repositório com as mesmas informações de merge e está esperando pelo merge.'
|
||||
pulls.open_unmerged_pull_exists=`Você não pode executar a operação de reabrir porque já existe uma solicitação de pull aberta (#%d) do mesmo repositório com as mesmas informações de merge e está esperando pelo merge.`
|
||||
|
||||
milestones.new=Novo marco
|
||||
milestones.open_tab=%d abertos
|
||||
@@ -570,23 +575,28 @@ settings.update_settings=Configurações de Atualização
|
||||
settings.change_reponame_prompt=Este mudanças vai afetar os links para este repositório.
|
||||
settings.advanced_settings=Configurações avançadas
|
||||
settings.wiki_desc=Habilitar o wiki para permitir que as pessoas escrevam documentos
|
||||
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.use_external_wiki=Usar wiki externa
|
||||
settings.external_wiki_url=URL externa da wiki
|
||||
settings.external_wiki_url_desc=Os visitantes serão redirecionados para a URL quando clicarem na aba.
|
||||
settings.issues_desc=Habilitar gerenciamento de "problemas" nativo
|
||||
settings.use_external_issue_tracker=Usar issue tracker externo
|
||||
settings.tracker_url_format=Formato de URL do issue tracker externo
|
||||
settings.tracker_url_format_desc=Você pode usar o espaço reservado <code>{user} {repo} {index}</code> para o nome do usuário, índice de nome e a questão do repositório.
|
||||
settings.pulls_desc=Habilitar pull requests para aceitar contribuições públicas
|
||||
settings.danger_zone=Zona de Perigo
|
||||
settings.new_owner_has_same_repo=O novo dono já tem um repositório com o mesmo nome. Por favor, escolha outro nome.
|
||||
settings.convert=Converter para repositório tradicional
|
||||
settings.convert_desc=Você pode converter este espelho em um repositório tradicional. Esta ação não pode ser revertida.
|
||||
settings.convert_notices_1=- Esta operação vai converter este repositório espelho em um repositório tradicional. Esta ação não pode ser desfeita.
|
||||
settings.convert_confirm=Confirmar conversão
|
||||
settings.convert_succeed=Repositório espelho convertido para tradicional com sucesso.
|
||||
settings.transfer=Transferir Propriedade
|
||||
settings.transfer_desc=Transferir este repositório para outro usuário ou para uma organização onde você tem direitos de administrador.
|
||||
settings.new_owner_has_same_repo=O novo dono já tem um repositório com o mesmo nome. Por favor, escolha outro nome.
|
||||
settings.delete=Deletar Este Repositório
|
||||
settings.delete_desc=Uma vez que você deleta um repositório, não tem volta. Por favor, tenha certeza.
|
||||
settings.transfer_notices_1=- Você vai perder acesso se o novo dono for um usuário individual.
|
||||
settings.transfer_notices_2=- Você vai continuar tendo acesso se o novo dono é uma organização e você é um dos membros.
|
||||
settings.transfer_form_title=Informe a seguinte informação para confirmar a sua operação:
|
||||
settings.delete=Deletar Este Repositório
|
||||
settings.delete_desc=Uma vez que você deleta um repositório, não tem volta. Por favor, tenha certeza.
|
||||
settings.delete_notices_1=-Esta operação <strong>NÃO PODERÁ</strong> ser desfeita.
|
||||
settings.delete_notices_2=- Esta operação irá apagar permanentemente o tudo deste repositório, incluindo os dados do Git, problemas, comentários e acessos dos colaboradores.
|
||||
settings.delete_notices_fork_1=- Se este repositório é público, todos os forks se tornarão independentes após a deleção.
|
||||
@@ -602,6 +612,7 @@ settings.add_collaborator=Adicionar um Novo Colaborador
|
||||
settings.add_collaborator_success=O novo colaborador foi adicionado.
|
||||
settings.remove_collaborator_success=O colaborador foi removido.
|
||||
settings.search_user_placeholder=Pesquisar usuário...
|
||||
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member=O usuário é um membro da organização que não pode ser adicionado como um colaborador.
|
||||
settings.add_webhook=Adicionar Webhook
|
||||
settings.hooks_desc=Hooks da web ou Webhooks permitem serviços externos serem notificados quando certos eventos acontecem no Gogs. Quando acontecem os eventos especificados, enviaremos uma solicitação POST para cada uma das URLs que você fornecer. Saiba mais no nosso <a target="_blank" href="%s"> Guia de Webhooks</a>.
|
||||
@@ -666,6 +677,8 @@ diff.parent=pai
|
||||
diff.commit=commit
|
||||
diff.data_not_available=Dados de Diff não disponíveis.
|
||||
diff.show_diff_stats=Mostrar estatísticas do Diff
|
||||
diff.show_split_view=Visão dividida
|
||||
diff.show_unified_view=Visão unificada
|
||||
diff.stats_desc=<strong> %d arquivos alterados</strong> com <strong>%d adições</strong> e <strong>%d exclusões</strong>
|
||||
diff.bin=BIN
|
||||
diff.view_file=Ver Arquivo
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys=Reescrever o arquivo '.ssh/authorized_keys' (atenç
|
||||
dashboard.resync_all_sshkeys_success=Todas as chaves públicas foram reescritas com sucesso.
|
||||
dashboard.resync_all_update_hooks=Reescrever todos os hooks de atualização dos repositórios (necessário quando o caminho de configuração customizado é alterado)
|
||||
dashboard.resync_all_update_hooks_success=Os hooks de atualização de todos os repositórios foram reescritos com sucesso.
|
||||
dashboard.reinit_missing_repos=Reinicializar todos os registros de repositório que perderam os arquivos do Git
|
||||
dashboard.reinit_missing_repos_success=Todos os repositórios que perderam arquivos do Git foram reinicializados com sucesso.
|
||||
|
||||
dashboard.server_uptime=Servidor Ligado
|
||||
dashboard.current_goroutine=Goroutines Atuais
|
||||
@@ -861,8 +876,8 @@ users.auth_login_name=Nome de login da autenticação
|
||||
users.password_helper=Deixe em branco para não mudar.
|
||||
users.update_profile_success=O perfil da conta foi atualizado com sucesso.
|
||||
users.edit_account=Editar Conta
|
||||
users.max_repo_creation=Maximum Repository Creation Limit
|
||||
users.max_repo_creation_desc=(Set -1 to use global default limit)
|
||||
users.max_repo_creation=Limite máximo de criação de repositórios
|
||||
users.max_repo_creation_desc=(Use "-1" para utilizar o limite padrão)
|
||||
users.is_activated=Esta conta está ativada
|
||||
users.is_admin=Esta conta tem permissões de administrador
|
||||
users.allow_git_hook=Esta conta tem permissões para criar hooks do Git
|
||||
@@ -907,6 +922,7 @@ auths.attribute_username_placeholder=Deixe vazio para usar o valor do campo de f
|
||||
auths.attribute_name=Atributo primeiro nome
|
||||
auths.attribute_surname=Atributo sobrenome
|
||||
auths.attribute_mail=Atributo e-mail
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
auths.filter=Filtro de usuário
|
||||
auths.admin_filter=Filtro de administrador
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm=Requerer Confirmação de E-mail
|
||||
config.disable_register=Desabilitar Registro
|
||||
config.show_registration_button=Mostrar Botão de Registo
|
||||
config.require_sign_in_view=Requerer Entrar no Gogs para Ver
|
||||
config.enable_cache_avatar=Habilitar Cache de Avatar
|
||||
config.mail_notify=Notificação de Correio
|
||||
config.disable_key_size_check=Desativar verificação de tamanho mínimo da chave
|
||||
config.enable_captcha=Habilitar o Captcha
|
||||
@@ -1024,13 +1039,15 @@ notices.delete_success=Avisos do sistema foram excluídos com sucesso.
|
||||
create_repo=repositório criado <a href="%s"> %s</a>
|
||||
rename_repo=renomeou o o repositório <code>%[1]s</code> para <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=pushed para <a href="%[1]s/src/%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a>
|
||||
create_issue='questão aberta <a href="%s/issues/%s">%s#%[2]s</a>'
|
||||
create_issue=`questão aberta <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue=`closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`criou o pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue='comentou sobre a questão <a href="%s/issues/%s">%s#%[2]s</a>'
|
||||
comment_issue=`comentou sobre a questão <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`mesclou o pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
transfer_repo=repositório transferido de <code>%s</code> para <a href="%s">%s</a>
|
||||
push_tag=Foi feito push na tag <a href="%s/src/%s">%[2]s</a> para <a href="%[1]s">%[3]s</a>
|
||||
compare_commits=View comparison for these %d commits
|
||||
compare_commits=Ver comparação entre esses %d commits
|
||||
|
||||
[tool]
|
||||
ago=atrás
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
app_desc=Удобная служба для собственного Git-репозитория, написанная на языке Go
|
||||
|
||||
home=Главная
|
||||
dashboard=Панель мониторинга
|
||||
dashboard=Панель управления
|
||||
explore=Обзор
|
||||
help=Помощь
|
||||
sign_in=Войти
|
||||
sign_out=Выход
|
||||
sign_up=Регистрация
|
||||
register=Зарегистрироваться
|
||||
register=Регистрация
|
||||
website=Веб-сайт
|
||||
version=Версия
|
||||
page=Страница
|
||||
@@ -28,19 +28,19 @@ organization=Организация
|
||||
mirror=Зеркало
|
||||
new_repo=Новый репозиторий
|
||||
new_migrate=Новая Миграция
|
||||
new_mirror=New Mirror
|
||||
new_mirror=Новое зеркало
|
||||
new_fork=Новый проект из репозитория
|
||||
new_org=Новая Организация
|
||||
manage_org=Управление Организацией
|
||||
new_org=Новая организация
|
||||
manage_org=Управление организацией
|
||||
admin_panel=Панель администратора
|
||||
account_settings=Настройки аккаунта
|
||||
settings=Настройки
|
||||
your_profile=Ваш профиль
|
||||
your_settings=Ваши настройки
|
||||
|
||||
news_feed=Лента новостей
|
||||
pull_requests=Pull Requests
|
||||
issues=Вопросы
|
||||
activities=Активность
|
||||
pull_requests=Запросы на слияние
|
||||
issues=Задачи
|
||||
|
||||
cancel=Отмена
|
||||
|
||||
@@ -48,13 +48,13 @@ cancel=Отмена
|
||||
search=Поиск...
|
||||
repository=Репозиторий
|
||||
user=Пользователь
|
||||
issue=Проблема
|
||||
issue=Задача
|
||||
code=Код
|
||||
|
||||
[install]
|
||||
install=Установка
|
||||
title=Установочные шаги для первого запуска
|
||||
docker_helper=Если вы используете Gogs в Docker-контейнере, пожалуйста прочтите <a target="_blank" href="%s">эти советы</a>, перед тем как что-либо изменить!
|
||||
docker_helper=Если вы запускаете Gogs внутри Docker, пожалуйста прочтите <a target="_blank" href="%s">эти советы</a> внимательно перед тем как что-либо изменить на этой странице!
|
||||
requite_db_desc=Gogs требует MySQL, PostgreSQL, SQLite3 или TiDB.
|
||||
db_title=Настройки базы данных
|
||||
db_type=Тип базы данных
|
||||
@@ -65,17 +65,17 @@ db_name=Имя базы данных
|
||||
db_helper=Для MySQL используйте тип таблиц InnoDB с кодировкой utf8_general_ci.
|
||||
ssl_mode=Режим SSL
|
||||
path=Путь
|
||||
sqlite_helper=Путь до базы данных SQLite или TiDB.
|
||||
sqlite_helper=Путь к файлу базы данных SQLite3 или TiDB. <br>Укажите абсолютный путь при запуске в качестве службы.
|
||||
err_empty_db_path=Путь к базе данных SQLite3 или TiDB не может быть пустым.
|
||||
err_invalid_tidb_name=Название базы данных TiDB не может содержать символы "." и "-".
|
||||
no_admin_and_disable_registration=Вы не можете отключить регистрацию, не создав аккаунт администратора.
|
||||
err_invalid_tidb_name=Имя базы данных TiDB не может содержать символы "." и "-".
|
||||
no_admin_and_disable_registration=Вы не можете отключить регистрацию до создания учетной записи администратора.
|
||||
err_empty_admin_password=Пароль администратора не может быть пустым.
|
||||
|
||||
general_title=Общие параметры Gogs
|
||||
app_name=Имя приложения
|
||||
app_name_helper=Укажите здесь название вашей потрясающей организации!
|
||||
repo_path=Путь корня репозитория
|
||||
repo_path_helper=Все удаленные репозитории Git будут сохранены в этой директории.
|
||||
repo_path_helper=Все сетевые репозитории Git будут сохранены в этой директории.
|
||||
run_user=Пользователь
|
||||
run_user_helper=У пользователя должен быть доступ к пути к корню репозитория и к запуску Gogs.
|
||||
domain=Домен
|
||||
@@ -86,6 +86,8 @@ http_port=Порт HTTP
|
||||
http_port_helper=Номер порта, который приложение будет слушать.
|
||||
app_url=URL приложения
|
||||
app_url_helper=Этот параметр влияет на URL для клонирования по HTTP/HTTPS и на адреса в электронной почте.
|
||||
log_root_path=Путь к журналу
|
||||
log_root_path_helper=Каталог для записи файлов журнала.
|
||||
|
||||
optional_title=Расширенные настройки
|
||||
email_title=Настройки службы электронной почты
|
||||
@@ -122,6 +124,7 @@ run_user_not_match=Текущий пользователь не является
|
||||
save_config_failed=Не удалось сохранить конфигурацию: %v
|
||||
invalid_admin_setting=Указан недопустимый параметр учетной записи администратора: %v
|
||||
install_success=Добро пожаловать! Мы рады, что вы выбрали Gogs. Веселитесь и берегите себя.
|
||||
invalid_log_root_path=Недопустимый путь для логов: %v
|
||||
|
||||
[home]
|
||||
uname_holder=Имя пользователь или E-mail
|
||||
@@ -133,7 +136,7 @@ my_orgs=Моя Организация
|
||||
my_mirrors=Мои зеркала
|
||||
view_home=Показать %s
|
||||
|
||||
issues.in_your_repos=В вашем репозитории
|
||||
issues.in_your_repos=В ваших репозиториях
|
||||
|
||||
[explore]
|
||||
repos=Репозитории
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken=Имя репозитория уже принято.
|
||||
org_name_been_taken=Название организации было уже принято.
|
||||
team_name_been_taken=Название команды было уже принято.
|
||||
email_been_used=Адрес электронной почты уже используется.
|
||||
illegal_team_name=Имя группы содержит недопустимые знаки.
|
||||
username_password_incorrect=Имя пользователя или пароль не правильный.
|
||||
enterred_invalid_repo_name=Пожалуйста, убедитесь, что введенно правильное имя хранилища.
|
||||
enterred_invalid_owner_name=Убедитесь, что введенное имя владельца верное.
|
||||
@@ -226,12 +228,14 @@ target_branch_not_exist=Целевая ветка не существует
|
||||
[user]
|
||||
change_avatar=Измените ваш аватар на gravatar.com
|
||||
change_custom_avatar=Измените ваш аватар в настройках
|
||||
join_on=Присоединилась к
|
||||
join_on=Присоединился
|
||||
repositories=Репозитории
|
||||
activity=Активность
|
||||
followers=Подписчики
|
||||
starred=Избранное
|
||||
following=Подписан
|
||||
follow=Подписаться
|
||||
unfollow=Отписаться
|
||||
|
||||
form.name_reserved=Имя пользователя '%s' зарезервировано.
|
||||
form.name_pattern_not_allowed=Имя пользователя «%s» не допускается.
|
||||
@@ -248,7 +252,7 @@ uid=UID
|
||||
|
||||
public_profile=Открытый профиль
|
||||
profile_desc=Адрес вашей электронной почты является публичным и будет использован для любых уведомлений, связанных с аккаунтом, а также для любых действий, совершенных через сайт.
|
||||
password_username_disabled=Non-local type users are not allowed to change their username.
|
||||
password_username_disabled=Нелокальные пользователи не могут изменить своё имя.
|
||||
full_name=ФИО
|
||||
website=Веб-сайт
|
||||
location=Местоположение
|
||||
@@ -273,7 +277,7 @@ new_password=Новый пароль
|
||||
retype_new_password=Подтверждение нового пароля
|
||||
password_incorrect=Текущий пароль не правильный.
|
||||
change_password_success=Пароль сменен успешно. Теперь вы можете войти с новым паролем.
|
||||
password_change_disabled=Non-local type users are not allowed to change their password.
|
||||
password_change_disabled=Нелокальные пользователи не могут изменить свой пароль.
|
||||
|
||||
emails=Адреса электронной почты
|
||||
manage_emails=Управление адресами электронной почты
|
||||
@@ -355,13 +359,13 @@ auto_init=Инициализировать этот репозиторий вы
|
||||
create_repo=Создать репозиторий
|
||||
default_branch=Ветка по умолчанию
|
||||
mirror_interval=Интервал зеркалирования (час)
|
||||
mirror_address=Mirror Address
|
||||
mirror_address_desc=Please include necessary user credentials in the address.
|
||||
mirror_address=Адрес зеркала
|
||||
mirror_address_desc=Укажите необходимые учетные данные в адрес.
|
||||
watchers=Наблюдатели
|
||||
stargazers=Звездочеты
|
||||
forks=Форки
|
||||
|
||||
form.reach_limit_of_creation=The owner has reached maximum creation limit of %d repositories.
|
||||
form.reach_limit_of_creation=У владельца достигнут максимальный предел в %d создаваемых репозиториев.
|
||||
form.name_reserved=Имя репозитория '%s' зарезервировано.
|
||||
form.name_pattern_not_allowed=Шаблон имени репозитория '%s' не допускается.
|
||||
|
||||
@@ -375,7 +379,7 @@ migrate.permission_denied=У вас нет прав на импорт локал
|
||||
migrate.invalid_local_path=Недопустимый локальный путь. Возможно он не существует или является не папкой.
|
||||
migrate.failed=Миграция не удалась: %v
|
||||
|
||||
mirror_from=mirror from
|
||||
mirror_from=зеркало из
|
||||
forked_from=форк от
|
||||
fork_from_self=Вы не можете форкнуть репозитарий, так как Вы уже его владелец!
|
||||
copy_link=Скопировать
|
||||
@@ -402,7 +406,7 @@ filter_branch_and_tag=Фильтр по ветке или тегу
|
||||
branches=Ветки
|
||||
tags=Метки
|
||||
issues=Обсуждения
|
||||
pulls=Пулл реквесты
|
||||
pulls=Запросы на слияние
|
||||
labels=Метки
|
||||
milestones=Этапы
|
||||
commits=Коммиты
|
||||
@@ -423,7 +427,7 @@ commits.newer=Новее
|
||||
|
||||
issues.new=Новая задача
|
||||
issues.new.labels=Метки
|
||||
issues.new.no_label=Не метка
|
||||
issues.new.no_label=Нет меток
|
||||
issues.new.clear_labels=Отчистить метки
|
||||
issues.new.milestone=Этап
|
||||
issues.new.no_milestone=Нет этапа
|
||||
@@ -437,8 +441,8 @@ issues.create=Добавить задачу
|
||||
issues.new_label=Новая метка
|
||||
issues.new_label_placeholder=Имя метки...
|
||||
issues.create_label=Добавить метку
|
||||
issues.open_tab=%d Открыть
|
||||
issues.close_tab=%d Закрыть
|
||||
issues.open_tab=%d открыто(ы)
|
||||
issues.close_tab=%d закрыто(ы)
|
||||
issues.filter_label=Метка
|
||||
issues.filter_label_no_select=Нет выбранной метки
|
||||
issues.filter_milestone=Этап
|
||||
@@ -447,7 +451,7 @@ issues.filter_assignee=Назначено
|
||||
issues.filter_assginee_no_select=Ответственный не выбран
|
||||
issues.filter_type=Тип
|
||||
issues.filter_type.all_issues=Все задачи
|
||||
issues.filter_type.assigned_to_you=Назначено Вам
|
||||
issues.filter_type.assigned_to_you=Назначено вам
|
||||
issues.filter_type.created_by_you=Созданные вами
|
||||
issues.filter_type.mentioning_you=Вы упомянуты
|
||||
issues.filter_sort=Сортировать
|
||||
@@ -457,19 +461,19 @@ issues.filter_sort.recentupdate=Недавно обновленные
|
||||
issues.filter_sort.leastupdate=Давно обновленные
|
||||
issues.filter_sort.mostcomment=Большего комментариев
|
||||
issues.filter_sort.leastcomment=Меньше комментариев
|
||||
issues.opened_by=%[1] открыта <a href="%[2]s">%[3]s</a>
|
||||
issues.opened_by=%[1]s открыта <a href="%[2]s">%[3]s</a>
|
||||
issues.opened_by_fake=%[1]s открыта %[2]s
|
||||
issues.previous=Предыдущая страница
|
||||
issues.next=Следующая страница
|
||||
issues.open_title=Открыта
|
||||
issues.closed_title=Закрыта
|
||||
issues.open_title=Открыто
|
||||
issues.closed_title=Закрыто
|
||||
issues.num_comments=комментариев: %d
|
||||
issues.commented_at=` прокомментировал <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.no_content=Пока нет содержимого.
|
||||
issues.close_issue=Закрыть
|
||||
issues.close_comment_issue=Прокомментировать и закрыть
|
||||
issues.reopen_issue=Открыть снова
|
||||
issues.reopen_comment_issue=Прокомментировать и открыть
|
||||
issues.reopen_comment_issue=Прокомментировать и открыть снова
|
||||
issues.create_comment=Комментировать
|
||||
issues.closed_at=`закрыл <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
issues.reopened_at=`открыл снова <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||
@@ -492,41 +496,42 @@ issues.label_modify=Изменение метки
|
||||
issues.label_deletion=Удаление метки
|
||||
issues.label_deletion_desc=Удаление ярлыка затронет все связанные задачи. Продолжить?
|
||||
issues.label_deletion_success=Метка была удалена успешно!
|
||||
issues.num_participants=%d участников
|
||||
|
||||
pulls.new=Новый пул реквест
|
||||
pulls.new=Новый запрос на слияние
|
||||
pulls.compare_changes=Сравнить изменения
|
||||
pulls.compare_changes_desc=Сравнить две ветки и создать пулл реквест для изменений.
|
||||
pulls.compare_changes_desc=Сравнить две ветки и создать запрос на слияние для изменений.
|
||||
pulls.compare_base=родительская ветка
|
||||
pulls.compare_compare=сравнить
|
||||
pulls.filter_branch=Фильтр по ветке
|
||||
pulls.no_results=Результатов не найдено.
|
||||
pulls.nothing_to_compare=Нечего сравнивать, родительская и текущая ветка одинаковые.
|
||||
pulls.has_pull_request=`Уже существует пулл-реквест между двумя целями <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
|
||||
pulls.create=Создать пулл-реквест
|
||||
pulls.create=Создать запрос на слияние
|
||||
pulls.title_desc=хочет смерджить %[1]d коммит(ов) из <code>%[2]s</code> в <code>%[3]s</code>
|
||||
pulls.merged_title_desc=слито %[1]d коммит(ов) из <code>%[2]s</code> в <code>%[3]s</code> %[4]s
|
||||
pulls.tab_conversation=Обсуждение
|
||||
pulls.tab_commits=Коммиты
|
||||
pulls.tab_files=Измененные файлы
|
||||
pulls.reopen_to_merge=Пожалуйста пересоздайте пулл-реквест для слияния.
|
||||
pulls.reopen_to_merge=Пожалуйста снова откройте этот запрос для слияния.
|
||||
pulls.merged=Слито
|
||||
pulls.has_merged=Слияние этого пулл-реквеста успешно завершено!
|
||||
pulls.has_merged=Слияние этого запроса успешно завершено!
|
||||
pulls.data_broken=Содержимое этого пулл-реквеста было нарушено, вследствии удаления или клонирования информации.
|
||||
pulls.is_checking=Продолжается проверка конфликтов, пожалуйста обновите страницу несколько позже.
|
||||
pulls.can_auto_merge_desc=This pull request can be merged automatically.
|
||||
pulls.cannot_auto_merge_desc=This pull request can't be merged automatically because there are conflicts.
|
||||
pulls.cannot_auto_merge_helper=Please merge manually in order to resolve the conflicts.
|
||||
pulls.can_auto_merge_desc=Этот запрос на слияние может быть объединён автоматически.
|
||||
pulls.cannot_auto_merge_desc=Этот запрос на слияние не может быть объединён автоматически.
|
||||
pulls.cannot_auto_merge_helper=Пожалуйста, совершите слияние вручную для урегулирования конфликтов.
|
||||
pulls.merge_pull_request=Слить пулл-реквест
|
||||
pulls.open_unmerged_pull_exists=`Вы не можете произвести операцию переоткрытия, потому что уже существует пулл-реквест (#%d) из этого же репозитория, с такими же параметрами слияния, который ожидает слияния.`
|
||||
pulls.open_unmerged_pull_exists=`Вы не можете снова открыть, поскольку уже существует запрос на слияние (#%d) из того же репозитория с той же информацией о слиянии и ожидающий слияния. `
|
||||
|
||||
milestones.new=Новая контрольная точка
|
||||
milestones.open_tab=%d открыты
|
||||
milestones.close_tab=%d Закрыт
|
||||
milestones.close_tab=%d закрыты
|
||||
milestones.closed=Закрыт %s
|
||||
milestones.no_due_date=Срок не указан
|
||||
milestones.open=Открыть
|
||||
milestones.close=Закрыть
|
||||
milestones.new_subheader=Создавайте контрольные точки для трекинга ваших вопросов.
|
||||
milestones.new_subheader=Создавайте этапы для организации ваших задач.
|
||||
milestones.create=Создать контрольную точку
|
||||
milestones.title=Заголовок
|
||||
milestones.desc=Описание
|
||||
@@ -540,7 +545,7 @@ milestones.cancel=Отмена
|
||||
milestones.modify=Изменить контрольную точку
|
||||
milestones.edit_success=Изменения контрольной точки '%s' успешно сохранены!
|
||||
milestones.deletion=Удаление контрольной точки
|
||||
milestones.deletion_desc=Удаление этой контрольной точки приведет с удалению всей информации, во всех вопросах (Issues). Вы действительно хотите продолжить?
|
||||
milestones.deletion_desc=Удаление этого этапа приведет к удалению связанной информации во всех связанных задачах. Вы хотите продолжить?
|
||||
milestones.deletion_success=Контрольная точка успешно удалена!
|
||||
|
||||
wiki=Вики
|
||||
@@ -569,26 +574,31 @@ settings.site=Официальный сайт
|
||||
settings.update_settings=Обновить настройки
|
||||
settings.change_reponame_prompt=Это изменение повлияет на отношения ссылок к этому репозиторию.
|
||||
settings.advanced_settings=Расширенные настройки
|
||||
settings.wiki_desc=Включить Вики, чтобы позволить людям ипсать документы
|
||||
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.wiki_desc=Включить Вики, чтобы позволить людям писать документы
|
||||
settings.use_external_wiki=Использовать внешнюю Wiki
|
||||
settings.external_wiki_url=URL-адрес внешней вики
|
||||
settings.external_wiki_url_desc=Посетители будут перенаправлены на URL-адрес, когда они кликнут по вкладке.
|
||||
settings.issues_desc=Включить встроенную, легковесную систему отслеживания ошибок
|
||||
settings.use_external_issue_tracker=Использовать внешнюю систему отслеживания ошибок
|
||||
settings.tracker_url_format=Внешний формат ссылки системы отслеживания ошибок.
|
||||
settings.tracker_url_format_desc=Вы можете использовать шаблон <code>{user} {repo} {index}</code> для имени пользователя, репозитория и номера обсуждения.
|
||||
settings.pulls_desc=Включить публичные пулл-реквесты
|
||||
settings.tracker_url_format_desc=Вы можете использовать шаблон <code>{user} {repo} {index}</code> для имени пользователя, репозитория и номера задачи.
|
||||
settings.pulls_desc=Включить публичные запросы на слияние
|
||||
settings.danger_zone=Опасная зона
|
||||
settings.new_owner_has_same_repo=У нового владельца уже есть хранилище с таким названием.
|
||||
settings.convert=Преобразовать в обычный репозиторий
|
||||
settings.convert_desc=Это зеркало можно преобразовать в обычный репозиторий. Это не может быть отменено.
|
||||
settings.convert_notices_1=- Эта операция преобразует это зеркало в обычный репозиторий, и она не может быть отменена.
|
||||
settings.convert_confirm=Подтвердите преобразование
|
||||
settings.convert_succeed=Репозиторий был успешно преобразован в обычный.
|
||||
settings.transfer=Передать права собственности
|
||||
settings.transfer_desc=Передать репозиторий другому пользователю или организации где у вас есть права администратора.
|
||||
settings.new_owner_has_same_repo=У нового владельца уже есть хранилище с таким названием.
|
||||
settings.delete=Удалить этот репозиторий
|
||||
settings.delete_desc=Как только вы удалите репозиторий — пути назад не будет. Удостоверьтесь, что вам это точно нужно.
|
||||
settings.transfer_notices_1=- Вы можете потерять доступ, если новый владелец является отдельным пользователем.
|
||||
settings.transfer_notices_2=- Вы сохраните доступ, если новым владельцем станет организация, владельцем которой вы являетесь.
|
||||
settings.transfer_form_title=Введите сопутствующую информацию для подтверждения операции:
|
||||
settings.delete=Удалить этот репозиторий
|
||||
settings.delete_desc=Как только вы удалите репозиторий — пути назад не будет. Удостоверьтесь, что вам это точно нужно.
|
||||
settings.delete_notices_1=- Эта операция <strong>НЕ МОЖЕТ</strong> быть отменена.
|
||||
settings.delete_notices_2=- Эта операция перманентно удалит всё из этого репозитория, включая данные Git, связанные с ним вопросы, комментарии и права доступа для сотрудников.
|
||||
settings.delete_notices_2=- Эта операция навсегда удалит всё из этого репозитория, включая данные Git, связанные с ним задачи, комментарии и права доступа для сотрудников.
|
||||
settings.delete_notices_fork_1=- Если данный репозиторий является публичным, все склонированные репозитории останутся независимыми, после его удаления.
|
||||
settings.delete_notices_fork_2=- Если данный репозиторий является приватным, все его форки будут удалены вместе с ним.
|
||||
settings.delete_notices_fork_3=- Если вы хотите сохранить все форки после удаления репозитория, то сначала сделайте его публичным.
|
||||
@@ -602,15 +612,16 @@ settings.add_collaborator=Добавить нового соавтора
|
||||
settings.add_collaborator_success=Был добавлен новый соавтор.
|
||||
settings.remove_collaborator_success=Соавтор был удален.
|
||||
settings.search_user_placeholder=Поиск пользователя...
|
||||
settings.org_not_allowed_to_be_collaborator=Организации не могут быть добавлены как соавторы.
|
||||
settings.user_is_org_member=Пользователь является членом организации, члены которой не могут быть добавлены в качестве соавтора.
|
||||
settings.add_webhook=Добавить Webhook
|
||||
settings.hooks_desc=Webhooks позволяют внешним службам получать уведомления при возникновении определенных событий на Gogs. При возникновении указанных событий мы отправим запрос POST на каждый заданный вами URL. Узнать больше можно в нашем <a target="_blank" href="%s">Руководстве по Webhooks</a>.
|
||||
settings.webhook_deletion=Удалить веб-хук
|
||||
settings.webhook_deletion_desc=Удаление этого веб-хука приведет к удалению всей, связанной с ним, информации, включая историю. Хотите продолжить?
|
||||
settings.webhook_deletion_success=Веб-хук успешно удален!
|
||||
settings.webhook.test_delivery=Test Delivery
|
||||
settings.webhook.test_delivery_desc=Send a fake push event delivery to test your webhook settings
|
||||
settings.webhook.test_delivery_success=Test webhook has been added to delivery queue. It may taks few seconds before it shows up in the delivery history.
|
||||
settings.webhook.test_delivery=Проверить доставку
|
||||
settings.webhook.test_delivery_desc=Отправить push для тестирования настройки веб-хуков
|
||||
settings.webhook.test_delivery_success=Тест веб-хука была добавлен в очередь доставки. Это может занять несколько секунд, прежде чем он отобразится в истории доставки.
|
||||
settings.webhook.request=Запрос
|
||||
settings.webhook.response=Ответ
|
||||
settings.webhook.headers=Заголовки
|
||||
@@ -650,7 +661,7 @@ settings.slack_domain=Домен
|
||||
settings.slack_channel=Канал
|
||||
settings.deploy_keys=Ключи развертывания
|
||||
settings.add_deploy_key=Добавить ключ развертывания
|
||||
settings.deploy_key_desc=Deploy key only has read-only access. It is not same as personal account SSH keys.
|
||||
settings.deploy_key_desc=Ключи развёртывания доступны только для чтения. Это не то же самое что и SSH-ключи аккаунта.
|
||||
settings.no_deploy_keys=Вы не добавляли ключи развертывания.
|
||||
settings.title=Заголовок
|
||||
settings.deploy_key_content=Содержимое
|
||||
@@ -666,6 +677,8 @@ diff.parent=Родитель
|
||||
diff.commit=Сommit
|
||||
diff.data_not_available=Данные Diff не доступны.
|
||||
diff.show_diff_stats=Показать статистику Diff
|
||||
diff.show_split_view=Разделённый вид
|
||||
diff.show_unified_view=Единый вид
|
||||
diff.stats_desc=<strong> %d измененных файлов</strong> с <strong>%d добавлено</strong> и <strong>%d удалено</strong>
|
||||
diff.bin=BIN
|
||||
diff.view_file=Просмотреть файл
|
||||
@@ -796,7 +809,7 @@ total=Всего: %d
|
||||
dashboard.statistic=Статистика
|
||||
dashboard.operations=Операции
|
||||
dashboard.system_status=Статус системного монитора
|
||||
dashboard.statistic_info=В базе данных Gogs записано <b>%d</b> пользователей, <b>%d</b> организаций, <b>%d</b> публичных ключей, <b>%d</b> репозиторий, <b>%d</b> подписок на репозитории, <b>%d</b> добавлений в избранное, <b>%d</b> действий, <b>%d</b> доступов, <b>%d</b> обсуждений, <b>%d</b> комментариев, <b>%d</b> социальных учетных записей, <b>%d</b> подписок на пользователей, <b>%d</b> зеркал, <b>%d</b> релизов, <b>%d</b> источников входа, <b>%d</b> веб-хуков, <b>%d</b> вех, <b>%d</b> меток, <b>%d</b> задач хуков, <b>%d</b> команд, <b>%d</b> задач по обновлению, <b>%d</b> присоединенных файлов.
|
||||
dashboard.statistic_info=В базе данных Gogs записано <b>%d</b> пользователей, <b>%d</b> организаций, <b>%d</b> публичных ключей, <b>%d</b> репозиториев, <b>%d</b> подписок на репозитории, <b>%d</b> добавлений в избранное, <b>%d</b> действий, <b>%d</b> доступов, <b>%d</b> задач, <b>%d</b> комментариев, <b>%d</b> социальных учетных записей, <b>%d</b> подписок на пользователей, <b>%d</b> зеркал, <b>%d</b> релизов, <b>%d</b> источников входа, <b>%d</b> веб-хуков, <b>%d</b> этапов, <b>%d</b> меток, <b>%d</b> задач хуков, <b>%d</b> команд, <b>%d</b> задач по обновлению, <b>%d</b> присоединенных файлов.
|
||||
dashboard.operation_name=Наименование Операции
|
||||
dashboard.operation_switch=Переключить
|
||||
dashboard.operation_run=Запуск
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys=Переписать файл «.ssh/authorized_key
|
||||
dashboard.resync_all_sshkeys_success=Были успешно переписаны все открытые ключи.
|
||||
dashboard.resync_all_update_hooks=Перезаписать все апдейт-хуки этого репозитория (необходимо, когда изменен путь до папки конфигураций)
|
||||
dashboard.resync_all_update_hooks_success=Апдейт-хуки всех репозиториев успешно перезаписаны.
|
||||
dashboard.reinit_missing_repos=Реинициализировать все репозитории с утерянными Git файлами
|
||||
dashboard.reinit_missing_repos_success=Все репозитории с утерянными Git файлами успешно реинициализированы.
|
||||
|
||||
dashboard.server_uptime=Время непрерывной работы сервера
|
||||
dashboard.current_goroutine=Текущий Goroutines
|
||||
@@ -861,8 +876,8 @@ users.auth_login_name=Логин для авторизации
|
||||
users.password_helper=Оставьте пустым, чтобы оставить без изменений.
|
||||
users.update_profile_success=Профиль учетной записи обновлен успешно.
|
||||
users.edit_account=Изменение учетной записи
|
||||
users.max_repo_creation=Maximum Repository Creation Limit
|
||||
users.max_repo_creation_desc=(Set -1 to use global default limit)
|
||||
users.max_repo_creation=Ограничение максимального количества создаваемых репозиториев
|
||||
users.max_repo_creation_desc=(Установить -1 для использования стандартного глобального значения предела)
|
||||
users.is_activated=Эта учетная запись активирована
|
||||
users.is_admin=У этой учетной записи есть права администратора
|
||||
users.allow_git_hook=Пользователь имеет право создать Git перехватчик
|
||||
@@ -884,7 +899,7 @@ repos.name=Имя
|
||||
repos.private=Приватный
|
||||
repos.watches=Следят
|
||||
repos.stars=В избранном
|
||||
repos.issues=Вопросы
|
||||
repos.issues=Задачи
|
||||
|
||||
auths.auth_manage_panel=Панель управления аутнентификациями
|
||||
auths.new=Добавить новый источник
|
||||
@@ -903,10 +918,11 @@ auths.bind_password_helper=Внимание: Этот пароль сохран
|
||||
auths.user_base=База для поиска пользователя
|
||||
auths.user_dn=DN пользователя
|
||||
auths.attribute_username=Атрибут username
|
||||
auths.attribute_username_placeholder=Leave empty to use sign-in form field value for user name.
|
||||
auths.attribute_username_placeholder=Оставьте пустым, чтобы использовать имя пользователя для регистрации.
|
||||
auths.attribute_name=Имя аттрибута
|
||||
auths.attribute_surname=Фамилия аттрибута
|
||||
auths.attribute_mail=Электронная почта аттрибута
|
||||
auths.attributes_in_bind=Извлечение атрибутов в виде Bind DN
|
||||
auths.filter=Фильтр пользователя
|
||||
auths.admin_filter=Фильтр администратора
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm=Требуется подтверждение по
|
||||
config.disable_register=Отключить регистрацию
|
||||
config.show_registration_button=Показать кнопку регистрации
|
||||
config.require_sign_in_view=Для просмотра необходима авторизация
|
||||
config.enable_cache_avatar=Кешировать аватар
|
||||
config.mail_notify=Почтовые уведомления
|
||||
config.disable_key_size_check=Отключить проверку на минимальный размер ключа
|
||||
config.enable_captcha=Включить капчу
|
||||
@@ -1021,16 +1036,18 @@ notices.op=Op.
|
||||
notices.delete_success=Системное уведомление успешно удалено.
|
||||
|
||||
[action]
|
||||
create_repo=создан репозиторий <a href="%s"> %s</a>
|
||||
create_repo=создал(а) репозиторий <a href="%s"> %s</a>
|
||||
rename_repo=репозиторий переименован из <code>%[1]s</code>на <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=запушил <a href="%[1]s/src/%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`открытый вопрос <a href="%s/issues/%s">%s#%[2]</a>`
|
||||
commit_repo=запушил(а) <a href="%[1]s/src/%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`открыл(а) задачу <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue=`закрыл(а) задачу <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`возобновил(а) задачу <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`созданный пулл-реквест <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`прокомментировал(а) вопрос <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`слил пул реквест <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
transfer_repo=перенес репозиторий <code>%s</code> в <a href="%s">%s</a>
|
||||
push_tag=запушил тэг <a href="%s/src/%s">%[2]s</a> в <a href="%[1]s">%[3]s</a>
|
||||
compare_commits=View comparison for these %d commits
|
||||
push_tag=запушил(а) метку <a href="%s/src/%s">%[2]s</a> в <a href="%[1]s">%[3]s</a>
|
||||
compare_commits=Просмотр сравнение для этих %d коммитов
|
||||
|
||||
[tool]
|
||||
ago=назад
|
||||
|
||||
@@ -38,7 +38,7 @@ settings=帐户设置
|
||||
your_profile=个人信息
|
||||
your_settings=用户设置
|
||||
|
||||
news_feed=最新活动
|
||||
activities=最近活动
|
||||
pull_requests=合并请求
|
||||
issues=工单管理
|
||||
|
||||
@@ -65,7 +65,7 @@ db_name=数据库名称
|
||||
db_helper=如果您使用 MySQL,请使用 INNODB 引擎以及 utf8_general_ci 字符集。
|
||||
ssl_mode=SSL 模式
|
||||
path=数据库文件路径
|
||||
sqlite_helper=SQLite3 或 TiDB 的数据库路径。
|
||||
sqlite_helper=SQLite3 或 TiDB 数据库文件路径。<br>作为服务启动时,请使用绝对路径。
|
||||
err_empty_db_path=SQLite3 或 TiDB 的数据库路径不能为空。
|
||||
err_invalid_tidb_name=TiDB 数据库名称不允许包含字符 "." 或 "-" 。
|
||||
no_admin_and_disable_registration=您不能够在未创建管理员用户的情况下禁止注册。
|
||||
@@ -86,6 +86,8 @@ http_port=HTTP 端口号
|
||||
http_port_helper=应用监听的端口号
|
||||
app_url=应用 URL
|
||||
app_url_helper=该设置影响 HTTP/HTTPS 克隆地址和一些邮箱中的链接。
|
||||
log_root_path=日志路径
|
||||
log_root_path_helper=存放日志文件的目录
|
||||
|
||||
optional_title=可选设置
|
||||
email_title=邮件服务设置
|
||||
@@ -122,6 +124,7 @@ run_user_not_match=运行系统用户非当前用户:%s -> %s
|
||||
save_config_failed=应用配置保存失败:%v
|
||||
invalid_admin_setting=管理员帐户设置不正确:%v
|
||||
install_success=您好!我们很高兴您选择使用 Gogs,祝您使用愉快,代码从此无 BUG!
|
||||
invalid_log_root_path=无效的日志路径:%v
|
||||
|
||||
[home]
|
||||
uname_holder=用户名或邮箱
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken=仓库名称已经被占用。
|
||||
org_name_been_taken=组织名称已经被占用。
|
||||
team_name_been_taken=团队名称已经被占用。
|
||||
email_been_used=邮箱地址已经被使用。
|
||||
illegal_team_name=团队名称包含非法字符。
|
||||
username_password_incorrect=用户名或密码不正确。
|
||||
enterred_invalid_repo_name=请检查您输入的仓库名称是正确。
|
||||
enterred_invalid_owner_name=请检查您输入的新所有者用户名是否正确。
|
||||
@@ -232,6 +234,8 @@ activity=公开活动
|
||||
followers=关注者
|
||||
starred=已点赞
|
||||
following=关注中
|
||||
follow=关注
|
||||
unfollow=取消关注
|
||||
|
||||
form.name_reserved=用户名 '%s' 是被保留的。
|
||||
form.name_pattern_not_allowed=用户名不允许 '%s' 的格式。
|
||||
@@ -492,6 +496,7 @@ issues.label_modify=修改标签
|
||||
issues.label_deletion=删除标签操作
|
||||
issues.label_deletion_desc=删除该标签将会移除所有工单中相关的信息。是否继续?
|
||||
issues.label_deletion_success=标签删除成功!
|
||||
issues.num_participants=%d 名参与者
|
||||
|
||||
pulls.new=创建合并请求
|
||||
pulls.compare_changes=对比文件变化
|
||||
@@ -579,14 +584,19 @@ settings.tracker_url_format=外部工单管理系统的 URL 格式
|
||||
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分别作为用户名、仓库名和工单索引的占位符。
|
||||
settings.pulls_desc=启用合并请求以接受社区贡献
|
||||
settings.danger_zone=危险操作区
|
||||
settings.new_owner_has_same_repo=新的仓库拥有者已经存在同名仓库!
|
||||
settings.convert=转换为普通仓库
|
||||
settings.convert_desc=您可以将该镜像仓库转换为普通仓库,且此操作不可逆。
|
||||
settings.convert_notices_1=- 该操作会将该镜像仓库转换为普通仓库,且操作不可逆。
|
||||
settings.convert_confirm=确认转换
|
||||
settings.convert_succeed=转换为普通仓库类型成功!
|
||||
settings.transfer=转移仓库所有权
|
||||
settings.transfer_desc=您可以将仓库转移至您拥有管理员权限的帐户或组织。
|
||||
settings.new_owner_has_same_repo=新的仓库拥有者已经存在同名仓库!
|
||||
settings.delete=删除本仓库
|
||||
settings.delete_desc=删除仓库操作不可逆转,请三思而后行。
|
||||
settings.transfer_notices_1=- 如果您将仓库转移给个人用户,您将会丢失操作权限。
|
||||
settings.transfer_notices_2=- 如果您将仓库转移给您是所有者的组织,您的操作权限将被保留。
|
||||
settings.transfer_form_title=请输入以下信息以确认您的操作:
|
||||
settings.delete=删除本仓库
|
||||
settings.delete_desc=删除仓库操作不可逆转,请三思而后行。
|
||||
settings.delete_notices_1=- 此操作 <strong>不可以</strong> 被回滚。
|
||||
settings.delete_notices_2=- 此操作将永久删除该仓库,包括 Git 数据、 工单、 评论和协作者的操作权限。
|
||||
settings.delete_notices_fork_1=- 如果该仓库为公开的,则在删除仓库后所有的派生仓库都将转换成独立的仓库。
|
||||
@@ -602,6 +612,7 @@ settings.add_collaborator=增加新的协作者
|
||||
settings.add_collaborator_success=成功添加新的协作者!
|
||||
settings.remove_collaborator_success=被操作的协作者已经被收回权限!
|
||||
settings.search_user_placeholder=搜索用户...
|
||||
settings.org_not_allowed_to_be_collaborator=组织不允许被添加为仓库协作者!
|
||||
settings.user_is_org_member=被操作的用户是组织成员,因此无法添加为协作者!
|
||||
settings.add_webhook=添加 Web 钩子
|
||||
settings.hooks_desc=Web 钩子允许您设定在 Gogs 上发生指定事件时对指定 URL 发送 POST 通知。查看 <a target="_blank" href="%s">Webhooks 文档</a> 获取更多信息。
|
||||
@@ -666,6 +677,8 @@ diff.parent=父节点
|
||||
diff.commit=当前提交
|
||||
diff.data_not_available=暂无可用数据
|
||||
diff.show_diff_stats=显示文件统计
|
||||
diff.show_split_view=分列视图
|
||||
diff.show_unified_view=合并视图
|
||||
diff.stats_desc=共有 <strong> %d 个文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
|
||||
diff.bin=二进制
|
||||
diff.view_file=查看文件
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys=重新生成 '.ssh/authorized_keys' 文件(警告
|
||||
dashboard.resync_all_sshkeys_success=所有公钥重新生成成功!
|
||||
dashboard.resync_all_update_hooks=重新生成所有仓库的 Update 钩子(用于自定义配置文件被修改)
|
||||
dashboard.resync_all_update_hooks_success=所有仓库的 Update 钩子重新生成成功!
|
||||
dashboard.reinit_missing_repos=重新初始化所有丢失 Git 文件的仓库
|
||||
dashboard.reinit_missing_repos_success=所有丢失 Git 文件的仓库重新初始化成功!
|
||||
|
||||
dashboard.server_uptime=服务运行时间
|
||||
dashboard.current_goroutine=当前 Goroutines 数量
|
||||
@@ -907,6 +922,7 @@ auths.attribute_username_placeholder=留空表示使用用户登录时所使用
|
||||
auths.attribute_name=名字属性
|
||||
auths.attribute_surname=姓氏属性
|
||||
auths.attribute_mail=邮箱属性
|
||||
auths.attributes_in_bind=从 Bind DN 中拉取属性信息
|
||||
auths.filter=用户过滤规则
|
||||
auths.admin_filter=管理员过滤规则
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm=注册邮件确认
|
||||
config.disable_register=关闭注册功能
|
||||
config.show_registration_button=显示注册按钮
|
||||
config.require_sign_in_view=强制登录浏览
|
||||
config.enable_cache_avatar=开启缓存头像
|
||||
config.mail_notify=邮件通知提醒
|
||||
config.disable_key_size_check=禁用密钥最小长度检查
|
||||
config.enable_captcha=启用验证码服务
|
||||
@@ -1025,6 +1040,8 @@ create_repo=创建了仓库 <a href="%s">%s</a>
|
||||
rename_repo=重命名仓库 <code>%[1]s</code> 为 <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=推送了 <a href="%[1]s/src/%[2]s">%[3]s</a> 分支的代码到 <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`创建了工单 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue=`关闭了工单 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`重新开启了工单 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`创建了合并请求 <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`评论了工单 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`合并了合并请求 <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
|
||||
@@ -3,44 +3,44 @@ app_desc=基於 Go 語言的自助 Git 服務
|
||||
home=首頁
|
||||
dashboard=控制面版
|
||||
explore=探索
|
||||
help=幫助
|
||||
sign_in=登錄
|
||||
sign_out=退出
|
||||
help=說明
|
||||
sign_in=登入
|
||||
sign_out=登出
|
||||
sign_up=註冊
|
||||
register=註冊
|
||||
website=官方網站
|
||||
version=當前版本
|
||||
website=網站
|
||||
version=版本
|
||||
page=頁面
|
||||
template=模版
|
||||
language=語言選項
|
||||
template=樣板
|
||||
language=語言
|
||||
create_new=創建...
|
||||
user_profile_and_more=用戶信息及更多
|
||||
signed_in_as=已登錄用戶
|
||||
|
||||
username=用戶名
|
||||
email=郵箱
|
||||
username=用戶名稱
|
||||
email=電子郵件
|
||||
password=密碼
|
||||
re_type=確認密碼
|
||||
captcha=驗證碼
|
||||
|
||||
repository=倉庫
|
||||
repository=儲存庫
|
||||
organization=組織
|
||||
mirror=鏡像
|
||||
new_repo=創建新的倉庫
|
||||
new_repo=新增儲存庫
|
||||
new_migrate=遷移外部倉庫
|
||||
new_mirror=New Mirror
|
||||
new_fork=新的派生倉庫
|
||||
new_org=創建新的組織
|
||||
manage_org=管理我的組織
|
||||
admin_panel=管理面版
|
||||
account_settings=帳戶設置
|
||||
settings=帳戶設置
|
||||
your_profile=個人信息
|
||||
your_settings=用戶設置
|
||||
new_mirror=新鏡像
|
||||
new_fork=新增程式庫分支
|
||||
new_org=新增組織
|
||||
manage_org=管理組織
|
||||
admin_panel=管理面板
|
||||
account_settings=帳號設定
|
||||
settings=設定
|
||||
your_profile=個人資料
|
||||
your_settings=用戶設定
|
||||
|
||||
news_feed=最新活動
|
||||
activities=Activities
|
||||
pull_requests=合併請求
|
||||
issues=問題管理
|
||||
issues=問題
|
||||
|
||||
cancel=取消
|
||||
|
||||
@@ -53,19 +53,19 @@ code=程式碼
|
||||
|
||||
[install]
|
||||
install=安裝頁面
|
||||
title=首次執行安裝程序
|
||||
title=首次安裝步驟
|
||||
docker_helper=如果您正在使用 Docker 容器運行 Gogs,請務必先仔細閱讀 <a target="_blank" href="%s">官方文檔</a> 後再對本頁面進行填寫。
|
||||
requite_db_desc=Gogs 要求安裝 MySQL、PostgreSQL、SQLite3 或 TiDB。
|
||||
db_title=數據庫設置
|
||||
db_type=數據庫類型
|
||||
host=數據庫主機
|
||||
user=數據庫用戶
|
||||
password=數據庫用戶密碼
|
||||
db_name=數據庫名稱
|
||||
db_type=資料庫類型
|
||||
host=主機
|
||||
user=帳號
|
||||
password=密碼
|
||||
db_name=資料庫名稱
|
||||
db_helper=如果您使用 MySQL,請使用 INNODB 引擎以及 utf8_general_ci 字符集。
|
||||
ssl_mode=SSL 模式
|
||||
path=數據庫文件路徑
|
||||
sqlite_helper=SQLite3 或 TiDB 的數據庫路徑。
|
||||
sqlite_helper=The file path of SQLite3 or TiDB database. <br>Please use absolute path when you start as service.
|
||||
err_empty_db_path=SQLite3 或 TiDB 的數據庫路徑不能為空。
|
||||
err_invalid_tidb_name=TiDB 數據庫名稱不允許包含字符 "." 或 "-" 。
|
||||
no_admin_and_disable_registration=您不能夠在未創建管理員用戶的情況下禁止註冊。
|
||||
@@ -74,25 +74,27 @@ err_empty_admin_password=管理員密碼不能為空。
|
||||
general_title=應用基本設置
|
||||
app_name=應用名稱
|
||||
app_name_helper=為您的組織取個響亮而又偉大的名稱
|
||||
repo_path=倉庫根目錄
|
||||
repo_path_helper=所有 Git 遠程倉庫都將被存放於該目錄。
|
||||
run_user=執行系統用戶
|
||||
run_user_helper=該用戶必須具有對倉庫根目錄和執行 Gogs 的操作權限。
|
||||
repo_path=儲存庫的根目錄
|
||||
repo_path_helper=所有Git遠端儲存庫將會儲存在這個目錄之下。
|
||||
run_user=執行使用者
|
||||
run_user_helper=該用戶必須具有對儲存庫根目錄和執行 Gogs 的操作權限。
|
||||
domain=域名
|
||||
domain_helper=該設置影響 SSH 複製地址。
|
||||
ssh_port=SSH 埠
|
||||
ssh_port_helper=您的 SSH 服務正在使用此埠號,若要禁用SSH 功能請保持欄位空白。
|
||||
http_port=HTTP 端口號
|
||||
http_port_helper=應用監聽的端口號
|
||||
app_url=應用 URL
|
||||
app_url=應用程式網址
|
||||
app_url_helper=該設置影響 HTTP/HTTPS 複製地址和一些郵箱中的連結。
|
||||
log_root_path=Log Path
|
||||
log_root_path_helper=Directory to write log files to.
|
||||
|
||||
optional_title=可選設置
|
||||
email_title=電子郵件服務設定
|
||||
smtp_host=SMTP 主機
|
||||
smtp_from=郵件來自
|
||||
smtp_from=寄件者
|
||||
smtp_from_helper=郵件來自地址,遵循 RFC 5322 標准。可以是一個單純的郵箱地址或使用 "name" <email@example.com> 的格式。
|
||||
mailer_user=發送郵箱
|
||||
mailer_user=寄件者 E-mail
|
||||
mailer_password=發送郵箱密碼
|
||||
register_confirm=啟用註冊郵箱確認
|
||||
mail_notify=啟用郵件通知提醒
|
||||
@@ -122,6 +124,7 @@ run_user_not_match=執行系統用戶非當前用戶:%s -> %s
|
||||
save_config_failed=應用配置保存失敗:%v
|
||||
invalid_admin_setting=管理員帳戶設置不正確:%v
|
||||
install_success=您好!我們很高興您選擇使用 Gogs,祝您使用愉快,代碼從此無 BUG!
|
||||
invalid_log_root_path=Log root path is invalid: %v
|
||||
|
||||
[home]
|
||||
uname_holder=用戶名或郵箱
|
||||
@@ -174,7 +177,7 @@ modify=確認修改
|
||||
|
||||
[form]
|
||||
UserName=用戶名
|
||||
RepoName=倉庫名稱
|
||||
RepoName=儲存庫名稱
|
||||
Email=郵箱地址
|
||||
Password=密碼
|
||||
Retype=確認密碼
|
||||
@@ -203,7 +206,6 @@ repo_name_been_taken=倉庫名稱已經被佔用。
|
||||
org_name_been_taken=組織名稱已經被佔用。
|
||||
team_name_been_taken=團隊名稱已經被佔用。
|
||||
email_been_used=郵箱地址已經被使用。
|
||||
illegal_team_name=團隊名稱包含不合法字符。
|
||||
username_password_incorrect=用戶名或密碼不正確。
|
||||
enterred_invalid_repo_name=請檢查您輸入的倉庫名稱是正確。
|
||||
enterred_invalid_owner_name=請檢查您輸入的新所有者用戶名是否正確。
|
||||
@@ -232,6 +234,8 @@ activity=公開活動
|
||||
followers=關註者
|
||||
starred=已讚好
|
||||
following=關註中
|
||||
follow=關注
|
||||
unfollow=取消關注
|
||||
|
||||
form.name_reserved=用戶名 '%s' 是被保留的。
|
||||
form.name_pattern_not_allowed=用戶名不允許 '%s' 的格式。
|
||||
@@ -248,7 +252,7 @@ uid=用戶 ID
|
||||
|
||||
public_profile=公開信息
|
||||
profile_desc=您的郵箱地址將會被公開,並被用於接收帳戶的所有提醒和通知。
|
||||
password_username_disabled=Non-local type users are not allowed to change their username.
|
||||
password_username_disabled=不允許非本地類型使用者更改他們的使用者名。
|
||||
full_name=自定義名稱
|
||||
website=個人網站
|
||||
location=所在地區
|
||||
@@ -273,7 +277,7 @@ new_password=新的密碼
|
||||
retype_new_password=重新輸入新的密碼
|
||||
password_incorrect=當前密碼不正確!
|
||||
change_password_success=密碼修改成功!您現在可以使用新的密碼登錄。
|
||||
password_change_disabled=Non-local type users are not allowed to change their password.
|
||||
password_change_disabled=不允許非本地類型使用者,更改其密碼。
|
||||
|
||||
emails=電子郵件地址
|
||||
manage_emails=管理電子郵件地址
|
||||
@@ -355,13 +359,13 @@ auto_init=使用選定的文件和模板初始化倉庫
|
||||
create_repo=創建倉庫
|
||||
default_branch=默認分支
|
||||
mirror_interval=鏡像同步周期(小時)
|
||||
mirror_address=Mirror Address
|
||||
mirror_address_desc=Please include necessary user credentials in the address.
|
||||
mirror_address=鏡像地址
|
||||
mirror_address_desc=請在位址中包括必要的使用者憑據。
|
||||
watchers=關注者
|
||||
stargazers=稱讚者
|
||||
forks=派生倉庫
|
||||
|
||||
form.reach_limit_of_creation=The owner has reached maximum creation limit of %d repositories.
|
||||
form.reach_limit_of_creation=擁有者已達到儲存庫最大的新增上限 %d。
|
||||
form.name_reserved=倉庫名稱 '%s' 是被保留的。
|
||||
form.name_pattern_not_allowed=倉庫名稱不允許 '%s' 的格式。
|
||||
|
||||
@@ -375,14 +379,14 @@ migrate.permission_denied=您並沒有導入本地倉庫的權限。
|
||||
migrate.invalid_local_path=無效的本地路徑,該路徑不存在或不是一個目錄!
|
||||
migrate.failed=遷移失敗:%v
|
||||
|
||||
mirror_from=mirror from
|
||||
mirror_from=镜像来自
|
||||
forked_from=派生自
|
||||
fork_from_self=無法派生已經擁有的倉庫!
|
||||
copy_link=複製連結
|
||||
copy_link_success=複製成功!
|
||||
copy_link_error=請按下 ⌘-C 或 Ctrl-C 複製
|
||||
copied=複製成功
|
||||
unwatch=取消關註
|
||||
unwatch=取消關注
|
||||
watch=關註
|
||||
unstar=取消讚好
|
||||
star=讚好
|
||||
@@ -492,6 +496,7 @@ issues.label_modify=修改標籤
|
||||
issues.label_deletion=刪除標籤
|
||||
issues.label_deletion_desc=刪除該標籤將會移除所有問題中相關的訊息。是否繼續?
|
||||
issues.label_deletion_success=標籤刪除成功!
|
||||
issues.num_participants=%d Participants
|
||||
|
||||
pulls.new=創建合併請求
|
||||
pulls.compare_changes=對比文件變化
|
||||
@@ -513,9 +518,9 @@ pulls.merged=已合併
|
||||
pulls.has_merged=該合併請求已經成功合併!
|
||||
pulls.data_broken=該合併請求的數據由於派生倉庫的相關信息被刪除而被破壞。
|
||||
pulls.is_checking=該合併請求正在進行衝突檢查,請稍後再刷新頁面。
|
||||
pulls.can_auto_merge_desc=This pull request can be merged automatically.
|
||||
pulls.cannot_auto_merge_desc=This pull request can't be merged automatically because there are conflicts.
|
||||
pulls.cannot_auto_merge_helper=Please merge manually in order to resolve the conflicts.
|
||||
pulls.can_auto_merge_desc=這個拉請求可以自動合併。
|
||||
pulls.cannot_auto_merge_desc=由於存在衝突,不能自動合併這推送請求。
|
||||
pulls.cannot_auto_merge_helper=請手動合併來解決衝突。
|
||||
pulls.merge_pull_request=合併請求
|
||||
pulls.open_unmerged_pull_exists=`由於已經存在來自相同倉庫和合併信息的未合併請求(#%d),您無法執行重新開啟操作。`
|
||||
|
||||
@@ -570,23 +575,28 @@ settings.update_settings=更新倉庫設置
|
||||
settings.change_reponame_prompt=該操作將會影響到所有與該倉庫有關的鏈接
|
||||
settings.advanced_settings=高級設置
|
||||
settings.wiki_desc=啟用 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.use_external_wiki=使用外部 wiki
|
||||
settings.external_wiki_url=外部 Wiki 連結
|
||||
settings.external_wiki_url_desc=當分頁上按一下,訪客將會重新導到 URL。
|
||||
settings.issues_desc=啟用內置的輕量級問題管理系統
|
||||
settings.use_external_issue_tracker=使用外部的問題管理系統
|
||||
settings.tracker_url_format=外部問題管理系統的 URL 格式
|
||||
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分別作為用戶名、倉庫名和問題索引的占位符。
|
||||
settings.pulls_desc=啟用合併請求以接受社區貢獻
|
||||
settings.danger_zone=危險操作區
|
||||
settings.new_owner_has_same_repo=新的倉庫擁有者已經存在同名倉庫!
|
||||
settings.convert=Convert To Regular Repository
|
||||
settings.convert_desc=You can convert this mirror to a regular repository. This cannot be reversed.
|
||||
settings.convert_notices_1=- This operation will convert this repository mirror into a regular repository and cannot be undone.
|
||||
settings.convert_confirm=Confirm Conversion
|
||||
settings.convert_succeed=Repository has been converted to regular type successfully.
|
||||
settings.transfer=轉移倉庫所有權
|
||||
settings.transfer_desc=您可以將倉庫轉移至您擁有管理員權限的帳戶或組織。
|
||||
settings.new_owner_has_same_repo=新的倉庫擁有者已經存在同名倉庫!
|
||||
settings.delete=刪除本倉庫
|
||||
settings.delete_desc=刪除倉庫操作不可逆轉,請三思而後行。
|
||||
settings.transfer_notices_1=- 如果您將倉庫轉移給個人用戶,您將會丟失操作權限。
|
||||
settings.transfer_notices_2=- 如果您將倉庫轉移給您是所有者的組織,您的操作權限將被保留。
|
||||
settings.transfer_form_title=請輸入以下信息以確認您的操作:
|
||||
settings.delete=刪除本倉庫
|
||||
settings.delete_desc=刪除倉庫操作不可逆轉,請三思而後行。
|
||||
settings.delete_notices_1=- 此操作 <strong>不可以</strong> 被回滾。
|
||||
settings.delete_notices_2=- 此操作將永久刪除該倉庫,包括 Git 數據、 問題、 評論和協作者的操作權限。
|
||||
settings.delete_notices_fork_1=- 如果該倉庫為公開的,則在刪除倉庫後所有的派生倉庫都將轉換成獨立的倉庫。
|
||||
@@ -602,6 +612,7 @@ settings.add_collaborator=增加新的協作者
|
||||
settings.add_collaborator_success=成功添加新的協作者!
|
||||
settings.remove_collaborator_success=被操作的協作者已經被收回權限!
|
||||
settings.search_user_placeholder=搜索用戶...
|
||||
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member=被操作的用戶是組織成員,因此無法添加為協作者!
|
||||
settings.add_webhook=添加 Web 鉤子
|
||||
settings.hooks_desc=Web 鉤子允許您設定在 Gogs 上發生指定事件時對指定 URL 發送 POST 通知。查看 <a target="_blank" href="%s">Webhooks 文檔</a> 獲取更多信息。
|
||||
@@ -666,6 +677,8 @@ diff.parent=父節點
|
||||
diff.commit=當前提交
|
||||
diff.data_not_available=暫無可用數據
|
||||
diff.show_diff_stats=顯示文件統計
|
||||
diff.show_split_view=分割檢視
|
||||
diff.show_unified_view=統一視圖
|
||||
diff.stats_desc=共有 <strong> %d 個文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
|
||||
diff.bin=二進制
|
||||
diff.view_file=查看文件
|
||||
@@ -692,7 +705,7 @@ release.prerelease_desc=這是一個預發佈版本
|
||||
release.prerelease_helper=我們會告知用戶不建議將本發佈投入生產環境使用。
|
||||
release.cancel=取消
|
||||
release.publish=發佈版本
|
||||
release.save_draft=保在草稿
|
||||
release.save_draft=儲存草稿
|
||||
release.edit_release=編輯發佈信息
|
||||
release.delete_release=刪除此次發布
|
||||
release.deletion=刪除版本發布操作
|
||||
@@ -814,6 +827,8 @@ dashboard.resync_all_sshkeys=重新生成 '.ssh/authorized_keys' 文件(警告
|
||||
dashboard.resync_all_sshkeys_success=所有公鑰重新生成成功!
|
||||
dashboard.resync_all_update_hooks=重新生成所有倉庫的 Update 鈎子(用於被修改的自定義配置文件)
|
||||
dashboard.resync_all_update_hooks_success=已成功重新生成所有倉庫的 Update 鈎子!
|
||||
dashboard.reinit_missing_repos=Reinitialize all repository records that lost Git files
|
||||
dashboard.reinit_missing_repos_success=All repository records that lost Git files have been reinitialized successfully.
|
||||
|
||||
dashboard.server_uptime=服務執行時間
|
||||
dashboard.current_goroutine=當前 Goroutines 數量
|
||||
@@ -861,8 +876,8 @@ users.auth_login_name=認證登錄名稱
|
||||
users.password_helper=留空使其保持不變。
|
||||
users.update_profile_success=該用戶信息更新成功!
|
||||
users.edit_account=編輯用戶信息
|
||||
users.max_repo_creation=Maximum Repository Creation Limit
|
||||
users.max_repo_creation_desc=(Set -1 to use global default limit)
|
||||
users.max_repo_creation=最大儲存庫新增限制
|
||||
users.max_repo_creation_desc=(設定 -1 使用全域預設限制)
|
||||
users.is_activated=該用戶已被激活
|
||||
users.is_admin=該用戶具有管理員權限
|
||||
users.allow_git_hook=該帳戶具有創建 Git 鉤子的權限
|
||||
@@ -907,6 +922,7 @@ auths.attribute_username_placeholder=留空表示使用用戶登錄時所使用
|
||||
auths.attribute_name=名子屬性
|
||||
auths.attribute_surname=姓氏屬性
|
||||
auths.attribute_mail=電子郵箱屬性
|
||||
auths.attributes_in_bind=Fetch attributes in Bind DN context
|
||||
auths.filter=使用者篩選器
|
||||
auths.admin_filter=管理者篩選器
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
@@ -958,7 +974,6 @@ config.register_email_confirm=註冊電子郵件確認
|
||||
config.disable_register=關閉註冊功能
|
||||
config.show_registration_button=顯示註冊按鈕
|
||||
config.require_sign_in_view=強制登錄瀏覽
|
||||
config.enable_cache_avatar=開啟緩存頭像
|
||||
config.mail_notify=郵件通知提醒
|
||||
config.disable_key_size_check=禁用密鑰最小長度檢查
|
||||
config.enable_captcha=啟用驗證碼服務
|
||||
@@ -1021,16 +1036,18 @@ notices.op=操作
|
||||
notices.delete_success=系統提示刪除成功!
|
||||
|
||||
[action]
|
||||
create_repo=創建了倉庫 <a href="%s">%s</a>
|
||||
create_repo=創建了儲存庫 <a href="%s">%s</a>
|
||||
rename_repo=重新命名倉庫 <code>%[1]s</code> 為 <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=推送了 <a href="%[1]s/src/%[2]s">%[3]s</a> 分支的代碼到 <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`創建了問題 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue=`closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue=`reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request=`創建了合併請求 <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue=`評論了問題 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request=`合併了合併請求 <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
transfer_repo=將倉庫 <code>%s</code> 轉移至 <a href="%s">%s</a>
|
||||
transfer_repo=將儲存庫 <code>%s</code> 轉移至 <a href="%s">%s</a>
|
||||
push_tag=推送了標籤 <a href="%s/src/%s">%[2]s</a> 到 <a href="%[1]s">%[3]s</a>
|
||||
compare_commits=View comparison for these %d commits
|
||||
compare_commits=查看 %d 次提交的內容比對
|
||||
|
||||
[tool]
|
||||
ago=之前
|
||||
|
||||
@@ -20,6 +20,8 @@ $ docker run --name=gogs -p 10022:22 -p 10080:3000 -v /var/gogs:/data gogs/gogs
|
||||
$ docker start gogs
|
||||
```
|
||||
|
||||
Note: It is important to map the Gogs ssh service from the container to the host and set the appropriate SSH Port and URI settings when setting up Gogs for the first time. To access and clone Gogs Git repositories with the above configuration you would use: `git clone ssh://git@hostname:10022/username/myrepo.git` for example.
|
||||
|
||||
Files will be store in local path `/var/gogs` in my case.
|
||||
|
||||
Directory `/var/gogs` keeps Git repositories and Gogs data:
|
||||
@@ -44,19 +46,34 @@ docker run --name=gogs-data --entrypoint /bin/true gogs/gogs
|
||||
# Use `docker run` for the first time.
|
||||
docker run --name=gogs --volumes-from gogs-data -p 10022:22 -p 10080:3000 gogs/gogs
|
||||
```
|
||||
#### Using Docker 1.9 Volume command
|
||||
|
||||
```
|
||||
# Create docker volume.
|
||||
$ docker volume create --name gogs-data
|
||||
|
||||
# Use `docker run` for the first time.
|
||||
$ docker run --name=gogs -p 10022:22 -p 10080:3000 -v gogs-data:/data gogs/gogs
|
||||
```
|
||||
|
||||
## Settings
|
||||
|
||||
### Application
|
||||
|
||||
Most of settings are obvious and easy to understand, but there are some settings can be confusing by running Gogs inside Docker:
|
||||
|
||||
- **Repository Root Path**: keep it as default value `/home/git/gogs-repositories` because `start.sh` already made a symbolic link for you.
|
||||
- **Run User**: keep it as default value `git` because `start.sh` already setup a user with name `git`.
|
||||
- **Domain**: fill in with Docker container IP(e.g. `192.168.99.100`). But if you want to access your Gogs instance from a different physical machine, please fill in with the hostname or IP address of the Docker host machine.
|
||||
- **SSH Port**: Use the exposed port from Docker container. For example, your SSH server listens on `22` inside Docker, but you expose it by `10022:22`, then use `10022` for this value.
|
||||
- **SSH Port**: Use the exposed port from Docker container. For example, your SSH server listens on `22` inside Docker, but you expose it by `10022:22`, then use `10022` for this value. **Builtin SSH server is not recommended inside Docker Container**
|
||||
- **HTTP Port**: Use port you want Gogs to listen on inside Docker container. For example, your Gogs listens on `3000` inside Docker, and you expose it by `10080:3000`, but you still use `3000` for this value.
|
||||
- **Application URL**: Use combination of **Domain** and **exposed HTTP Port** values(e.g. `http://192.168.99.100:10080/`).
|
||||
|
||||
Full documentation of settings can be found [here](http://gogs.io/docs/advanced/configuration_cheat_sheet.html).
|
||||
Full documentation of application settings can be found [here](http://gogs.io/docs/advanced/configuration_cheat_sheet.html).
|
||||
|
||||
### Crond
|
||||
|
||||
Please set environment variable `RUN_CROND` to be `true` or `1` in order to start `crond` inside the container.
|
||||
|
||||
## Upgrade
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ export GOPATH=/tmp/go
|
||||
export PATH=${PATH}:${GOPATH}/bin
|
||||
|
||||
# Install build deps
|
||||
apk -U --no-progress add linux-pam-dev go@community gcc musl-dev
|
||||
apk -U --no-progress add --virtual build-deps linux-pam-dev go gcc musl-dev
|
||||
|
||||
# Init go environment to build Gogs
|
||||
mkdir -p ${GOPATH}/src/github.com/gogits/
|
||||
@@ -20,7 +20,7 @@ go build -tags "sqlite cert pam"
|
||||
rm -r $GOPATH
|
||||
|
||||
# Remove build deps
|
||||
apk --no-progress del linux-pam-dev go gcc musl-dev
|
||||
apk --no-progress del build-deps
|
||||
|
||||
# Create git user for Gogs
|
||||
adduser -H -D -g 'Gogs Git User' git -h /data/git -s /bin/bash && passwd -u git
|
||||
|
||||
16
docker/nsswitch.conf
Normal file
16
docker/nsswitch.conf
Normal file
@@ -0,0 +1,16 @@
|
||||
# /etc/nsswitch.conf
|
||||
|
||||
passwd: compat
|
||||
group: compat
|
||||
shadow: compat
|
||||
|
||||
hosts: files dns
|
||||
networks: files
|
||||
|
||||
protocols: db files
|
||||
services: db files
|
||||
ethers: db files
|
||||
rpc: db files
|
||||
|
||||
netgroup: nis
|
||||
|
||||
0
docker/s6/crond/down
Normal file
0
docker/s6/crond/down
Normal file
9
docker/s6/crond/run
Executable file
9
docker/s6/crond/run
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
# Crontabs are located by default in /var/spool/cron/crontabs/
|
||||
# The default configuration is also calling all the scripts in /etc/periodic/${period}
|
||||
|
||||
if test -f ./setup; then
|
||||
source ./setup
|
||||
fi
|
||||
|
||||
exec gosu root /usr/sbin/crond -fS
|
||||
@@ -1,10 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Check if host keys are present, else create them
|
||||
if ! test -f /data/ssh/ssh_host_key; then
|
||||
ssh-keygen -q -f /data/ssh/ssh_host_key -N '' -t rsa1
|
||||
fi
|
||||
|
||||
if ! test -f /data/ssh/ssh_host_rsa_key; then
|
||||
ssh-keygen -q -f /data/ssh/ssh_host_rsa_key -N '' -t rsa
|
||||
fi
|
||||
|
||||
@@ -4,7 +4,6 @@ ListenAddress 0.0.0.0
|
||||
ListenAddress ::
|
||||
Protocol 2
|
||||
LogLevel INFO
|
||||
HostKey /data/ssh/ssh_host_key
|
||||
HostKey /data/ssh/ssh_host_rsa_key
|
||||
HostKey /data/ssh/ssh_host_dsa_key
|
||||
HostKey /data/ssh/ssh_host_ecdsa_key
|
||||
|
||||
@@ -48,6 +48,15 @@ else
|
||||
create_socat_links
|
||||
fi
|
||||
|
||||
CROND=$(echo "$RUN_CROND" | tr '[:upper:]' '[:lower:]')
|
||||
if [ "$CROND" = "true" -o "$CROND" = "1" ]; then
|
||||
echo "init:crond | Cron Daemon (crond) will be run as requested by s6" 1>&2
|
||||
rm -f /app/gogs/docker/s6/crond/down
|
||||
else
|
||||
# Tell s6 not to run the crond service
|
||||
touch /app/gogs/docker/s6/crond/down
|
||||
fi
|
||||
|
||||
# Exec CMD or S6 by default if nothing present
|
||||
if [ $# -gt 0 ];then
|
||||
exec "$@"
|
||||
|
||||
5
gogs.go
5
gogs.go
@@ -1,4 +1,4 @@
|
||||
// +build go1.3
|
||||
// +build go1.4
|
||||
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
@@ -12,13 +12,12 @@ import (
|
||||
"runtime"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
_ "github.com/kardianos/minwinsvc"
|
||||
|
||||
"github.com/gogits/gogs/cmd"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
const APP_VER = "0.8.0.1212"
|
||||
const APP_VER = "0.8.43.0223"
|
||||
|
||||
func init() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
|
||||
109
models/action.go
109
models/action.go
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
"github.com/gogits/git-shell"
|
||||
"github.com/gogits/git-module"
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
@@ -28,17 +28,19 @@ import (
|
||||
type ActionType int
|
||||
|
||||
const (
|
||||
CREATE_REPO ActionType = iota + 1 // 1
|
||||
RENAME_REPO // 2
|
||||
STAR_REPO // 3
|
||||
FOLLOW_REPO // 4
|
||||
COMMIT_REPO // 5
|
||||
CREATE_ISSUE // 6
|
||||
CREATE_PULL_REQUEST // 7
|
||||
TRANSFER_REPO // 8
|
||||
PUSH_TAG // 9
|
||||
COMMENT_ISSUE // 10
|
||||
MERGE_PULL_REQUEST // 11
|
||||
ACTION_CREATE_REPO ActionType = iota + 1 // 1
|
||||
ACTION_RENAME_REPO // 2
|
||||
ACTION_STAR_REPO // 3
|
||||
ACTION_WATCH_REPO // 4
|
||||
ACTION_COMMIT_REPO // 5
|
||||
ACTION_CREATE_ISSUE // 6
|
||||
ACTION_CREATE_PULL_REQUEST // 7
|
||||
ACTION_TRANSFER_REPO // 8
|
||||
ACTION_PUSH_TAG // 9
|
||||
ACTION_COMMENT_ISSUE // 10
|
||||
ACTION_MERGE_PULL_REQUEST // 11
|
||||
ACTION_CLOSE_ISSUE // 12
|
||||
ACTION_REOPEN_ISSUE // 13
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -90,54 +92,70 @@ func (a *Action) AfterSet(colName string, _ xorm.Cell) {
|
||||
}
|
||||
}
|
||||
|
||||
func (a Action) GetOpType() int {
|
||||
func (a *Action) GetOpType() int {
|
||||
return int(a.OpType)
|
||||
}
|
||||
|
||||
func (a Action) GetActUserName() string {
|
||||
func (a *Action) GetActUserName() string {
|
||||
return a.ActUserName
|
||||
}
|
||||
|
||||
func (a Action) GetActEmail() string {
|
||||
func (a *Action) ShortActUserName() string {
|
||||
return base.EllipsisString(a.ActUserName, 20)
|
||||
}
|
||||
|
||||
func (a *Action) GetActEmail() string {
|
||||
return a.ActEmail
|
||||
}
|
||||
|
||||
func (a Action) GetRepoUserName() string {
|
||||
func (a *Action) GetRepoUserName() string {
|
||||
return a.RepoUserName
|
||||
}
|
||||
|
||||
func (a Action) GetRepoName() string {
|
||||
func (a *Action) ShortRepoUserName() string {
|
||||
return base.EllipsisString(a.RepoUserName, 20)
|
||||
}
|
||||
|
||||
func (a *Action) GetRepoName() string {
|
||||
return a.RepoName
|
||||
}
|
||||
|
||||
func (a Action) GetRepoPath() string {
|
||||
func (a *Action) ShortRepoName() string {
|
||||
return base.EllipsisString(a.RepoName, 33)
|
||||
}
|
||||
|
||||
func (a *Action) GetRepoPath() string {
|
||||
return path.Join(a.RepoUserName, a.RepoName)
|
||||
}
|
||||
|
||||
func (a Action) GetRepoLink() string {
|
||||
func (a *Action) ShortRepoPath() string {
|
||||
return path.Join(a.ShortRepoUserName(), a.ShortRepoName())
|
||||
}
|
||||
|
||||
func (a *Action) GetRepoLink() string {
|
||||
if len(setting.AppSubUrl) > 0 {
|
||||
return path.Join(setting.AppSubUrl, a.GetRepoPath())
|
||||
}
|
||||
return "/" + a.GetRepoPath()
|
||||
}
|
||||
|
||||
func (a Action) GetBranch() string {
|
||||
func (a *Action) GetBranch() string {
|
||||
return a.RefName
|
||||
}
|
||||
|
||||
func (a Action) GetContent() string {
|
||||
func (a *Action) GetContent() string {
|
||||
return a.Content
|
||||
}
|
||||
|
||||
func (a Action) GetCreate() time.Time {
|
||||
func (a *Action) GetCreate() time.Time {
|
||||
return a.Created
|
||||
}
|
||||
|
||||
func (a Action) GetIssueInfos() []string {
|
||||
func (a *Action) GetIssueInfos() []string {
|
||||
return strings.SplitN(a.Content, "|", 2)
|
||||
}
|
||||
|
||||
func (a Action) GetIssueTitle() string {
|
||||
func (a *Action) GetIssueTitle() string {
|
||||
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
|
||||
issue, err := GetIssueByIndex(a.RepoID, index)
|
||||
if err != nil {
|
||||
@@ -147,7 +165,7 @@ func (a Action) GetIssueTitle() string {
|
||||
return issue.Name
|
||||
}
|
||||
|
||||
func (a Action) GetIssueContent() string {
|
||||
func (a *Action) GetIssueContent() string {
|
||||
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
|
||||
issue, err := GetIssueByIndex(a.RepoID, index)
|
||||
if err != nil {
|
||||
@@ -162,7 +180,7 @@ func newRepoAction(e Engine, u *User, repo *Repository) (err error) {
|
||||
ActUserID: u.Id,
|
||||
ActUserName: u.Name,
|
||||
ActEmail: u.Email,
|
||||
OpType: CREATE_REPO,
|
||||
OpType: ACTION_CREATE_REPO,
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
RepoName: repo.Name,
|
||||
@@ -185,7 +203,7 @@ func renameRepoAction(e Engine, actUser *User, oldRepoName string, repo *Reposit
|
||||
ActUserID: actUser.Id,
|
||||
ActUserName: actUser.Name,
|
||||
ActEmail: actUser.Email,
|
||||
OpType: RENAME_REPO,
|
||||
OpType: ACTION_RENAME_REPO,
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
RepoName: repo.Name,
|
||||
@@ -427,10 +445,10 @@ func CommitRepoAction(
|
||||
}
|
||||
|
||||
isNewBranch := false
|
||||
opType := COMMIT_REPO
|
||||
opType := ACTION_COMMIT_REPO
|
||||
// Check it's tag push or branch.
|
||||
if strings.HasPrefix(refFullName, "refs/tags/") {
|
||||
opType = PUSH_TAG
|
||||
opType = ACTION_PUSH_TAG
|
||||
commit = &PushCommits{}
|
||||
} else {
|
||||
// if not the first commit, set the compareUrl
|
||||
@@ -482,11 +500,11 @@ func CommitRepoAction(
|
||||
payloadSender := &api.PayloadUser{
|
||||
UserName: pusher.Name,
|
||||
ID: pusher.Id,
|
||||
AvatarUrl: setting.AppUrl + pusher.RelAvatarLink(),
|
||||
AvatarUrl: pusher.AvatarLink(),
|
||||
}
|
||||
|
||||
switch opType {
|
||||
case COMMIT_REPO: // Push
|
||||
case ACTION_COMMIT_REPO: // Push
|
||||
p := &api.PushPayload{
|
||||
Ref: refFullName,
|
||||
Before: oldCommitID,
|
||||
@@ -514,7 +532,7 @@ func CommitRepoAction(
|
||||
})
|
||||
}
|
||||
|
||||
case PUSH_TAG: // Create
|
||||
case ACTION_PUSH_TAG: // Create
|
||||
return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
|
||||
Ref: refName,
|
||||
RefType: "tag",
|
||||
@@ -531,7 +549,7 @@ func transferRepoAction(e Engine, actUser, oldOwner, newOwner *User, repo *Repos
|
||||
ActUserID: actUser.Id,
|
||||
ActUserName: actUser.Name,
|
||||
ActEmail: actUser.Email,
|
||||
OpType: TRANSFER_REPO,
|
||||
OpType: ACTION_TRANSFER_REPO,
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: newOwner.Name,
|
||||
RepoName: repo.Name,
|
||||
@@ -562,7 +580,7 @@ func mergePullRequestAction(e Engine, actUser *User, repo *Repository, pull *Iss
|
||||
ActUserID: actUser.Id,
|
||||
ActUserName: actUser.Name,
|
||||
ActEmail: actUser.Email,
|
||||
OpType: MERGE_PULL_REQUEST,
|
||||
OpType: ACTION_MERGE_PULL_REQUEST,
|
||||
Content: fmt.Sprintf("%d|%s", pull.Index, pull.Name),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
@@ -577,12 +595,29 @@ func MergePullRequestAction(actUser *User, repo *Repository, pull *Issue) error
|
||||
}
|
||||
|
||||
// GetFeeds returns action list of given user in given context.
|
||||
func GetFeeds(uid, offset int64, isProfile bool) ([]*Action, error) {
|
||||
// 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) {
|
||||
actions := make([]*Action, 0, 20)
|
||||
sess := x.Limit(20, int(offset)).Desc("id").Where("user_id=?", uid)
|
||||
sess := x.Limit(20, int(offset)).Desc("id").Where("user_id=?", ctxUserID)
|
||||
if isProfile {
|
||||
sess.And("is_private=?", false).And("act_user_id=?", uid)
|
||||
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
|
||||
}
|
||||
|
||||
var repoIDs []int64
|
||||
for _, repo := range ctxUser.Repos {
|
||||
repoIDs = append(repoIDs, repo.ID)
|
||||
}
|
||||
|
||||
if len(repoIDs) > 0 {
|
||||
sess.In("repo_id", repoIDs)
|
||||
}
|
||||
}
|
||||
|
||||
err := sess.Find(&actions)
|
||||
return actions, err
|
||||
}
|
||||
|
||||
@@ -5,12 +5,17 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
type NoticeType int
|
||||
@@ -47,6 +52,25 @@ func CreateRepositoryNotice(desc string) error {
|
||||
return CreateNotice(NOTICE_REPOSITORY, desc)
|
||||
}
|
||||
|
||||
// RemoveAllWithNotice removes all directories in given path and
|
||||
// creates a system notice when error occurs.
|
||||
func RemoveAllWithNotice(title, path string) {
|
||||
var err error
|
||||
if setting.IsWindows {
|
||||
err = exec.Command("cmd", "/C", "rmdir", "/S", "/Q", path).Run()
|
||||
} else {
|
||||
err = os.RemoveAll(path)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
desc := fmt.Sprintf("%s [%s]: %v", title, path, err)
|
||||
log.Warn(desc)
|
||||
if err = CreateRepositoryNotice(desc); err != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CountNotices returns number of notices.
|
||||
func CountNotices() int64 {
|
||||
count, _ := x.Count(new(Notice))
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cron
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/cron"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
var c = cron.New()
|
||||
|
||||
func NewContext() {
|
||||
var (
|
||||
entry *cron.Entry
|
||||
err error
|
||||
)
|
||||
if setting.Cron.UpdateMirror.Enabled {
|
||||
entry, err = c.AddFunc("Update mirrors", setting.Cron.UpdateMirror.Schedule, models.MirrorUpdate)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Update mirrors]: %v", err)
|
||||
}
|
||||
if setting.Cron.UpdateMirror.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
go models.MirrorUpdate()
|
||||
}
|
||||
}
|
||||
if setting.Cron.RepoHealthCheck.Enabled {
|
||||
entry, err = c.AddFunc("Repository health check", setting.Cron.RepoHealthCheck.Schedule, models.GitFsck)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Repository health check]: %v", err)
|
||||
}
|
||||
if setting.Cron.RepoHealthCheck.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
go models.GitFsck()
|
||||
}
|
||||
}
|
||||
if setting.Cron.CheckRepoStats.Enabled {
|
||||
entry, err = c.AddFunc("Check repository statistics", setting.Cron.CheckRepoStats.Schedule, models.CheckRepoStats)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Check repository statistics]: %v", err)
|
||||
}
|
||||
if setting.Cron.CheckRepoStats.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
go models.CheckRepoStats()
|
||||
}
|
||||
}
|
||||
c.Start()
|
||||
}
|
||||
|
||||
// ListTasks returns all running cron tasks.
|
||||
func ListTasks() []*cron.Entry {
|
||||
return c.Entries()
|
||||
}
|
||||
@@ -392,6 +392,26 @@ func (err ErrReleaseNotExist) Error() string {
|
||||
return fmt.Sprintf("Release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName)
|
||||
}
|
||||
|
||||
// __________ .__
|
||||
// \______ \____________ ____ ____ | |__
|
||||
// | | _/\_ __ \__ \ / \_/ ___\| | \
|
||||
// | | \ | | \// __ \| | \ \___| Y \
|
||||
// |______ / |__| (____ /___| /\___ >___| /
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
type ErrBranchNotExist struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func IsErrBranchNotExist(err error) bool {
|
||||
_, ok := err.(ErrBranchNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrBranchNotExist) Error() string {
|
||||
return fmt.Sprintf("Branch does not exist [name: %s]", err.Name)
|
||||
}
|
||||
|
||||
// __ __ ___. .__ __
|
||||
// / \ / \ ____\_ |__ | |__ ____ ____ | | __
|
||||
// \ \/\/ // __ \| __ \| | \ / _ \ / _ \| |/ /
|
||||
@@ -559,5 +579,26 @@ func IsErrAuthenticationNotExist(err error) bool {
|
||||
}
|
||||
|
||||
func (err ErrAuthenticationNotExist) Error() string {
|
||||
return fmt.Sprintf("Authentication does not exist [id: %d]", err.ID)
|
||||
return fmt.Sprintf("authentication does not exist [id: %d]", err.ID)
|
||||
}
|
||||
|
||||
// ___________
|
||||
// \__ ___/___ _____ _____
|
||||
// | |_/ __ \\__ \ / \
|
||||
// | |\ ___/ / __ \| Y Y \
|
||||
// |____| \___ >____ /__|_| /
|
||||
// \/ \/ \/
|
||||
|
||||
type ErrTeamAlreadyExist struct {
|
||||
OrgID int64
|
||||
Name string
|
||||
}
|
||||
|
||||
func IsErrTeamAlreadyExist(err error) bool {
|
||||
_, ok := err.(ErrTeamAlreadyExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrTeamAlreadyExist) Error() string {
|
||||
return fmt.Sprintf("team already exists [org_id: %d, name: %s]", err.OrgID, err.Name)
|
||||
}
|
||||
|
||||
@@ -8,46 +8,54 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
"golang.org/x/net/html/charset"
|
||||
"golang.org/x/text/transform"
|
||||
|
||||
"github.com/gogits/git-shell"
|
||||
"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/template/highlight"
|
||||
)
|
||||
|
||||
// Diff line types.
|
||||
type DiffLineType uint8
|
||||
|
||||
const (
|
||||
DIFF_LINE_PLAIN = iota + 1
|
||||
DIFF_LINE_PLAIN DiffLineType = iota + 1
|
||||
DIFF_LINE_ADD
|
||||
DIFF_LINE_DEL
|
||||
DIFF_LINE_SECTION
|
||||
)
|
||||
|
||||
type DiffFileType uint8
|
||||
|
||||
const (
|
||||
DIFF_FILE_ADD = iota + 1
|
||||
DIFF_FILE_ADD DiffFileType = iota + 1
|
||||
DIFF_FILE_CHANGE
|
||||
DIFF_FILE_DEL
|
||||
DIFF_FILE_RENAME
|
||||
)
|
||||
|
||||
type DiffLine struct {
|
||||
LeftIdx int
|
||||
RightIdx int
|
||||
Type int
|
||||
Content string
|
||||
LeftIdx int
|
||||
RightIdx int
|
||||
Type DiffLineType
|
||||
Content string
|
||||
}
|
||||
|
||||
func (d DiffLine) GetType() int {
|
||||
return d.Type
|
||||
func (d *DiffLine) GetType() int {
|
||||
return int(d.Type)
|
||||
}
|
||||
|
||||
type DiffSection struct {
|
||||
@@ -55,12 +63,99 @@ type DiffSection struct {
|
||||
Lines []*DiffLine
|
||||
}
|
||||
|
||||
var (
|
||||
addedCodePrefix = []byte("<span class=\"added-code\">")
|
||||
removedCodePrefix = []byte("<span class=\"removed-code\">")
|
||||
codeTagSuffix = []byte("</span>")
|
||||
)
|
||||
|
||||
func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML {
|
||||
var buf bytes.Buffer
|
||||
for i := range diffs {
|
||||
if 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 {
|
||||
buf.Write(removedCodePrefix)
|
||||
buf.WriteString(html.EscapeString(diffs[i].Text))
|
||||
buf.Write(codeTagSuffix)
|
||||
} else if diffs[i].Type == diffmatchpatch.DiffEqual {
|
||||
buf.WriteString(html.EscapeString(diffs[i].Text))
|
||||
}
|
||||
}
|
||||
|
||||
return template.HTML(buf.Bytes())
|
||||
}
|
||||
|
||||
// get an specific line by type (add or del) and file line number
|
||||
func (diffSection *DiffSection) GetLine(lineType DiffLineType, idx int) *DiffLine {
|
||||
difference := 0
|
||||
|
||||
for _, diffLine := range diffSection.Lines {
|
||||
if diffLine.Type == DIFF_LINE_PLAIN {
|
||||
// get the difference of line numbers between ADD and DEL versions
|
||||
difference = diffLine.RightIdx - diffLine.LeftIdx
|
||||
continue
|
||||
}
|
||||
|
||||
if lineType == DIFF_LINE_DEL {
|
||||
if diffLine.RightIdx == 0 && diffLine.LeftIdx == idx-difference {
|
||||
return diffLine
|
||||
}
|
||||
} else if lineType == DIFF_LINE_ADD {
|
||||
if diffLine.LeftIdx == 0 && diffLine.RightIdx == idx+difference {
|
||||
return diffLine
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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()
|
||||
}
|
||||
|
||||
// try to find equivalent diff line. ignore, otherwise
|
||||
if diffLine.Type == DIFF_LINE_ADD {
|
||||
compareDiffLine = diffSection.GetLine(DIFF_LINE_DEL, diffLine.RightIdx)
|
||||
if compareDiffLine == nil {
|
||||
return getDefaultReturn()
|
||||
}
|
||||
diff1 = compareDiffLine.Content
|
||||
diff2 = diffLine.Content
|
||||
} else {
|
||||
compareDiffLine = diffSection.GetLine(DIFF_LINE_ADD, diffLine.LeftIdx)
|
||||
if compareDiffLine == nil {
|
||||
return getDefaultReturn()
|
||||
}
|
||||
diff1 = diffLine.Content
|
||||
diff2 = compareDiffLine.Content
|
||||
}
|
||||
|
||||
dmp := diffmatchpatch.New()
|
||||
diffRecord := dmp.DiffMain(diff1[1:], diff2[1:], true)
|
||||
diffRecord = dmp.DiffCleanupSemantic(diffRecord)
|
||||
|
||||
return diffToHTML(diffRecord, diffLine.Type)
|
||||
}
|
||||
|
||||
type DiffFile struct {
|
||||
Name string
|
||||
OldName string
|
||||
Index int
|
||||
Addition, Deletion int
|
||||
Type int
|
||||
Type DiffFileType
|
||||
IsCreated bool
|
||||
IsDeleted bool
|
||||
IsBin bool
|
||||
@@ -68,6 +163,14 @@ type DiffFile struct {
|
||||
Sections []*DiffSection
|
||||
}
|
||||
|
||||
func (diffFile *DiffFile) GetType() int {
|
||||
return int(diffFile.Type)
|
||||
}
|
||||
|
||||
func (diffFile *DiffFile) GetHighlightClass() string {
|
||||
return highlight.FileNameToHighlightClass(diffFile.Name)
|
||||
}
|
||||
|
||||
type Diff struct {
|
||||
TotalAddition, TotalDeletion int
|
||||
Files []*DiffFile
|
||||
@@ -124,6 +227,7 @@ func ParsePatch(maxlines int, reader io.Reader) (*Diff, error) {
|
||||
// Diff data too large, we only show the first about maxlines lines
|
||||
if lineCount >= maxlines {
|
||||
log.Warn("Diff data too large")
|
||||
io.Copy(ioutil.Discard, reader)
|
||||
diff.Files = nil
|
||||
return diff, nil
|
||||
}
|
||||
|
||||
70
models/git_diff_test.go
Normal file
70
models/git_diff_test.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
dmp "github.com/sergi/go-diff/diffmatchpatch"
|
||||
"html/template"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func assertEqual(t *testing.T, s1 string, s2 template.HTML) {
|
||||
if s1 != string(s2) {
|
||||
t.Errorf("%s should be equal %s", s2, s1)
|
||||
}
|
||||
}
|
||||
|
||||
func assertLineEqual(t *testing.T, d1 *DiffLine, d2 *DiffLine) {
|
||||
if d1 != d2 {
|
||||
t.Errorf("%v should be equal %v", d1, d2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiffToHTML(t *testing.T) {
|
||||
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{
|
||||
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])
|
||||
}
|
||||
@@ -17,11 +17,11 @@ import (
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
gouuid "github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -364,7 +364,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
|
||||
ActUserID: issue.Poster.Id,
|
||||
ActUserName: issue.Poster.Name,
|
||||
ActEmail: issue.Poster.Email,
|
||||
OpType: CREATE_ISSUE,
|
||||
OpType: ACTION_CREATE_ISSUE,
|
||||
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
@@ -665,6 +665,47 @@ func GetIssueUserPairsByMode(uid, rid int64, isClosed bool, page, filterMode int
|
||||
return ius, err
|
||||
}
|
||||
|
||||
func UpdateMentions(userNames []string, issueId int64) error {
|
||||
for i := range userNames {
|
||||
userNames[i] = strings.ToLower(userNames[i])
|
||||
}
|
||||
users := make([]*User, 0, len(userNames))
|
||||
|
||||
if err := x.Where("lower_name IN (?)", strings.Join(userNames, "\",\"")).OrderBy("lower_name ASC").Find(&users); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ids := make([]int64, 0, len(userNames))
|
||||
for _, user := range users {
|
||||
ids = append(ids, user.Id)
|
||||
if !user.IsOrganization() {
|
||||
continue
|
||||
}
|
||||
|
||||
if user.NumMembers == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
tempIds := make([]int64, 0, user.NumMembers)
|
||||
orgUsers, err := GetOrgUsersByOrgId(user.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, orgUser := range orgUsers {
|
||||
tempIds = append(tempIds, orgUser.ID)
|
||||
}
|
||||
|
||||
ids = append(ids, tempIds...)
|
||||
}
|
||||
|
||||
if err := UpdateIssueUsersByMentions(ids, issueId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IssueStats represents issue statistic information.
|
||||
type IssueStats struct {
|
||||
OpenCount, ClosedCount int64
|
||||
@@ -1138,6 +1179,7 @@ func (m *Milestone) AfterSet(colName string, _ xorm.Cell) {
|
||||
if m.Deadline.Year() == 9999 {
|
||||
return
|
||||
}
|
||||
m.Deadline = regulateTimeZone(m.Deadline)
|
||||
|
||||
m.DeadlineString = m.Deadline.Format("2006-01-02")
|
||||
if time.Now().After(m.Deadline) {
|
||||
@@ -1522,9 +1564,24 @@ func createComment(e *xorm.Session, u *User, repo *Repository, issue *Issue, com
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Compose comment action, could be plain comment, close or reopen issue.
|
||||
// This object will be used to notify watchers in the end of function.
|
||||
act := &Action{
|
||||
ActUserID: u.Id,
|
||||
ActUserName: u.Name,
|
||||
ActEmail: u.Email,
|
||||
Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
RepoName: repo.Name,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}
|
||||
|
||||
// Check comment type.
|
||||
switch cmtType {
|
||||
case COMMENT_TYPE_COMMENT:
|
||||
act.OpType = ACTION_COMMENT_ISSUE
|
||||
|
||||
if _, err = e.Exec("UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", issue.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1551,23 +1608,9 @@ func createComment(e *xorm.Session, u *User, repo *Repository, issue *Issue, com
|
||||
}
|
||||
}
|
||||
|
||||
// Notify watchers.
|
||||
act := &Action{
|
||||
ActUserID: u.Id,
|
||||
ActUserName: u.LowerName,
|
||||
ActEmail: u.Email,
|
||||
OpType: COMMENT_ISSUE,
|
||||
Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.LowerName,
|
||||
RepoName: repo.LowerName,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}
|
||||
if err = notifyWatchers(e, act); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case COMMENT_TYPE_REOPEN:
|
||||
act.OpType = ACTION_REOPEN_ISSUE
|
||||
|
||||
if issue.IsPull {
|
||||
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls-1 WHERE id=?", repo.ID)
|
||||
} else {
|
||||
@@ -1577,6 +1620,8 @@ func createComment(e *xorm.Session, u *User, repo *Repository, issue *Issue, com
|
||||
return nil, err
|
||||
}
|
||||
case COMMENT_TYPE_CLOSE:
|
||||
act.OpType = ACTION_CLOSE_ISSUE
|
||||
|
||||
if issue.IsPull {
|
||||
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls+1 WHERE id=?", repo.ID)
|
||||
} else {
|
||||
@@ -1587,6 +1632,11 @@ func createComment(e *xorm.Session, u *User, repo *Repository, issue *Issue, com
|
||||
}
|
||||
}
|
||||
|
||||
// Notify watchers for whatever action comes in.
|
||||
if err = notifyWatchers(e, act); err != nil {
|
||||
return nil, fmt.Errorf("notifyWatchers: %v", err)
|
||||
}
|
||||
|
||||
return comment, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -28,11 +28,11 @@ type LoginType int
|
||||
// Note: new type must be added at the end of list to maintain compatibility.
|
||||
const (
|
||||
LOGIN_NOTYPE LoginType = iota
|
||||
LOGIN_PLAIN
|
||||
LOGIN_LDAP
|
||||
LOGIN_SMTP
|
||||
LOGIN_PAM
|
||||
LOGIN_DLDAP
|
||||
LOGIN_PLAIN // 1
|
||||
LOGIN_LDAP // 2
|
||||
LOGIN_SMTP // 3
|
||||
LOGIN_PAM // 4
|
||||
LOGIN_DLDAP // 5
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -42,7 +42,7 @@ var (
|
||||
|
||||
var LoginNames = map[LoginType]string{
|
||||
LOGIN_LDAP: "LDAP (via BindDN)",
|
||||
LOGIN_DLDAP: "LDAP (simple auth)",
|
||||
LOGIN_DLDAP: "LDAP (simple auth)", // Via direct bind
|
||||
LOGIN_SMTP: "SMTP",
|
||||
LOGIN_PAM: "PAM",
|
||||
}
|
||||
@@ -105,10 +105,21 @@ type LoginSource struct {
|
||||
Updated time.Time `xorm:"UPDATED"`
|
||||
}
|
||||
|
||||
// Cell2Int64 converts a xorm.Cell type to int64,
|
||||
// and handles possible irregular cases.
|
||||
func Cell2Int64(val xorm.Cell) int64 {
|
||||
switch (*val).(type) {
|
||||
case []uint8:
|
||||
log.Trace("Cell2Int64 ([]uint8): %v", *val)
|
||||
return com.StrTo(string((*val).([]uint8))).MustInt64()
|
||||
}
|
||||
return (*val).(int64)
|
||||
}
|
||||
|
||||
func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
|
||||
switch colName {
|
||||
case "type":
|
||||
switch LoginType((*val).(int64)) {
|
||||
switch LoginType(Cell2Int64(val)) {
|
||||
case LOGIN_LDAP, LOGIN_DLDAP:
|
||||
source.Cfg = new(LDAPConfig)
|
||||
case LOGIN_SMTP:
|
||||
|
||||
@@ -16,11 +16,12 @@ import (
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
gouuid "github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
|
||||
const _MIN_DB_VER = 4
|
||||
@@ -57,12 +58,13 @@ 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{
|
||||
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
|
||||
NewMigration("refactor attachment table", attachmentRefactor), // V7 -> V8:v0.6.4
|
||||
NewMigration("rename pull request fields", renamePullRequestFields), // V8 -> V9:v0.6.16
|
||||
NewMigration("clean up migrate repo info", cleanUpMigrateRepoInfo), // V9 -> V10:v0.6.20
|
||||
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
|
||||
NewMigration("refactor attachment table", attachmentRefactor), // V7 -> V8:v0.6.4
|
||||
NewMigration("rename pull request fields", renamePullRequestFields), // V8 -> V9:v0.6.16
|
||||
NewMigration("clean up migrate repo info", cleanUpMigrateRepoInfo), // V9 -> V10:v0.6.20
|
||||
NewMigration("generate rands and salt for organizations", generateOrgRandsAndSalt), // V10 -> V11:v0.8.5
|
||||
}
|
||||
|
||||
// Migrate database to current version
|
||||
@@ -422,3 +424,32 @@ func cleanUpMigrateRepoInfo(x *xorm.Engine) (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateOrgRandsAndSalt(x *xorm.Engine) (err error) {
|
||||
type User struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Rands string `xorm:"VARCHAR(10)"`
|
||||
Salt string `xorm:"VARCHAR(10)"`
|
||||
}
|
||||
|
||||
orgs := make([]*User, 0, 10)
|
||||
if err = x.Where("type=1").And("rands=''").Find(&orgs); err != nil {
|
||||
return fmt.Errorf("select all organizations: %v", err)
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, org := range orgs {
|
||||
org.Rands = base.GetRandomString(10)
|
||||
org.Salt = base.GetRandomString(10)
|
||||
if _, err = sess.Id(org.ID).Update(org); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
@@ -191,12 +191,7 @@ func SetEngine() (err error) {
|
||||
return fmt.Errorf("Fail to create xorm.log: %v", err)
|
||||
}
|
||||
x.SetLogger(xorm.NewSimpleLogger(f))
|
||||
|
||||
x.ShowSQL = true
|
||||
x.ShowInfo = true
|
||||
x.ShowDebug = true
|
||||
x.ShowErr = true
|
||||
x.ShowWarn = true
|
||||
x.ShowSQL(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
120
models/org.go
120
models/org.go
@@ -10,14 +10,13 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrOrgNotExist = errors.New("Organization does not exist")
|
||||
ErrTeamAlreadyExist = errors.New("Team already exist")
|
||||
ErrTeamNotExist = errors.New("Team does not exist")
|
||||
ErrTeamNameIllegal = errors.New("Team name contains illegal characters")
|
||||
ErrOrgNotExist = errors.New("Organization does not exist")
|
||||
ErrTeamNotExist = errors.New("Team does not exist")
|
||||
)
|
||||
|
||||
// IsOwnedBy returns true if given user is in the owner team.
|
||||
@@ -108,6 +107,8 @@ func CreateOrganization(org, owner *User) (err error) {
|
||||
|
||||
org.LowerName = strings.ToLower(org.Name)
|
||||
org.FullName = org.Name
|
||||
org.Rands = GetUserSalt()
|
||||
org.Salt = GetUserSalt()
|
||||
org.UseCustomAvatar = true
|
||||
org.MaxRepoCreation = -1
|
||||
org.NumTeams = 1
|
||||
@@ -253,6 +254,27 @@ func IsPublicMembership(orgId, uid int64) bool {
|
||||
return has
|
||||
}
|
||||
|
||||
func getOrgsByUserID(sess *xorm.Session, userID int64, showAll bool) ([]*User, error) {
|
||||
orgs := make([]*User, 0, 10)
|
||||
if !showAll {
|
||||
sess.And("`org_user`.is_public=?", true)
|
||||
}
|
||||
return orgs, sess.And("`org_user`.uid=?", userID).
|
||||
Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
|
||||
}
|
||||
|
||||
// GetOrgsByUserID returns a list of organizations that the given user ID
|
||||
// has joined.
|
||||
func GetOrgsByUserID(userID int64, showAll bool) ([]*User, error) {
|
||||
return getOrgsByUserID(x.NewSession(), userID, showAll)
|
||||
}
|
||||
|
||||
// GetOrgsByUserIDDesc returns a list of organizations that the given user ID
|
||||
// has joined, ordered descending by the given condition.
|
||||
func GetOrgsByUserIDDesc(userID int64, desc string, showAll bool) ([]*User, error) {
|
||||
return getOrgsByUserID(x.NewSession().Desc(desc), userID, showAll)
|
||||
}
|
||||
|
||||
func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
|
||||
orgs := make([]*User, 0, 10)
|
||||
return orgs, sess.Where("`org_user`.uid=?", userID).And("`org_user`.is_owner=?", true).
|
||||
@@ -266,16 +288,21 @@ func GetOwnedOrgsByUserID(userID int64) ([]*User, error) {
|
||||
}
|
||||
|
||||
// GetOwnedOrganizationsByUserIDDesc returns a list of organizations are owned by
|
||||
// given user ID and descring order by given condition.
|
||||
// given user ID, ordered descending by the given condition.
|
||||
func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
|
||||
sess := x.NewSession()
|
||||
return getOwnedOrgsByUserID(sess.Desc(desc), userID)
|
||||
}
|
||||
|
||||
// GetOrgUsersByUserId returns all organization-user relations by user ID.
|
||||
func GetOrgUsersByUserId(uid int64) ([]*OrgUser, error) {
|
||||
// GetOrgUsersByUserID returns all organization-user relations by user ID.
|
||||
func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
|
||||
ous := make([]*OrgUser, 0, 10)
|
||||
err := x.Where("uid=?", uid).Find(&ous)
|
||||
sess := x.Where("uid=?", uid)
|
||||
if !all {
|
||||
// Only show public organizations
|
||||
sess.And("is_public=?", true)
|
||||
}
|
||||
err := sess.Find(&ous)
|
||||
return ous, err
|
||||
}
|
||||
|
||||
@@ -591,9 +618,9 @@ func (t *Team) RemoveRepository(repoID int64) error {
|
||||
|
||||
// NewTeam creates a record of new team.
|
||||
// It's caller's responsibility to assign organization ID.
|
||||
func NewTeam(t *Team) (err error) {
|
||||
if err = IsUsableName(t.Name); err != nil {
|
||||
return err
|
||||
func NewTeam(t *Team) error {
|
||||
if len(t.Name) == 0 {
|
||||
return errors.New("empty team name")
|
||||
}
|
||||
|
||||
has, err := x.Id(t.OrgID).Get(new(User))
|
||||
@@ -608,7 +635,7 @@ func NewTeam(t *Team) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
return ErrTeamAlreadyExist
|
||||
return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
@@ -667,8 +694,8 @@ func GetTeamById(teamId int64) (*Team, error) {
|
||||
|
||||
// UpdateTeam updates information of team.
|
||||
func UpdateTeam(t *Team, authChanged bool) (err error) {
|
||||
if err = IsUsableName(t.Name); err != nil {
|
||||
return err
|
||||
if len(t.Name) == 0 {
|
||||
return errors.New("empty team name")
|
||||
}
|
||||
|
||||
if len(t.Description) > 255 {
|
||||
@@ -682,6 +709,13 @@ func UpdateTeam(t *Team, authChanged bool) (err error) {
|
||||
}
|
||||
|
||||
t.LowerName = strings.ToLower(t.Name)
|
||||
has, err := x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).And("id!=?", t.ID).Get(new(Team))
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
|
||||
}
|
||||
|
||||
if _, err = sess.Id(t.ID).AllCols().Update(t); err != nil {
|
||||
return fmt.Errorf("update: %v", err)
|
||||
}
|
||||
@@ -1016,3 +1050,61 @@ func removeOrgRepo(e Engine, orgID, repoID int64) error {
|
||||
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) {
|
||||
teams := make([]*Team, 0, 10)
|
||||
if err = x.Cols("`team`.id").
|
||||
Where("`team_user`.org_id=?", org.Id).
|
||||
And("`team_user`.uid=?", userID).
|
||||
Join("INNER", "`team_user`", "`team_user`.team_id=`team`.id").
|
||||
Find(&teams); err != nil {
|
||||
return fmt.Errorf("GetUserRepositories: get teams: %v", err)
|
||||
}
|
||||
|
||||
teamIDs := make([]string, len(teams))
|
||||
for i := range teams {
|
||||
teamIDs[i] = com.ToStr(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
|
||||
}
|
||||
|
||||
// Due to a bug in xorm using IN() together with OR() is impossible.
|
||||
// As a workaround, we have to build the IN statement on our own, until this is fixed.
|
||||
// https://github.com/go-xorm/xorm/issues/342
|
||||
|
||||
if err = x.Cols("`repository`.*").
|
||||
Join("INNER", "`team_repo`", "`team_repo`.repo_id=`repository`.id").
|
||||
Where("`repository`.owner_id=?", org.Id).
|
||||
And("`repository`.is_private=?", false).
|
||||
Or("`team_repo`.team_id=(?)", strings.Join(teamIDs, ",")).
|
||||
GroupBy("`repository`.id").
|
||||
Find(&org.Repos); err != nil {
|
||||
return fmt.Errorf("GetUserRepositories: get repositories: %v", err)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// GetTeams returns all teams that belong to organization,
|
||||
// and that the user has joined.
|
||||
func (org *User) GetUserTeams(userID int64) error {
|
||||
if err := x.Cols("`team`.*").
|
||||
Where("`team_user`.org_id=?", org.Id).
|
||||
And("`team_user`.uid=?", userID).
|
||||
Join("INNER", "`team_user`", "`team_user`.team_id=`team`.id").
|
||||
Find(&org.Teams); err != nil {
|
||||
return fmt.Errorf("GetUserTeams: %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
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
"github.com/gogits/git-shell"
|
||||
"github.com/gogits/git-module"
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
@@ -256,6 +256,7 @@ var patchConflicts = []string{
|
||||
"patch does not apply",
|
||||
"already exists in working directory",
|
||||
"unrecognized input",
|
||||
"error:",
|
||||
}
|
||||
|
||||
// testPatch checks if patch can be merged to base repository without conflit.
|
||||
@@ -279,7 +280,7 @@ func (pr *PullRequest) testPatch() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Trace("PullRequest[%d].testPatch(patchPath): %s", pr.ID, patchPath)
|
||||
log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)
|
||||
|
||||
if err := pr.BaseRepo.UpdateLocalCopy(); err != nil {
|
||||
return fmt.Errorf("UpdateLocalCopy: %v", err)
|
||||
@@ -287,7 +288,7 @@ func (pr *PullRequest) testPatch() (err error) {
|
||||
|
||||
// Checkout base branch.
|
||||
_, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
|
||||
fmt.Sprintf("PullRequest.Merge(git checkout): %v", pr.BaseRepo.ID),
|
||||
fmt.Sprintf("PullRequest.Merge (git checkout): %v", pr.BaseRepo.ID),
|
||||
"git", "checkout", pr.BaseBranch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("git checkout: %s", stderr)
|
||||
@@ -295,12 +296,12 @@ func (pr *PullRequest) testPatch() (err error) {
|
||||
|
||||
pr.Status = PULL_REQUEST_STATUS_CHECKING
|
||||
_, stderr, err = process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
|
||||
fmt.Sprintf("testPatch(git apply --check): %d", pr.BaseRepo.ID),
|
||||
fmt.Sprintf("testPatch (git apply --check): %d", pr.BaseRepo.ID),
|
||||
"git", "apply", "--check", patchPath)
|
||||
if err != nil {
|
||||
for i := range patchConflicts {
|
||||
if strings.Contains(stderr, patchConflicts[i]) {
|
||||
log.Trace("PullRequest[%d].testPatch(apply): has conflit", pr.ID)
|
||||
log.Trace("PullRequest[%d].testPatch (apply): has conflit", pr.ID)
|
||||
fmt.Println(stderr)
|
||||
pr.Status = PULL_REQUEST_STATUS_CONFLICT
|
||||
return nil
|
||||
@@ -329,7 +330,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
|
||||
ActUserID: pull.Poster.Id,
|
||||
ActUserName: pull.Poster.Name,
|
||||
ActEmail: pull.Poster.Email,
|
||||
OpType: CREATE_PULL_REQUEST,
|
||||
OpType: ACTION_CREATE_PULL_REQUEST,
|
||||
Content: fmt.Sprintf("%d|%s", pull.Index, pull.Name),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
@@ -481,6 +482,33 @@ func (pr *PullRequest) UpdatePatch() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PushToBaseRepo pushes commits from branches of head repository to
|
||||
// corresponding branches of base repository.
|
||||
// FIXME: could fail after user force push head repo, should we always force push here?
|
||||
// FIXME: Only push branches that are actually updates?
|
||||
func (pr *PullRequest) PushToBaseRepo() (err error) {
|
||||
log.Trace("PushToBaseRepo[%[1]d]: pushing commits to base repo 'refs/pull/%[1]d/head'", pr.ID)
|
||||
|
||||
headRepoPath := pr.HeadRepo.RepoPath()
|
||||
headGitRepo, err := git.OpenRepository(headRepoPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("OpenRepository: %v", err)
|
||||
}
|
||||
|
||||
tmpRemoteName := fmt.Sprintf("tmp-pull-%d", pr.ID)
|
||||
if err = headGitRepo.AddRemote(tmpRemoteName, pr.BaseRepo.RepoPath(), false); err != nil {
|
||||
return fmt.Errorf("headGitRepo.AddRemote: %v", err)
|
||||
}
|
||||
// Make sure to remove the remote even if the push fails
|
||||
defer headGitRepo.RemoveRemote(tmpRemoteName)
|
||||
|
||||
if err = git.Push(headRepoPath, tmpRemoteName, fmt.Sprintf("%s:refs/pull/%d/head", pr.HeadBranch, pr.Index)); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddToTaskQueue adds itself to pull request test task queue.
|
||||
func (pr *PullRequest) AddToTaskQueue() {
|
||||
go PullRequestQueue.AddFunc(pr.ID, func() {
|
||||
@@ -497,6 +525,9 @@ func addHeadRepoTasks(prs []*PullRequest) {
|
||||
if err := pr.UpdatePatch(); err != nil {
|
||||
log.Error(4, "UpdatePatch: %v", err)
|
||||
continue
|
||||
} else if err := pr.PushToBaseRepo(); err != nil {
|
||||
log.Error(4, "PushToBaseRepo: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
pr.AddToTaskQueue()
|
||||
@@ -525,6 +556,14 @@ func AddTestPullRequestTask(repoID int64, branch string) {
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeUsernameInPullRequests(oldUserName, newUserName string) error {
|
||||
pr := PullRequest{
|
||||
HeadUserName: strings.ToLower(newUserName),
|
||||
}
|
||||
_, err := x.Cols("head_user_name").Where("head_user_name = ?", strings.ToLower(oldUserName)).Update(pr)
|
||||
return err
|
||||
}
|
||||
|
||||
// checkAndUpdateStatus checks if pull request is possible to levaing checking status,
|
||||
// and set to be either conflict or mergeable.
|
||||
func (pr *PullRequest) checkAndUpdateStatus() {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
"github.com/gogits/git-shell"
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/modules/process"
|
||||
)
|
||||
|
||||
146
models/repo.go
146
models/repo.go
@@ -27,12 +27,12 @@ import (
|
||||
"github.com/mcuadros/go-version"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"github.com/gogits/git-shell"
|
||||
"github.com/gogits/git-module"
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/bindata"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/markdown"
|
||||
"github.com/gogits/gogs/modules/process"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
@@ -129,6 +129,8 @@ func NewRepoContext() {
|
||||
log.Fatal(4, "Fail to execute 'git config --global core.quotepath false': %s", stderr)
|
||||
}
|
||||
|
||||
// Clean up temporary data.
|
||||
os.RemoveAll(filepath.Join(setting.AppDataPath, "tmp"))
|
||||
}
|
||||
|
||||
// Repository represents a git repository.
|
||||
@@ -330,7 +332,17 @@ func (repo *Repository) IsOwnedBy(userID int64) bool {
|
||||
|
||||
// CanBeForked returns true if repository meets the requirements of being forked.
|
||||
func (repo *Repository) CanBeForked() bool {
|
||||
return !repo.IsBare && !repo.IsMirror
|
||||
return !repo.IsBare
|
||||
}
|
||||
|
||||
// CanEnablePulls returns true if repository meets the requirements of accepting pulls.
|
||||
func (repo *Repository) CanEnablePulls() bool {
|
||||
return !repo.IsMirror
|
||||
}
|
||||
|
||||
// AllowPulls returns true if repository meets the requirements of accepting pulls and has them enabled.
|
||||
func (repo *Repository) AllowsPulls() bool {
|
||||
return repo.CanEnablePulls() && repo.EnablePulls
|
||||
}
|
||||
|
||||
func (repo *Repository) NextIssueIndex() int64 {
|
||||
@@ -346,7 +358,7 @@ func (repo *Repository) DescriptionHtml() template.HTML {
|
||||
sanitize := func(s string) string {
|
||||
return fmt.Sprintf(`<a href="%[1]s" target="_blank">%[1]s</a>`, s)
|
||||
}
|
||||
return template.HTML(DescPattern.ReplaceAllStringFunc(base.Sanitizer.Sanitize(repo.Description), sanitize))
|
||||
return template.HTML(DescPattern.ReplaceAllStringFunc(markdown.Sanitizer.Sanitize(repo.Description), sanitize))
|
||||
}
|
||||
|
||||
func (repo *Repository) LocalCopyPath() string {
|
||||
@@ -400,7 +412,7 @@ func (repo *Repository) ComposePayload() *api.PayloadRepo {
|
||||
cl := repo.CloneLink()
|
||||
return &api.PayloadRepo{
|
||||
ID: repo.ID,
|
||||
Name: repo.LowerName,
|
||||
Name: repo.Name,
|
||||
URL: repo.FullRepoLink(),
|
||||
SSHURL: cl.SSH,
|
||||
CloneURL: cl.HTTPS,
|
||||
@@ -412,7 +424,8 @@ func (repo *Repository) ComposePayload() *api.PayloadRepo {
|
||||
Email: repo.MustOwner().Email,
|
||||
UserName: repo.MustOwner().Name,
|
||||
},
|
||||
Private: repo.IsPrivate,
|
||||
Private: repo.IsPrivate,
|
||||
DefaultBranch: repo.DefaultBranch,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,6 +602,11 @@ func UpdateMirror(m *Mirror) error {
|
||||
return updateMirror(x, m)
|
||||
}
|
||||
|
||||
func DeleteMirrorByRepoID(repoID int64) error {
|
||||
_, err := x.Delete(&Mirror{RepoID: repoID})
|
||||
return err
|
||||
}
|
||||
|
||||
func createUpdateHook(repoPath string) error {
|
||||
return git.SetUpdateHook(repoPath,
|
||||
fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf))
|
||||
@@ -652,7 +670,12 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
|
||||
return repo, UpdateRepository(repo, false)
|
||||
}
|
||||
|
||||
if err = createUpdateHook(repoPath); err != nil {
|
||||
return CleanUpMigrateInfo(repo, repoPath)
|
||||
}
|
||||
|
||||
// Finish migrating repository with things that don't need to be done for mirrors.
|
||||
func CleanUpMigrateInfo(repo *Repository, repoPath string) (*Repository, error) {
|
||||
if err := createUpdateHook(repoPath); err != nil {
|
||||
return repo, fmt.Errorf("createUpdateHook: %v", err)
|
||||
}
|
||||
|
||||
@@ -955,10 +978,13 @@ func countRepositories(showPrivate bool) int64 {
|
||||
sess := x.NewSession()
|
||||
|
||||
if !showPrivate {
|
||||
sess.Where("is_private=", false)
|
||||
sess.Where("is_private=?", false)
|
||||
}
|
||||
|
||||
count, _ := sess.Count(new(Repository))
|
||||
count, err := sess.Count(new(Repository))
|
||||
if err != nil {
|
||||
log.Error(4, "countRepositories: %v", err)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
@@ -1091,13 +1117,16 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error {
|
||||
return fmt.Errorf("transferRepoAction: %v", err)
|
||||
}
|
||||
|
||||
// Change repository directory name.
|
||||
// Rename remote repository to new path and delete local copy.
|
||||
if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil {
|
||||
return fmt.Errorf("rename repository directory: %v", err)
|
||||
}
|
||||
RemoveAllWithNotice("Delete repository local copy", repo.LocalCopyPath())
|
||||
|
||||
// Rename remote wiki repository to new path and delete local copy.
|
||||
wikiPath := WikiPath(owner.Name, repo.Name)
|
||||
if com.IsExist(wikiPath) {
|
||||
RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
|
||||
if err = os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil {
|
||||
return fmt.Errorf("rename repository wiki: %v", err)
|
||||
}
|
||||
@@ -1121,16 +1150,22 @@ func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error)
|
||||
return ErrRepoAlreadyExist{u.Name, newRepoName}
|
||||
}
|
||||
|
||||
repo, err := GetRepositoryByName(u.Id, oldRepoName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetRepositoryByName: %v", err)
|
||||
}
|
||||
|
||||
// Change repository directory name.
|
||||
if err = os.Rename(RepoPath(u.Name, oldRepoName), RepoPath(u.Name, newRepoName)); err != nil {
|
||||
if err = os.Rename(repo.RepoPath(), RepoPath(u.Name, newRepoName)); err != nil {
|
||||
return fmt.Errorf("rename repository directory: %v", err)
|
||||
}
|
||||
|
||||
wikiPath := WikiPath(u.Name, oldRepoName)
|
||||
wikiPath := repo.WikiPath()
|
||||
if com.IsExist(wikiPath) {
|
||||
if err = os.Rename(wikiPath, WikiPath(u.Name, newRepoName)); err != nil {
|
||||
return fmt.Errorf("rename repository wiki: %v", err)
|
||||
}
|
||||
RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -1293,28 +1328,16 @@ func DeleteRepository(uid, repoID int64) error {
|
||||
|
||||
// Remove repository files.
|
||||
repoPath := repo.repoPath(sess)
|
||||
if err = os.RemoveAll(repoPath); err != nil {
|
||||
desc := fmt.Sprintf("delete repository files [%s]: %v", repoPath, err)
|
||||
log.Warn(desc)
|
||||
if err = CreateRepositoryNotice(desc); err != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
}
|
||||
RemoveAllWithNotice("Delete repository files", repoPath)
|
||||
|
||||
wikiPath := repo.WikiPath()
|
||||
if err = os.RemoveAll(wikiPath); err != nil {
|
||||
desc := fmt.Sprintf("delete repository wiki [%s]: %v", wikiPath, err)
|
||||
log.Warn(desc)
|
||||
if err = CreateRepositoryNotice(desc); err != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
wikiPaths := []string{repo.WikiPath(), repo.LocalWikiPath()}
|
||||
for _, wikiPath := range wikiPaths {
|
||||
RemoveAllWithNotice("Delete repository wiki", wikiPath)
|
||||
}
|
||||
|
||||
// Remove attachment files.
|
||||
for i := range attachmentPaths {
|
||||
if err = os.Remove(attachmentPaths[i]); err != nil {
|
||||
log.Warn("delete attachment: %v", err)
|
||||
}
|
||||
RemoveAllWithNotice("Delete attachment", attachmentPaths[i])
|
||||
}
|
||||
|
||||
if err = sess.Commit(); err != nil {
|
||||
@@ -1329,7 +1352,7 @@ func DeleteRepository(uid, repoID int64) error {
|
||||
}
|
||||
for i := range forkRepos {
|
||||
if err = DeleteRepository(forkRepos[i].OwnerID, forkRepos[i].ID); err != nil {
|
||||
log.Error(4, "updateRepository[%d]: %v", forkRepos[i].ID, err)
|
||||
log.Error(4, "DeleteRepository [%d]: %v", forkRepos[i].ID, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1453,9 +1476,8 @@ func DeleteRepositoryArchives() error {
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteMissingRepositories deletes all repository records that lost Git files.
|
||||
func DeleteMissingRepositories() error {
|
||||
repos := make([]*Repository, 0, 5)
|
||||
func gatherMissingRepoRecords() ([]*Repository, error) {
|
||||
repos := make([]*Repository, 0, 10)
|
||||
if err := x.Where("id > 0").Iterate(new(Repository),
|
||||
func(idx int, bean interface{}) error {
|
||||
repo := bean.(*Repository)
|
||||
@@ -1464,10 +1486,18 @@ func DeleteMissingRepositories() error {
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteMissingRepositories: %v", err)); err2 != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err2)
|
||||
if err2 := CreateRepositoryNotice(fmt.Sprintf("gatherMissingRepoRecords: %v", err)); err2 != nil {
|
||||
return nil, fmt.Errorf("CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
// DeleteMissingRepositories deletes all repository records that lost Git files.
|
||||
func DeleteMissingRepositories() error {
|
||||
repos, err := gatherMissingRepoRecords()
|
||||
if err != nil {
|
||||
return fmt.Errorf("gatherMissingRepoRecords: %v", err)
|
||||
}
|
||||
|
||||
if len(repos) == 0 {
|
||||
@@ -1478,7 +1508,29 @@ func DeleteMissingRepositories() error {
|
||||
log.Trace("Deleting %d/%d...", repo.OwnerID, repo.ID)
|
||||
if err := DeleteRepository(repo.OwnerID, repo.ID); err != nil {
|
||||
if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepository [%d]: %v", repo.ID, err)); err2 != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err2)
|
||||
return fmt.Errorf("CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReinitMissingRepositories reinitializes all repository records that lost Git files.
|
||||
func ReinitMissingRepositories() error {
|
||||
repos, err := gatherMissingRepoRecords()
|
||||
if err != nil {
|
||||
return fmt.Errorf("gatherMissingRepoRecords: %v", err)
|
||||
}
|
||||
|
||||
if len(repos) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, repo := range repos {
|
||||
log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID)
|
||||
if err := git.InitRepository(repo.RepoPath(), true); err != nil {
|
||||
if err2 := CreateRepositoryNotice(fmt.Sprintf("InitRepository [%d]: %v", repo.ID, err)); err2 != nil {
|
||||
return fmt.Errorf("CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1598,7 +1650,7 @@ func GitFsck() {
|
||||
repo := bean.(*Repository)
|
||||
repoPath := repo.RepoPath()
|
||||
if err := git.Fsck(repoPath, setting.Cron.RepoHealthCheck.Timeout, setting.Cron.RepoHealthCheck.Args...); err != nil {
|
||||
desc := fmt.Sprintf("Fail to health check repository(%s)", repoPath)
|
||||
desc := fmt.Sprintf("Fail to health check repository (%s): %v", repoPath, err)
|
||||
log.Warn(desc)
|
||||
if err = CreateRepositoryNotice(desc); err != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err)
|
||||
@@ -1886,8 +1938,13 @@ func GetWatchers(repoID int64) ([]*Watch, error) {
|
||||
// Repository.GetWatchers returns range of users watching given repository.
|
||||
func (repo *Repository) GetWatchers(page int) ([]*User, error) {
|
||||
users := make([]*User, 0, ItemsPerPage)
|
||||
return users, x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).
|
||||
Where("repo_id=?", repo.ID).Join("LEFT", "watch", "user.id=watch.user_id").Find(&users)
|
||||
sess := x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).Where("watch.repo_id=?", repo.ID)
|
||||
if setting.UsePostgreSQL {
|
||||
sess = sess.Join("LEFT", "watch", `"user".id=watch.user_id`)
|
||||
} else {
|
||||
sess = sess.Join("LEFT", "watch", "user.id=watch.user_id")
|
||||
}
|
||||
return users, sess.Find(&users)
|
||||
}
|
||||
|
||||
func notifyWatchers(e Engine, act *Action) error {
|
||||
@@ -1969,8 +2026,13 @@ func IsStaring(uid, repoId int64) bool {
|
||||
|
||||
func (repo *Repository) GetStargazers(page int) ([]*User, error) {
|
||||
users := make([]*User, 0, ItemsPerPage)
|
||||
return users, x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).
|
||||
Where("repo_id=?", repo.ID).Join("LEFT", "star", "user.id=star.uid").Find(&users)
|
||||
sess := x.Limit(ItemsPerPage, (page-1)*ItemsPerPage).Where("star.repo_id=?", repo.ID)
|
||||
if setting.UsePostgreSQL {
|
||||
sess = sess.Join("LEFT", "star", `"user".id=star.uid`)
|
||||
} else {
|
||||
sess = sess.Join("LEFT", "star", "user.id=star.uid")
|
||||
}
|
||||
return users, sess.Find(&users)
|
||||
}
|
||||
|
||||
// ___________ __
|
||||
|
||||
57
models/repo_branch.go
Normal file
57
models/repo_branch.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// 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 (
|
||||
"github.com/gogits/git-module"
|
||||
)
|
||||
|
||||
type Branch struct {
|
||||
Path string
|
||||
Name string
|
||||
}
|
||||
|
||||
func GetBranchesByPath(path string) ([]*Branch, error) {
|
||||
gitRepo, err := git.OpenRepository(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
brs, err := gitRepo.GetBranches()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
branches := make([]*Branch, len(brs))
|
||||
for i := range brs {
|
||||
branches[i] = &Branch{
|
||||
Path: path,
|
||||
Name: brs[i],
|
||||
}
|
||||
}
|
||||
return branches, nil
|
||||
}
|
||||
|
||||
func (repo *Repository) GetBranch(br string) (*Branch, error) {
|
||||
if !git.IsBranchExist(repo.RepoPath(), br) {
|
||||
return nil, &ErrBranchNotExist{br}
|
||||
}
|
||||
return &Branch{
|
||||
Path: repo.RepoPath(),
|
||||
Name: br,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (repo *Repository) GetBranches() ([]*Branch, error) {
|
||||
return GetBranchesByPath(repo.RepoPath())
|
||||
}
|
||||
|
||||
func (br *Branch) GetCommit() (*git.Commit, error) {
|
||||
gitRepo, err := git.OpenRepository(br.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gitRepo.GetBranchCommit(br.Name)
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/process"
|
||||
@@ -33,24 +34,6 @@ const (
|
||||
)
|
||||
|
||||
var sshOpLocker = sync.Mutex{}
|
||||
var SSHPath string // SSH directory.
|
||||
|
||||
// homeDir returns the home directory of current user.
|
||||
func homeDir() string {
|
||||
home, err := com.HomeDir()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Fail to get home directory: %v", err)
|
||||
}
|
||||
return home
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Determine and create .ssh path.
|
||||
SSHPath = filepath.Join(homeDir(), ".ssh")
|
||||
if err := os.MkdirAll(SSHPath, 0700); err != nil {
|
||||
log.Fatal(4, "fail to create '%s': %v", SSHPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
type KeyType int
|
||||
|
||||
@@ -182,48 +165,23 @@ func CheckPublicKeyString(content string) (_ string, err error) {
|
||||
return "", errors.New("only a single line with a single key please")
|
||||
}
|
||||
|
||||
// write the key to a file…
|
||||
tmpFile, err := ioutil.TempFile(os.TempDir(), "keytest")
|
||||
// remove any unnecessary whitespace now
|
||||
content = strings.TrimSpace(content)
|
||||
|
||||
fields := strings.Fields(content)
|
||||
if len(fields) < 2 {
|
||||
return "", errors.New("too less fields")
|
||||
}
|
||||
|
||||
key, err := base64.StdEncoding.DecodeString(fields[1])
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("StdEncoding.DecodeString: %v", err)
|
||||
}
|
||||
tmpPath := tmpFile.Name()
|
||||
defer os.Remove(tmpPath)
|
||||
tmpFile.WriteString(content)
|
||||
tmpFile.Close()
|
||||
|
||||
// Check if ssh-keygen recognizes its contents.
|
||||
stdout, stderr, err := process.Exec("CheckPublicKeyString", "ssh-keygen", "-lf", tmpPath)
|
||||
pkey, err := ssh.ParsePublicKey([]byte(key))
|
||||
if err != nil {
|
||||
return "", errors.New("ssh-keygen -lf: " + stderr)
|
||||
} else if len(stdout) < 2 {
|
||||
return "", errors.New("ssh-keygen returned not enough output to evaluate the key: " + stdout)
|
||||
}
|
||||
|
||||
// The ssh-keygen in Windows does not print key type, so no need go further.
|
||||
if setting.IsWindows {
|
||||
return content, nil
|
||||
}
|
||||
|
||||
sshKeygenOutput := strings.Split(stdout, " ")
|
||||
if len(sshKeygenOutput) < 4 {
|
||||
return content, ErrKeyUnableVerify{stdout}
|
||||
}
|
||||
|
||||
// Check if key type and key size match.
|
||||
if !setting.Service.DisableMinimumKeySizeCheck {
|
||||
keySize := com.StrTo(sshKeygenOutput[0]).MustInt()
|
||||
if keySize == 0 {
|
||||
return "", errors.New("cannot get key size of the given key")
|
||||
}
|
||||
|
||||
keyType := strings.Trim(sshKeygenOutput[len(sshKeygenOutput)-1], " ()\n")
|
||||
if minimumKeySize := setting.Service.MinimumKeySizes[keyType]; minimumKeySize == 0 {
|
||||
return "", fmt.Errorf("unrecognized public key type: %s", keyType)
|
||||
} else if keySize < minimumKeySize {
|
||||
return "", fmt.Errorf("the minimum accepted size of a public key %s is %d", keyType, minimumKeySize)
|
||||
}
|
||||
return "", fmt.Errorf("ParsePublicKey: %v", err)
|
||||
}
|
||||
log.Trace("Key type: %s", pkey.Type())
|
||||
|
||||
return content, nil
|
||||
}
|
||||
@@ -233,7 +191,7 @@ func saveAuthorizedKeyFile(keys ...*PublicKey) error {
|
||||
sshOpLocker.Lock()
|
||||
defer sshOpLocker.Unlock()
|
||||
|
||||
fpath := filepath.Join(SSHPath, "authorized_keys")
|
||||
fpath := filepath.Join(setting.SSHRootPath, "authorized_keys")
|
||||
f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -419,6 +377,11 @@ func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !isFound {
|
||||
log.Warn("SSH key %d not found in authorized_keys file for deletion", key.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -449,8 +412,8 @@ func deletePublicKey(e *xorm.Session, keyID int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
fpath := filepath.Join(SSHPath, "authorized_keys")
|
||||
tmpPath := filepath.Join(SSHPath, "authorized_keys.tmp")
|
||||
fpath := filepath.Join(setting.SSHRootPath, "authorized_keys")
|
||||
tmpPath := filepath.Join(setting.SSHRootPath, "authorized_keys.tmp")
|
||||
if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil {
|
||||
return err
|
||||
} else if err = os.Remove(fpath); err != nil {
|
||||
@@ -492,7 +455,7 @@ func RewriteAllPublicKeys() error {
|
||||
sshOpLocker.Lock()
|
||||
defer sshOpLocker.Unlock()
|
||||
|
||||
tmpPath := filepath.Join(SSHPath, "authorized_keys.tmp")
|
||||
tmpPath := filepath.Join(setting.SSHRootPath, "authorized_keys.tmp")
|
||||
f, err := os.OpenFile(tmpPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -508,7 +471,7 @@ func RewriteAllPublicKeys() error {
|
||||
return err
|
||||
}
|
||||
|
||||
fpath := filepath.Join(SSHPath, "authorized_keys")
|
||||
fpath := filepath.Join(setting.SSHRootPath, "authorized_keys")
|
||||
if com.IsExist(fpath) {
|
||||
if err = os.Remove(fpath); err != nil {
|
||||
return err
|
||||
|
||||
@@ -7,8 +7,9 @@ package models
|
||||
import (
|
||||
"time"
|
||||
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
|
||||
// AccessToken represents a personal access token.
|
||||
@@ -25,7 +26,7 @@ type AccessToken struct {
|
||||
|
||||
// NewAccessToken creates new access token.
|
||||
func NewAccessToken(t *AccessToken) error {
|
||||
t.Sha1 = base.EncodeSha1(uuid.NewV4().String())
|
||||
t.Sha1 = base.EncodeSha1(gouuid.NewV4().String())
|
||||
_, err := x.Insert(t)
|
||||
return err
|
||||
}
|
||||
@@ -57,8 +58,8 @@ func ListAccessTokens(uid int64) ([]*AccessToken, error) {
|
||||
return tokens, nil
|
||||
}
|
||||
|
||||
// UpdateAccessToekn updates information of access token.
|
||||
func UpdateAccessToekn(t *AccessToken) error {
|
||||
// UpdateAccessToken updates information of access token.
|
||||
func UpdateAccessToken(t *AccessToken) error {
|
||||
_, err := x.Id(t.ID).AllCols().Update(t)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
git "github.com/gogits/git-shell"
|
||||
git "github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
)
|
||||
@@ -65,94 +65,104 @@ func ListToPushCommits(l *list.List) *PushCommits {
|
||||
return &PushCommits{l.Len(), commits, "", nil}
|
||||
}
|
||||
|
||||
func Update(refName, oldCommitID, newCommitID, userName, repoUserName, repoName string, userID int64) error {
|
||||
isNew := strings.HasPrefix(oldCommitID, "0000000")
|
||||
if isNew &&
|
||||
strings.HasPrefix(newCommitID, "0000000") {
|
||||
return fmt.Errorf("old rev and new rev both 000000")
|
||||
type PushUpdateOptions struct {
|
||||
RefName string
|
||||
OldCommitID string
|
||||
NewCommitID string
|
||||
PusherID int64
|
||||
PusherName string
|
||||
RepoUserName string
|
||||
RepoName 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")
|
||||
if isNewRef && isDelRef {
|
||||
return fmt.Errorf("Old and new revisions both start with 000000")
|
||||
}
|
||||
|
||||
f := RepoPath(repoUserName, repoName)
|
||||
repoPath := RepoPath(opts.RepoUserName, opts.RepoName)
|
||||
|
||||
gitUpdate := exec.Command("git", "update-server-info")
|
||||
gitUpdate.Dir = f
|
||||
gitUpdate.Run()
|
||||
gitUpdate.Dir = repoPath
|
||||
if err = gitUpdate.Run(); err != nil {
|
||||
return fmt.Errorf("Fail to call 'git update-server-info': %v", err)
|
||||
}
|
||||
|
||||
isDel := strings.HasPrefix(newCommitID, "0000000")
|
||||
if isDel {
|
||||
log.GitLogger.Info("del rev", refName, "from", userName+"/"+repoName+".git", "by", userID)
|
||||
if isDelRef {
|
||||
log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %d",
|
||||
opts.RefName, opts.RepoUserName, opts.RepoName, opts.PusherName)
|
||||
return nil
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(f)
|
||||
gitRepo, err := git.OpenRepository(repoPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("runUpdate.Open repoId: %v", err)
|
||||
return fmt.Errorf("OpenRepository: %v", err)
|
||||
}
|
||||
|
||||
user, err := GetUserByName(repoUserName)
|
||||
repoUser, err := GetUserByName(opts.RepoUserName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("runUpdate.GetUserByName: %v", err)
|
||||
return fmt.Errorf("GetUserByName: %v", err)
|
||||
}
|
||||
|
||||
repo, err := GetRepositoryByName(user.Id, repoName)
|
||||
repo, err := GetRepositoryByName(repoUser.Id, opts.RepoName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("runUpdate.GetRepositoryByName userId: %v", err)
|
||||
return fmt.Errorf("GetRepositoryByName: %v", err)
|
||||
}
|
||||
|
||||
// Push tags.
|
||||
if strings.HasPrefix(refName, "refs/tags/") {
|
||||
tagName := git.RefEndName(refName)
|
||||
tag, err := gitRepo.GetTag(tagName)
|
||||
if strings.HasPrefix(opts.RefName, "refs/tags/") {
|
||||
tag, err := gitRepo.GetTag(git.RefEndName(opts.RefName))
|
||||
if err != nil {
|
||||
log.GitLogger.Fatal(4, "runUpdate.GetTag: %v", err)
|
||||
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 {
|
||||
log.GitLogger.Fatal(4, "runUpdate.GetTag Commit: %v", err)
|
||||
return fmt.Errorf("tag.Commit: %v", err)
|
||||
}
|
||||
actEmail = cmt.Committer.Email
|
||||
}
|
||||
|
||||
commit := &PushCommits{}
|
||||
|
||||
if err = CommitRepoAction(userID, user.Id, userName, actEmail,
|
||||
repo.ID, repoUserName, repoName, refName, commit, oldCommitID, newCommitID); err != nil {
|
||||
log.GitLogger.Fatal(4, "CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
|
||||
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 {
|
||||
return fmt.Errorf("CommitRepoAction (tag): %v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
newCommit, err := gitRepo.GetCommit(newCommitID)
|
||||
newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("runUpdate GetCommit of newCommitId: %v", err)
|
||||
return fmt.Errorf("gitRepo.GetCommit: %v", err)
|
||||
}
|
||||
|
||||
// Push new branch.
|
||||
var l *list.List
|
||||
if isNew {
|
||||
if isNewRef {
|
||||
l, err = newCommit.CommitsBeforeLimit(10)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsBefore: %v", err)
|
||||
return fmt.Errorf("newCommit.CommitsBeforeLimit: %v", err)
|
||||
}
|
||||
} else {
|
||||
l, err = newCommit.CommitsBeforeUntil(oldCommitID)
|
||||
l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsBeforeUntil: %v", err)
|
||||
return fmt.Errorf("newCommit.CommitsBeforeUntil: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("runUpdate.Commit repoId: %v", err)
|
||||
}
|
||||
|
||||
if err = CommitRepoAction(userID, user.Id, userName, user.Email,
|
||||
repo.ID, repoUserName, repoName, refName, ListToPushCommits(l), oldCommitID, newCommitID); err != nil {
|
||||
return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
|
||||
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 {
|
||||
return fmt.Errorf("CommitRepoAction (branch): %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
243
models/user.go
243
models/user.go
@@ -16,7 +16,6 @@ import (
|
||||
_ "image/jpeg"
|
||||
"image/png"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -25,11 +24,12 @@ import (
|
||||
"github.com/go-xorm/xorm"
|
||||
"github.com/nfnt/resize"
|
||||
|
||||
"github.com/gogits/git-shell"
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -56,7 +56,7 @@ type User struct {
|
||||
LowerName string `xorm:"UNIQUE NOT NULL"`
|
||||
Name string `xorm:"UNIQUE NOT NULL"`
|
||||
FullName string
|
||||
// Email is the primary email address (to be used for communication).
|
||||
// Email is the primary email address (to be used for communication)
|
||||
Email string `xorm:"NOT NULL"`
|
||||
Passwd string `xorm:"NOT NULL"`
|
||||
LoginType LoginType
|
||||
@@ -78,24 +78,24 @@ type User struct {
|
||||
// Maximum repository creation limit, -1 means use gloabl default
|
||||
MaxRepoCreation int `xorm:"NOT NULL DEFAULT -1"`
|
||||
|
||||
// Permissions.
|
||||
// Permissions
|
||||
IsActive bool
|
||||
IsAdmin bool
|
||||
AllowGitHook bool
|
||||
AllowImportLocal bool // Allow migrate repository by local path
|
||||
|
||||
// Avatar.
|
||||
// Avatar
|
||||
Avatar string `xorm:"VARCHAR(2048) NOT NULL"`
|
||||
AvatarEmail string `xorm:"NOT NULL"`
|
||||
UseCustomAvatar bool
|
||||
|
||||
// Counters.
|
||||
NumFollowers int
|
||||
NumFollowings int
|
||||
NumStars int
|
||||
NumRepos int
|
||||
// Counters
|
||||
NumFollowers int
|
||||
NumFollowing int `xorm:"NOT NULL DEFAULT 0"`
|
||||
NumStars int
|
||||
NumRepos int
|
||||
|
||||
// For organization.
|
||||
// For organization
|
||||
Description string
|
||||
NumTeams int
|
||||
NumMembers int
|
||||
@@ -112,7 +112,7 @@ func (u *User) BeforeUpdate() {
|
||||
func (u *User) AfterSet(colName string, _ xorm.Cell) {
|
||||
switch colName {
|
||||
case "full_name":
|
||||
u.FullName = base.Sanitizer.Sanitize(u.FullName)
|
||||
u.FullName = markdown.Sanitizer.Sanitize(u.FullName)
|
||||
case "created":
|
||||
u.Created = regulateTimeZone(u.Created)
|
||||
}
|
||||
@@ -211,7 +211,7 @@ func (u *User) GenerateRandomAvatar() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("RandomImage: %v", err)
|
||||
}
|
||||
if err = os.MkdirAll(path.Dir(u.CustomAvatarPath()), os.ModePerm); err != nil {
|
||||
if err = os.MkdirAll(filepath.Dir(u.CustomAvatarPath()), os.ModePerm); err != nil {
|
||||
return fmt.Errorf("MkdirAll: %v", err)
|
||||
}
|
||||
fw, err := os.Create(u.CustomAvatarPath())
|
||||
@@ -248,8 +248,6 @@ func (u *User) RelAvatarLink() string {
|
||||
}
|
||||
|
||||
return "/avatars/" + com.ToStr(u.Id)
|
||||
case setting.Service.EnableCacheAvatar:
|
||||
return "/avatar/" + u.Avatar
|
||||
}
|
||||
return setting.GravatarSource + u.Avatar
|
||||
}
|
||||
@@ -263,6 +261,34 @@ func (u *User) AvatarLink() string {
|
||||
return link
|
||||
}
|
||||
|
||||
// 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)
|
||||
if setting.UsePostgreSQL {
|
||||
sess = sess.Join("LEFT", "follow", `"user".id=follow.user_id`)
|
||||
} else {
|
||||
sess = sess.Join("LEFT", "follow", "user.id=follow.user_id")
|
||||
}
|
||||
return users, sess.Find(&users)
|
||||
}
|
||||
|
||||
func (u *User) IsFollowing(followID int64) bool {
|
||||
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)
|
||||
if setting.UsePostgreSQL {
|
||||
sess = sess.Join("LEFT", "follow", `"user".id=follow.follow_id`)
|
||||
} else {
|
||||
sess = sess.Join("LEFT", "follow", "user.id=follow.follow_id")
|
||||
}
|
||||
return users, sess.Find(&users)
|
||||
}
|
||||
|
||||
// NewGitSig generates and returns the signature of given user.
|
||||
func (u *User) NewGitSig() *git.Signature {
|
||||
return &git.Signature{
|
||||
@@ -376,8 +402,8 @@ func (u *User) GetOwnedOrganizations() (err error) {
|
||||
}
|
||||
|
||||
// GetOrganizations returns all organizations that user belongs to.
|
||||
func (u *User) GetOrganizations() error {
|
||||
ous, err := GetOrgUsersByUserId(u.Id)
|
||||
func (u *User) GetOrganizations(all bool) error {
|
||||
ous, err := GetOrgUsersByUserID(u.Id, all)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -401,13 +427,8 @@ func (u *User) DisplayName() string {
|
||||
return u.Name
|
||||
}
|
||||
|
||||
// ShortName returns shorted user name with given maximum length,
|
||||
// it adds "..." at the end if user name has more length than maximum.
|
||||
func (u *User) ShortName(length int) string {
|
||||
if len(u.Name) < length {
|
||||
return u.Name
|
||||
}
|
||||
return u.Name[:length] + "..."
|
||||
return base.EllipsisString(u.Name, length)
|
||||
}
|
||||
|
||||
// IsUserExist checks if given user name exist,
|
||||
@@ -471,7 +492,7 @@ func CreateUser(u *User) (err error) {
|
||||
|
||||
u.LowerName = strings.ToLower(u.Name)
|
||||
u.AvatarEmail = u.Email
|
||||
u.Avatar = avatar.HashEmail(u.AvatarEmail)
|
||||
u.Avatar = base.HashEmail(u.AvatarEmail)
|
||||
u.Rands = GetUserSalt()
|
||||
u.Salt = GetUserSalt()
|
||||
u.EncodePasswd()
|
||||
@@ -576,7 +597,20 @@ func ChangeUserName(u *User, newUserName string) (err error) {
|
||||
return ErrUserAlreadyExist{newUserName}
|
||||
}
|
||||
|
||||
return os.Rename(UserPath(u.LowerName), UserPath(newUserName))
|
||||
if err = ChangeUsernameInPullRequests(u.Name, newUserName); err != nil {
|
||||
return fmt.Errorf("ChangeUsernameInPullRequests: %v", err)
|
||||
}
|
||||
|
||||
// Delete all local copies of repository wiki that user owns.
|
||||
if err = x.Where("owner_id=?", u.Id).Iterate(new(Repository), func(idx int, bean interface{}) error {
|
||||
repo := bean.(*Repository)
|
||||
RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
|
||||
return nil
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Delete repository wiki local copy: %v", err)
|
||||
}
|
||||
|
||||
return os.Rename(UserPath(u.Name), UserPath(newUserName))
|
||||
}
|
||||
|
||||
func updateUser(e Engine, u *User) error {
|
||||
@@ -593,7 +627,7 @@ func updateUser(e Engine, u *User) error {
|
||||
if len(u.AvatarEmail) == 0 {
|
||||
u.AvatarEmail = u.Email
|
||||
}
|
||||
u.Avatar = avatar.HashEmail(u.AvatarEmail)
|
||||
u.Avatar = base.HashEmail(u.AvatarEmail)
|
||||
}
|
||||
|
||||
u.LowerName = strings.ToLower(u.Name)
|
||||
@@ -608,7 +642,7 @@ func updateUser(e Engine, u *User) error {
|
||||
u.Description = u.Description[:255]
|
||||
}
|
||||
|
||||
u.FullName = base.Sanitizer.Sanitize(u.FullName)
|
||||
u.FullName = markdown.Sanitizer.Sanitize(u.FullName)
|
||||
_, err := e.Id(u.Id).AllCols().Update(u)
|
||||
return err
|
||||
}
|
||||
@@ -888,7 +922,7 @@ func GetEmailAddresses(uid int64) ([]*EmailAddress, error) {
|
||||
}
|
||||
|
||||
func AddEmailAddress(email *EmailAddress) error {
|
||||
email.Email = strings.ToLower(email.Email)
|
||||
email.Email = strings.ToLower(strings.TrimSpace(email.Email))
|
||||
used, err := IsEmailUsed(email.Email)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -900,6 +934,29 @@ func AddEmailAddress(email *EmailAddress) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func AddEmailAddresses(emails []*EmailAddress) error {
|
||||
if len(emails) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if any of them has been used
|
||||
for i := range emails {
|
||||
emails[i].Email = strings.ToLower(strings.TrimSpace(emails[i].Email))
|
||||
used, err := IsEmailUsed(emails[i].Email)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if used {
|
||||
return ErrEmailAlreadyUsed{emails[i].Email}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := x.Insert(emails); err != nil {
|
||||
return fmt.Errorf("Insert: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (email *EmailAddress) Activate() error {
|
||||
email.IsActivated = true
|
||||
if _, err := x.Id(email.ID).AllCols().Update(email); err != nil {
|
||||
@@ -914,20 +971,23 @@ func (email *EmailAddress) Activate() error {
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteEmailAddress(email *EmailAddress) error {
|
||||
has, err := x.Get(email)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return ErrEmailNotExist
|
||||
func DeleteEmailAddress(email *EmailAddress) (err error) {
|
||||
if email.ID > 0 {
|
||||
_, err = x.Id(email.ID).Delete(new(EmailAddress))
|
||||
} else {
|
||||
_, err = x.Where("email=?", email.Email).Delete(new(EmailAddress))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = x.Id(email.ID).Delete(email); err != nil {
|
||||
return err
|
||||
func DeleteEmailAddresses(emails []*EmailAddress) (err error) {
|
||||
for i := range emails {
|
||||
if err = DeleteEmailAddress(emails[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func MakeEmailPrimary(email *EmailAddress) error {
|
||||
@@ -1051,100 +1111,73 @@ func SearchUserByName(opt SearchOption) (us []*User, err error) {
|
||||
return us, err
|
||||
}
|
||||
|
||||
// Follow is connection request for receiving user notification.
|
||||
// ___________ .__ .__
|
||||
// \_ _____/___ | | | | ______ _ __
|
||||
// | __)/ _ \| | | | / _ \ \/ \/ /
|
||||
// | \( <_> ) |_| |_( <_> ) /
|
||||
// \___ / \____/|____/____/\____/ \/\_/
|
||||
// \/
|
||||
|
||||
// Follow represents relations of user and his/her followers.
|
||||
type Follow struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UserID int64 `xorm:"UNIQUE(follow)"`
|
||||
FollowID int64 `xorm:"UNIQUE(follow)"`
|
||||
}
|
||||
|
||||
func IsFollowing(userID, followID int64) bool {
|
||||
has, _ := x.Get(&Follow{UserID: userID, FollowID: followID})
|
||||
return has
|
||||
}
|
||||
|
||||
// FollowUser marks someone be another's follower.
|
||||
func FollowUser(userId int64, followId int64) (err error) {
|
||||
func FollowUser(userID, followID int64) (err error) {
|
||||
if userID == followID || IsFollowing(userID, followID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
sess.Begin()
|
||||
|
||||
if _, err = sess.Insert(&Follow{UserID: userId, FollowID: followId}); err != nil {
|
||||
sess.Rollback()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawSql := "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?"
|
||||
if _, err = sess.Exec(rawSql, followId); err != nil {
|
||||
sess.Rollback()
|
||||
if _, err = sess.Insert(&Follow{UserID: userID, FollowID: followID}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawSql = "UPDATE `user` SET num_followings = num_followings + 1 WHERE id = ?"
|
||||
if _, err = sess.Exec(rawSql, userId); err != nil {
|
||||
sess.Rollback()
|
||||
if _, err = sess.Exec("UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?", followID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = sess.Exec("UPDATE `user` SET num_following = num_following + 1 WHERE id = ?", userID); err != nil {
|
||||
return err
|
||||
}
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// UnFollowUser unmarks someone be another's follower.
|
||||
func UnFollowUser(userId int64, unFollowId int64) (err error) {
|
||||
session := x.NewSession()
|
||||
defer session.Close()
|
||||
session.Begin()
|
||||
// UnfollowUser unmarks someone be another's follower.
|
||||
func UnfollowUser(userID, followID int64) (err error) {
|
||||
if userID == followID || !IsFollowing(userID, followID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err = session.Delete(&Follow{UserID: userId, FollowID: unFollowId}); err != nil {
|
||||
session.Rollback()
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawSql := "UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?"
|
||||
if _, err = session.Exec(rawSql, unFollowId); err != nil {
|
||||
session.Rollback()
|
||||
if _, err = sess.Delete(&Follow{UserID: userID, FollowID: followID}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawSql = "UPDATE `user` SET num_followings = num_followings - 1 WHERE id = ?"
|
||||
if _, err = session.Exec(rawSql, userId); err != nil {
|
||||
session.Rollback()
|
||||
if _, err = sess.Exec("UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?", followID); err != nil {
|
||||
return err
|
||||
}
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func UpdateMentions(userNames []string, issueId int64) error {
|
||||
for i := range userNames {
|
||||
userNames[i] = strings.ToLower(userNames[i])
|
||||
}
|
||||
users := make([]*User, 0, len(userNames))
|
||||
|
||||
if err := x.Where("lower_name IN (?)", strings.Join(userNames, "\",\"")).OrderBy("lower_name ASC").Find(&users); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ids := make([]int64, 0, len(userNames))
|
||||
for _, user := range users {
|
||||
ids = append(ids, user.Id)
|
||||
if !user.IsOrganization() {
|
||||
continue
|
||||
}
|
||||
|
||||
if user.NumMembers == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
tempIds := make([]int64, 0, user.NumMembers)
|
||||
orgUsers, err := GetOrgUsersByOrgId(user.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, orgUser := range orgUsers {
|
||||
tempIds = append(tempIds, orgUser.ID)
|
||||
}
|
||||
|
||||
ids = append(ids, tempIds...)
|
||||
}
|
||||
|
||||
if err := UpdateIssueUsersByMentions(ids, issueId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
if _, err = sess.Exec("UPDATE `user` SET num_following = num_following - 1 WHERE id = ?", userID); err != nil {
|
||||
return err
|
||||
}
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@ import (
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
|
||||
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/uuid"
|
||||
)
|
||||
|
||||
type HookContentType int
|
||||
@@ -285,7 +285,7 @@ type HookTask struct {
|
||||
HookID int64
|
||||
UUID string
|
||||
Type HookTaskType
|
||||
URL string
|
||||
URL string `xorm:"TEXT"`
|
||||
api.Payloader `xorm:"-"`
|
||||
PayloadContent string `xorm:"TEXT"`
|
||||
ContentType HookContentType
|
||||
@@ -361,7 +361,7 @@ func CreateHookTask(t *HookTask) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.UUID = uuid.NewV4().String()
|
||||
t.UUID = gouuid.NewV4().String()
|
||||
t.PayloadContent = string(data)
|
||||
_, err = x.Insert(t)
|
||||
return err
|
||||
@@ -398,6 +398,7 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
|
||||
return nil
|
||||
}
|
||||
|
||||
var payloader api.Payloader
|
||||
for _, w := range ws {
|
||||
switch event {
|
||||
case HOOK_EVENT_CREATE:
|
||||
@@ -410,14 +411,16 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
|
||||
}
|
||||
}
|
||||
|
||||
// Use separate objects so modifcations won't be made on payload on non-Gogs type hooks.
|
||||
switch w.HookTaskType {
|
||||
case SLACK:
|
||||
p, err = GetSlackPayload(p, event, w.Meta)
|
||||
payloader, err = GetSlackPayload(p, event, w.Meta)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetSlackPayload: %v", err)
|
||||
}
|
||||
default:
|
||||
p.SetSecret(w.Secret)
|
||||
payloader = p
|
||||
}
|
||||
|
||||
if err = CreateHookTask(&HookTask{
|
||||
@@ -425,7 +428,7 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
|
||||
HookID: w.ID,
|
||||
Type: w.HookTaskType,
|
||||
URL: w.URL,
|
||||
Payloader: p,
|
||||
Payloader: payloader,
|
||||
ContentType: w.ContentType,
|
||||
EventType: HOOK_EVENT_PUSH,
|
||||
IsSSL: w.IsSSL,
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogits/git-shell"
|
||||
"github.com/gogits/git-module"
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
)
|
||||
|
||||
|
||||
@@ -12,10 +12,11 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"net/url"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
"github.com/gogits/git-shell"
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
@@ -65,12 +66,13 @@ var wikiWorkingPool = &workingPool{
|
||||
|
||||
// ToWikiPageURL formats a string to corresponding wiki URL name.
|
||||
func ToWikiPageURL(name string) string {
|
||||
return strings.Replace(name, " ", "-", -1)
|
||||
return url.QueryEscape(strings.Replace(name, " ", "-", -1))
|
||||
}
|
||||
|
||||
// ToWikiPageName formats a URL back to corresponding wiki page name.
|
||||
func ToWikiPageName(name string) string {
|
||||
return strings.Replace(name, "-", " ", -1)
|
||||
func ToWikiPageName(urlString string) string {
|
||||
name, _ := url.QueryUnescape(strings.Replace(urlString, "-", " ", -1))
|
||||
return name
|
||||
}
|
||||
|
||||
// WikiCloneLink returns clone URLs of repository wiki.
|
||||
|
||||
@@ -12,13 +12,13 @@ import (
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-macaron/binding"
|
||||
"github.com/go-macaron/session"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
"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"
|
||||
"github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
|
||||
func IsAPIPath(url string) bool {
|
||||
@@ -55,8 +55,8 @@ func SignedInID(ctx *macaron.Context, sess session.Store) int64 {
|
||||
return 0
|
||||
}
|
||||
t.Updated = time.Now()
|
||||
if err = models.UpdateAccessToekn(t); err != nil {
|
||||
log.Error(4, "UpdateAccessToekn: %v", err)
|
||||
if err = models.UpdateAccessToken(t); err != nil {
|
||||
log.Error(4, "UpdateAccessToken: %v", err)
|
||||
}
|
||||
return t.UID
|
||||
}
|
||||
@@ -102,7 +102,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
||||
if setting.Service.EnableReverseProxyAutoRegister {
|
||||
u := &models.User{
|
||||
Name: webAuthUser,
|
||||
Email: uuid.NewV4().String() + "@localhost",
|
||||
Email: gouuid.NewV4().String() + "@localhost",
|
||||
Passwd: webAuthUser,
|
||||
IsActive: true,
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ type AuthenticationForm struct {
|
||||
AttributeName string
|
||||
AttributeSurname string
|
||||
AttributeMail string
|
||||
AttributesInBind bool
|
||||
Filter string
|
||||
AdminFilter string
|
||||
IsActive bool
|
||||
|
||||
@@ -31,6 +31,7 @@ type Source struct {
|
||||
AttributeName string // First name attribute
|
||||
AttributeSurname string // Surname attribute
|
||||
AttributeMail string // E-mail attribute
|
||||
AttributesInBind bool // fetch attributes in bind context (not user)
|
||||
Filter string // Query filter to validate entry
|
||||
AdminFilter string // Query filter to check if user is admin
|
||||
Enabled bool // if this source is disabled
|
||||
@@ -58,18 +59,10 @@ func (ls *Source) sanitizedUserDN(username string) (string, bool) {
|
||||
return fmt.Sprintf(ls.UserDN, username), true
|
||||
}
|
||||
|
||||
func (ls *Source) FindUserDN(name string) (string, bool) {
|
||||
l, err := ldapDial(ls)
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
|
||||
ls.Enabled = false
|
||||
return "", false
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
|
||||
log.Trace("Search for LDAP user: %s", name)
|
||||
if ls.BindDN != "" && ls.BindPassword != "" {
|
||||
err = l.Bind(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)
|
||||
return "", false
|
||||
@@ -85,7 +78,7 @@ func (ls *Source) FindUserDN(name string) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
log.Trace("Searching using filter %s", userFilter)
|
||||
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)
|
||||
@@ -111,6 +104,14 @@ func (ls *Source) FindUserDN(name string) (string, bool) {
|
||||
|
||||
// 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) {
|
||||
l, err := ldapDial(ls)
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
|
||||
ls.Enabled = false
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
var userDN string
|
||||
if directBind {
|
||||
log.Trace("LDAP will bind directly via UserDN template: %s", ls.UserDN)
|
||||
@@ -124,36 +125,29 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
|
||||
log.Trace("LDAP will use BindDN.")
|
||||
|
||||
var found bool
|
||||
userDN, found = ls.FindUserDN(name)
|
||||
userDN, found = ls.findUserDN(l, name)
|
||||
if !found {
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
}
|
||||
|
||||
l, err := ldapDial(ls)
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Connect error (%s): %v", ls.Host, err)
|
||||
ls.Enabled = false
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
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)
|
||||
return "", "", "", "", false, false
|
||||
if directBind || !ls.AttributesInBind {
|
||||
// binds user (checking password) before looking-up attributes in user context
|
||||
err = bindUser(l, userDN, passwd)
|
||||
if err != nil {
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
}
|
||||
|
||||
log.Trace("Bound successfully with userDN: %s", userDN)
|
||||
userFilter, ok := ls.sanitizedUserQuery(name)
|
||||
if !ok {
|
||||
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)
|
||||
search := ldap.NewSearchRequest(
|
||||
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
|
||||
[]string{ls.AttributeName, ls.AttributeSurname, ls.AttributeMail},
|
||||
[]string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail},
|
||||
nil)
|
||||
|
||||
sr, err := l.Search(search)
|
||||
@@ -177,6 +171,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
|
||||
|
||||
admin_attr := false
|
||||
if len(ls.AdminFilter) > 0 {
|
||||
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},
|
||||
@@ -192,9 +187,28 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
|
||||
}
|
||||
}
|
||||
|
||||
if !directBind && ls.AttributesInBind {
|
||||
// binds user (checking password) after looking-up attributes in BindDN context
|
||||
err = bindUser(l, userDN, passwd)
|
||||
if err != nil {
|
||||
return "", "", "", "", false, false
|
||||
}
|
||||
}
|
||||
|
||||
return username_attr, name_attr, sn_attr, mail_attr, admin_attr, true
|
||||
}
|
||||
|
||||
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)
|
||||
return err
|
||||
}
|
||||
log.Trace("Bound successfully with userDN: %s", userDN)
|
||||
return err
|
||||
}
|
||||
|
||||
func ldapDial(ls *Source) (*ldap.Conn, error) {
|
||||
if ls.UseSSL {
|
||||
log.Debug("Using TLS for LDAP without verifying: %v", ls.SkipVerify)
|
||||
|
||||
@@ -45,9 +45,9 @@ func (f *UpdateOrgSettingForm) Validate(ctx *macaron.Context, errs binding.Error
|
||||
// \/ \/ \/
|
||||
|
||||
type CreateTeamForm struct {
|
||||
TeamName string `form:"team_name" binding:"Required;AlphaDashDot;MaxSize(30)"`
|
||||
Description string `form:"desc" binding:"MaxSize(255)"`
|
||||
Permission string `form:"permission"`
|
||||
TeamName string `binding:"Required;AlphaDashDot;MaxSize(30)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Permission string
|
||||
}
|
||||
|
||||
func (f *CreateTeamForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
|
||||
@@ -57,7 +57,7 @@ func (f *MigrateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
|
||||
// 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) {
|
||||
remoteAddr := f.CloneAddr
|
||||
remoteAddr := strings.TrimSpace(f.CloneAddr)
|
||||
|
||||
// Remote address can be HTTP/HTTPS/Git URL or local path.
|
||||
if strings.HasPrefix(remoteAddr, "http://") ||
|
||||
@@ -239,7 +239,7 @@ func (f *NewReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) bin
|
||||
|
||||
type EditReleaseForm struct {
|
||||
Title string `form:"title" binding:"Required"`
|
||||
Content string `form:"content" binding:"Required"`
|
||||
Content string `form:"content"`
|
||||
Draft string `form:"draft"`
|
||||
Prerelease bool `form:"prerelease"`
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ type InstallForm struct {
|
||||
SSHPort int
|
||||
HTTPPort string `binding:"Required"`
|
||||
AppUrl string `binding:"Required"`
|
||||
LogRootPath string `binding:"Required"`
|
||||
|
||||
SMTPHost string
|
||||
SMTPFrom string
|
||||
|
||||
@@ -2,74 +2,23 @@
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// for www.gravatar.com image cache
|
||||
|
||||
/*
|
||||
It is recommend to use this way
|
||||
|
||||
cacheDir := "./cache"
|
||||
defaultImg := "./default.jpg"
|
||||
http.Handle("/avatar/", avatar.CacheServer(cacheDir, defaultImg))
|
||||
*/
|
||||
package avatar
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color/palette"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/issue9/identicon"
|
||||
"github.com/nfnt/resize"
|
||||
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
//FIXME: remove cache module
|
||||
|
||||
var gravatarSource string
|
||||
|
||||
func UpdateGravatarSource() {
|
||||
gravatarSource = setting.GravatarSource
|
||||
if strings.HasPrefix(gravatarSource, "//") {
|
||||
gravatarSource = "http:" + gravatarSource
|
||||
} else if !strings.HasPrefix(gravatarSource, "http://") &&
|
||||
!strings.HasPrefix(gravatarSource, "https://") {
|
||||
gravatarSource = "http://" + gravatarSource
|
||||
}
|
||||
log.Debug("avatar.UpdateGravatarSource(update gavatar source): %s", gravatarSource)
|
||||
}
|
||||
|
||||
// hash email to md5 string
|
||||
// keep this func in order to make this package independent
|
||||
func HashEmail(email string) string {
|
||||
// https://en.gravatar.com/site/implement/hash/
|
||||
email = strings.TrimSpace(email)
|
||||
email = strings.ToLower(email)
|
||||
|
||||
h := md5.New()
|
||||
h.Write([]byte(email))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
const _RANDOM_AVATAR_SIZE = 200
|
||||
|
||||
// RandomImage generates and returns a random avatar image.
|
||||
func RandomImage(data []byte) (image.Image, error) {
|
||||
// RandomImage generates and returns a random avatar image unique to input data
|
||||
// in custom size (height and width).
|
||||
func RandomImageSize(size int, data []byte) (image.Image, error) {
|
||||
randExtent := len(palette.WebSafe) - 32
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
colorIndex := rand.Intn(randExtent)
|
||||
@@ -78,262 +27,17 @@ func RandomImage(data []byte) (image.Image, error) {
|
||||
backColorIndex = randExtent - 1
|
||||
}
|
||||
|
||||
// Size, background, forecolor
|
||||
imgMaker, err := identicon.New(_RANDOM_AVATAR_SIZE,
|
||||
// Define size, background, and forecolor
|
||||
imgMaker, err := identicon.New(size,
|
||||
palette.WebSafe[backColorIndex], palette.WebSafe[colorIndex:colorIndex+32]...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("identicon.New: %v", err)
|
||||
}
|
||||
return imgMaker.Make(data), nil
|
||||
}
|
||||
|
||||
// Avatar represents the avatar object.
|
||||
type Avatar struct {
|
||||
Hash string
|
||||
AlterImage string // image path
|
||||
cacheDir string // image save dir
|
||||
reqParams string
|
||||
imagePath string
|
||||
expireDuration time.Duration
|
||||
}
|
||||
|
||||
func New(hash string, cacheDir string) *Avatar {
|
||||
return &Avatar{
|
||||
Hash: hash,
|
||||
cacheDir: cacheDir,
|
||||
expireDuration: time.Minute * 10,
|
||||
reqParams: url.Values{
|
||||
"d": {"retro"},
|
||||
"size": {"290"},
|
||||
"r": {"pg"}}.Encode(),
|
||||
imagePath: filepath.Join(cacheDir, hash+".image"), //maybe png or jpeg
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Avatar) HasCache() bool {
|
||||
fileInfo, err := os.Stat(this.imagePath)
|
||||
return err == nil && fileInfo.Mode().IsRegular()
|
||||
}
|
||||
|
||||
func (this *Avatar) Modtime() (modtime time.Time, err error) {
|
||||
fileInfo, err := os.Stat(this.imagePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return fileInfo.ModTime(), nil
|
||||
}
|
||||
|
||||
func (this *Avatar) Expired() bool {
|
||||
modtime, err := this.Modtime()
|
||||
return err != nil || time.Since(modtime) > this.expireDuration
|
||||
}
|
||||
|
||||
// default image format: jpeg
|
||||
func (this *Avatar) Encode(wr io.Writer, size int) (err error) {
|
||||
var img image.Image
|
||||
decodeImageFile := func(file string) (img image.Image, err error) {
|
||||
fd, err := os.Open(file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
if img, err = jpeg.Decode(fd); err != nil {
|
||||
fd.Seek(0, os.SEEK_SET)
|
||||
img, err = png.Decode(fd)
|
||||
}
|
||||
return
|
||||
}
|
||||
imgPath := this.imagePath
|
||||
if !this.HasCache() {
|
||||
if this.AlterImage == "" {
|
||||
return errors.New("request image failed, and no alt image offered")
|
||||
}
|
||||
imgPath = this.AlterImage
|
||||
}
|
||||
|
||||
if img, err = decodeImageFile(imgPath); err != nil {
|
||||
return
|
||||
}
|
||||
m := resize.Resize(uint(size), 0, img, resize.Lanczos3)
|
||||
return jpeg.Encode(wr, m, nil)
|
||||
}
|
||||
|
||||
// get image from gravatar.com
|
||||
func (this *Avatar) Update() {
|
||||
UpdateGravatarSource()
|
||||
thunder.Fetch(gravatarSource+this.Hash+"?"+this.reqParams,
|
||||
this.imagePath)
|
||||
}
|
||||
|
||||
func (this *Avatar) UpdateTimeout(timeout time.Duration) (err error) {
|
||||
UpdateGravatarSource()
|
||||
select {
|
||||
case <-time.After(timeout):
|
||||
err = fmt.Errorf("get gravatar image %s timeout", this.Hash)
|
||||
case err = <-thunder.GoFetch(gravatarSource+this.Hash+"?"+this.reqParams,
|
||||
this.imagePath):
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type service struct {
|
||||
cacheDir string
|
||||
altImage string
|
||||
}
|
||||
|
||||
func (this *service) mustInt(r *http.Request, defaultValue int, keys ...string) (v int) {
|
||||
for _, k := range keys {
|
||||
if _, err := fmt.Sscanf(r.FormValue(k), "%d", &v); err == nil {
|
||||
defaultValue = v
|
||||
}
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func (this *service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
urlPath := r.URL.Path
|
||||
hash := urlPath[strings.LastIndex(urlPath, "/")+1:]
|
||||
size := this.mustInt(r, 290, "s", "size") // default size = 290*290
|
||||
|
||||
avatar := New(hash, this.cacheDir)
|
||||
avatar.AlterImage = this.altImage
|
||||
if avatar.Expired() {
|
||||
if err := avatar.UpdateTimeout(time.Millisecond * 1000); err != nil {
|
||||
log.Trace("avatar update error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if modtime, err := avatar.Modtime(); err == nil {
|
||||
etag := fmt.Sprintf("size(%d)", size)
|
||||
if t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && modtime.Before(t.Add(1*time.Second)) && etag == r.Header.Get("If-None-Match") {
|
||||
h := w.Header()
|
||||
delete(h, "Content-Type")
|
||||
delete(h, "Content-Length")
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Last-Modified", modtime.UTC().Format(http.TimeFormat))
|
||||
w.Header().Set("ETag", etag)
|
||||
}
|
||||
w.Header().Set("Content-Type", "image/jpeg")
|
||||
|
||||
if err := avatar.Encode(w, size); err != nil {
|
||||
log.Warn("avatar encode error: %v", err)
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
}
|
||||
|
||||
// http.Handle("/avatar/", avatar.CacheServer("./cache"))
|
||||
func CacheServer(cacheDir string, defaultImgPath string) http.Handler {
|
||||
return &service{
|
||||
cacheDir: cacheDir,
|
||||
altImage: defaultImgPath,
|
||||
}
|
||||
}
|
||||
|
||||
// thunder downloader
|
||||
var thunder = &Thunder{QueueSize: 10}
|
||||
|
||||
type Thunder struct {
|
||||
QueueSize int // download queue size
|
||||
q chan *thunderTask
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (t *Thunder) init() {
|
||||
if t.QueueSize < 1 {
|
||||
t.QueueSize = 1
|
||||
}
|
||||
t.q = make(chan *thunderTask, t.QueueSize)
|
||||
for i := 0; i < t.QueueSize; i++ {
|
||||
go func() {
|
||||
for {
|
||||
task := <-t.q
|
||||
task.Fetch()
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Thunder) Fetch(url string, saveFile string) error {
|
||||
t.once.Do(t.init)
|
||||
task := &thunderTask{
|
||||
Url: url,
|
||||
SaveFile: saveFile,
|
||||
}
|
||||
task.Add(1)
|
||||
t.q <- task
|
||||
task.Wait()
|
||||
return task.err
|
||||
}
|
||||
|
||||
func (t *Thunder) GoFetch(url, saveFile string) chan error {
|
||||
c := make(chan error)
|
||||
go func() {
|
||||
c <- t.Fetch(url, saveFile)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
// thunder download
|
||||
type thunderTask struct {
|
||||
Url string
|
||||
SaveFile string
|
||||
sync.WaitGroup
|
||||
err error
|
||||
}
|
||||
|
||||
func (this *thunderTask) Fetch() {
|
||||
this.err = this.fetch()
|
||||
this.Done()
|
||||
}
|
||||
|
||||
var client = &http.Client{}
|
||||
|
||||
func (this *thunderTask) fetch() error {
|
||||
log.Debug("avatar.fetch(fetch new avatar): %s", this.Url)
|
||||
req, _ := http.NewRequest("GET", this.Url, nil)
|
||||
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/jpeg,image/png,*/*;q=0.8")
|
||||
req.Header.Set("Accept-Encoding", "deflate,sdch")
|
||||
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8")
|
||||
req.Header.Set("Cache-Control", "no-cache")
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36")
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
/*
|
||||
log.Println("headers:", resp.Header)
|
||||
switch resp.Header.Get("Content-Type") {
|
||||
case "image/jpeg":
|
||||
this.SaveFile += ".jpeg"
|
||||
case "image/png":
|
||||
this.SaveFile += ".png"
|
||||
}
|
||||
*/
|
||||
/*
|
||||
imgType := resp.Header.Get("Content-Type")
|
||||
if imgType != "image/jpeg" && imgType != "image/png" {
|
||||
return errors.New("not png or jpeg")
|
||||
}
|
||||
*/
|
||||
|
||||
tmpFile := this.SaveFile + ".part" // mv to destination when finished
|
||||
fd, err := os.Create(tmpFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(fd, resp.Body)
|
||||
fd.Close()
|
||||
if err != nil {
|
||||
os.Remove(tmpFile)
|
||||
return err
|
||||
}
|
||||
return os.Rename(tmpFile, this.SaveFile)
|
||||
// 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)
|
||||
}
|
||||
|
||||
@@ -1,61 +1,23 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// 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 avatar_test
|
||||
|
||||
package avatar
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogits/gogs/modules/avatar"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
const TMPDIR = "test-avatar"
|
||||
func Test_RandomImage(t *testing.T) {
|
||||
Convey("Generate a random avatar from email", t, func() {
|
||||
_, err := RandomImage([]byte("gogs@local"))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
func TestFetch(t *testing.T) {
|
||||
os.Mkdir(TMPDIR, 0755)
|
||||
defer os.RemoveAll(TMPDIR)
|
||||
|
||||
hash := avatar.HashEmail("ssx205@gmail.com")
|
||||
a := avatar.New(hash, TMPDIR)
|
||||
a.UpdateTimeout(time.Millisecond * 200)
|
||||
}
|
||||
|
||||
func TestFetchMany(t *testing.T) {
|
||||
os.Mkdir(TMPDIR, 0755)
|
||||
defer os.RemoveAll(TMPDIR)
|
||||
|
||||
t.Log("start")
|
||||
var n = 5
|
||||
ch := make(chan bool, n)
|
||||
for i := 0; i < n; i++ {
|
||||
go func(i int) {
|
||||
hash := avatar.HashEmail(strconv.Itoa(i) + "ssx205@gmail.com")
|
||||
a := avatar.New(hash, TMPDIR)
|
||||
a.Update()
|
||||
t.Log("finish", hash)
|
||||
ch <- true
|
||||
}(i)
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
<-ch
|
||||
}
|
||||
t.Log("end")
|
||||
}
|
||||
|
||||
// cat
|
||||
// wget http://www.artsjournal.com/artfulmanager/wp/wp-content/uploads/2013/12/200x200xmirror_cat.jpg.pagespeed.ic.GOZSv6v1_H.jpg -O default.jpg
|
||||
/*
|
||||
func TestHttp(t *testing.T) {
|
||||
http.Handle("/", avatar.CacheServer("./", "default.jpg"))
|
||||
http.ListenAndServe(":8001", nil)
|
||||
}
|
||||
*/
|
||||
|
||||
func TestLogTrace(t *testing.T) {
|
||||
log.Trace("%v", errors.New("console log test"))
|
||||
Convey("Try to generate an image with size zero", func() {
|
||||
_, err := RandomImageSize(0, []byte("gogs@local"))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,29 +4,8 @@
|
||||
|
||||
package base
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const DOC_URL = "https://github.com/gogits/go-gogs-client/wiki"
|
||||
|
||||
type (
|
||||
TplName string
|
||||
)
|
||||
|
||||
var GoGetMetas = make(map[string]bool)
|
||||
|
||||
// ExecPath returns the executable path.
|
||||
func ExecPath() (string, error) {
|
||||
file, err := exec.LookPath(os.Args[0])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
p, err := filepath.Abs(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
@@ -1,339 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/russross/blackfriday"
|
||||
"golang.org/x/net/html"
|
||||
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
func isletter(c byte) bool {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|
||||
}
|
||||
|
||||
func isalnum(c byte) bool {
|
||||
return (c >= '0' && c <= '9') || isletter(c)
|
||||
}
|
||||
|
||||
var validLinks = [][]byte{[]byte("http://"), []byte("https://"), []byte("ftp://"), []byte("mailto://")}
|
||||
|
||||
func isLink(link []byte) bool {
|
||||
for _, prefix := range validLinks {
|
||||
if len(link) > len(prefix) && bytes.Equal(bytes.ToLower(link[:len(prefix)]), prefix) && isalnum(link[len(prefix)]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func IsMarkdownFile(name string) bool {
|
||||
name = strings.ToLower(name)
|
||||
switch filepath.Ext(name) {
|
||||
case ".md", ".markdown", ".mdown", ".mkd":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsTextFile(data []byte) (string, bool) {
|
||||
contentType := http.DetectContentType(data)
|
||||
if strings.Index(contentType, "text/") != -1 {
|
||||
return contentType, true
|
||||
}
|
||||
return contentType, false
|
||||
}
|
||||
|
||||
func IsImageFile(data []byte) (string, bool) {
|
||||
contentType := http.DetectContentType(data)
|
||||
if strings.Index(contentType, "image/") != -1 {
|
||||
return contentType, true
|
||||
}
|
||||
return contentType, false
|
||||
}
|
||||
|
||||
// IsReadmeFile returns true if given file name suppose to be a README file.
|
||||
func IsReadmeFile(name string) bool {
|
||||
name = strings.ToLower(name)
|
||||
if len(name) < 6 {
|
||||
return false
|
||||
} else if len(name) == 6 {
|
||||
if name == "readme" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
if name[:7] == "readme." {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type CustomRender struct {
|
||||
blackfriday.Renderer
|
||||
urlPrefix string
|
||||
}
|
||||
|
||||
func (options *CustomRender) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
|
||||
if len(link) > 0 && !isLink(link) {
|
||||
if link[0] == '#' {
|
||||
// link = append([]byte(options.urlPrefix), link...)
|
||||
} else {
|
||||
link = []byte(path.Join(options.urlPrefix, string(link)))
|
||||
}
|
||||
}
|
||||
|
||||
options.Renderer.Link(out, link, title, content)
|
||||
}
|
||||
|
||||
var (
|
||||
svgSuffix = []byte(".svg")
|
||||
svgSuffixWithMark = []byte(".svg?")
|
||||
)
|
||||
|
||||
func (options *CustomRender) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
||||
prefix := strings.Replace(options.urlPrefix, "/src/", "/raw/", 1)
|
||||
if len(link) > 0 {
|
||||
if isLink(link) {
|
||||
// External link with .svg suffix usually means CI status.
|
||||
if bytes.HasSuffix(link, svgSuffix) || bytes.Contains(link, svgSuffixWithMark) {
|
||||
options.Renderer.Image(out, link, title, alt)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if link[0] != '/' {
|
||||
prefix += "/"
|
||||
}
|
||||
link = []byte(prefix + string(link))
|
||||
}
|
||||
}
|
||||
|
||||
out.WriteString(`<a href="`)
|
||||
out.Write(link)
|
||||
out.WriteString(`">`)
|
||||
options.Renderer.Image(out, link, title, alt)
|
||||
out.WriteString("</a>")
|
||||
}
|
||||
|
||||
var (
|
||||
MentionPattern = regexp.MustCompile(`(\s|^)@[0-9a-zA-Z_\.]+`)
|
||||
commitPattern = regexp.MustCompile(`(\s|^)https?.*commit/[0-9a-zA-Z]+(#+[0-9a-zA-Z-]*)?`)
|
||||
issueFullPattern = regexp.MustCompile(`(\s|^)https?.*issues/[0-9]+(#+[0-9a-zA-Z-]*)?`)
|
||||
issueIndexPattern = regexp.MustCompile(`( |^|\()#[0-9]+\b`)
|
||||
sha1CurrentPattern = regexp.MustCompile(`\b[0-9a-f]{40}\b`)
|
||||
)
|
||||
|
||||
func cutoutVerbosePrefix(prefix string) string {
|
||||
count := 0
|
||||
for i := 0; i < len(prefix); i++ {
|
||||
if prefix[i] == '/' {
|
||||
count++
|
||||
}
|
||||
if count >= 3 {
|
||||
return prefix[:i]
|
||||
}
|
||||
}
|
||||
return prefix
|
||||
}
|
||||
|
||||
func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
|
||||
urlPrefix = cutoutVerbosePrefix(urlPrefix)
|
||||
ms := issueIndexPattern.FindAll(rawBytes, -1)
|
||||
for _, m := range ms {
|
||||
var space string
|
||||
m2 := m
|
||||
if m2[0] != '#' {
|
||||
space = string(m2[0])
|
||||
m2 = m2[1:]
|
||||
}
|
||||
if metas == nil {
|
||||
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s/issues/%s">%s</a>`,
|
||||
space, urlPrefix, m2[1:], m2)), 1)
|
||||
} else {
|
||||
// Support for external issue tracker
|
||||
metas["index"] = string(m2[1:])
|
||||
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s">%s</a>`,
|
||||
space, com.Expand(metas["format"], metas), m2)), 1)
|
||||
}
|
||||
}
|
||||
return rawBytes
|
||||
}
|
||||
|
||||
func RenderSpecialLink(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
|
||||
ms := MentionPattern.FindAll(rawBytes, -1)
|
||||
for _, m := range ms {
|
||||
m = bytes.TrimSpace(m)
|
||||
rawBytes = bytes.Replace(rawBytes, m,
|
||||
[]byte(fmt.Sprintf(`<a href="%s/%s">%s</a>`, setting.AppSubUrl, m[1:], m)), -1)
|
||||
}
|
||||
|
||||
rawBytes = RenderIssueIndexPattern(rawBytes, urlPrefix, metas)
|
||||
rawBytes = RenderSha1CurrentPattern(rawBytes, urlPrefix)
|
||||
return rawBytes
|
||||
}
|
||||
|
||||
func RenderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte {
|
||||
ms := sha1CurrentPattern.FindAll(rawBytes, -1)
|
||||
for _, m := range ms {
|
||||
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
|
||||
`<a href="%s/commit/%s"><code>%s</code></a>`, urlPrefix, m, ShortSha(string(m)))), -1)
|
||||
}
|
||||
return rawBytes
|
||||
}
|
||||
|
||||
func RenderRawMarkdown(body []byte, urlPrefix string) []byte {
|
||||
htmlFlags := 0
|
||||
htmlFlags |= blackfriday.HTML_SKIP_STYLE
|
||||
htmlFlags |= blackfriday.HTML_OMIT_CONTENTS
|
||||
renderer := &CustomRender{
|
||||
Renderer: blackfriday.HtmlRenderer(htmlFlags, "", ""),
|
||||
urlPrefix: urlPrefix,
|
||||
}
|
||||
|
||||
// set up the parser
|
||||
extensions := 0
|
||||
extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
|
||||
extensions |= blackfriday.EXTENSION_TABLES
|
||||
extensions |= blackfriday.EXTENSION_FENCED_CODE
|
||||
extensions |= blackfriday.EXTENSION_AUTOLINK
|
||||
extensions |= blackfriday.EXTENSION_STRIKETHROUGH
|
||||
extensions |= blackfriday.EXTENSION_SPACE_HEADERS
|
||||
extensions |= blackfriday.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK
|
||||
|
||||
if setting.Markdown.EnableHardLineBreak {
|
||||
extensions |= blackfriday.EXTENSION_HARD_LINE_BREAK
|
||||
}
|
||||
|
||||
body = blackfriday.Markdown(body, renderer, extensions)
|
||||
return body
|
||||
}
|
||||
|
||||
var (
|
||||
leftAngleBracket = []byte("</")
|
||||
rightAngleBracket = []byte(">")
|
||||
)
|
||||
|
||||
var noEndTags = []string{"img", "input", "br", "hr"}
|
||||
|
||||
// PreProcessMarkdown renders full links of commits, issues and pulls to shorter version.
|
||||
func PreProcessMarkdown(rawHTML []byte, urlPrefix string) []byte {
|
||||
ms := commitPattern.FindAll(rawHTML, -1)
|
||||
for _, m := range ms {
|
||||
m = bytes.TrimSpace(m)
|
||||
i := strings.Index(string(m), "commit/")
|
||||
j := strings.Index(string(m), "#")
|
||||
if j == -1 {
|
||||
j = len(m)
|
||||
}
|
||||
rawHTML = bytes.Replace(rawHTML, m, []byte(fmt.Sprintf(
|
||||
` <code><a href="%s">%s</a></code>`, m, ShortSha(string(m[i+7:j])))), -1)
|
||||
}
|
||||
ms = issueFullPattern.FindAll(rawHTML, -1)
|
||||
for _, m := range ms {
|
||||
m = bytes.TrimSpace(m)
|
||||
i := strings.Index(string(m), "issues/")
|
||||
j := strings.Index(string(m), "#")
|
||||
if j == -1 {
|
||||
j = len(m)
|
||||
}
|
||||
rawHTML = bytes.Replace(rawHTML, m, []byte(fmt.Sprintf(
|
||||
` <a href="%s">#%s</a>`, m, ShortSha(string(m[i+7:j])))), -1)
|
||||
}
|
||||
return rawHTML
|
||||
}
|
||||
|
||||
// PostProcessMarkdown treats different types of HTML differently,
|
||||
// and only renders special links for plain text blocks.
|
||||
func PostProcessMarkdown(rawHtml []byte, urlPrefix string, metas map[string]string) []byte {
|
||||
startTags := make([]string, 0, 5)
|
||||
var buf bytes.Buffer
|
||||
tokenizer := html.NewTokenizer(bytes.NewReader(rawHtml))
|
||||
|
||||
OUTER_LOOP:
|
||||
for html.ErrorToken != tokenizer.Next() {
|
||||
token := tokenizer.Token()
|
||||
switch token.Type {
|
||||
case html.TextToken:
|
||||
buf.Write(RenderSpecialLink([]byte(token.String()), urlPrefix, metas))
|
||||
|
||||
case html.StartTagToken:
|
||||
buf.WriteString(token.String())
|
||||
tagName := token.Data
|
||||
// If this is an excluded tag, we skip processing all output until a close tag is encountered.
|
||||
if strings.EqualFold("a", tagName) || strings.EqualFold("code", tagName) || strings.EqualFold("pre", tagName) {
|
||||
stackNum := 1
|
||||
for html.ErrorToken != tokenizer.Next() {
|
||||
token = tokenizer.Token()
|
||||
|
||||
// Copy the token to the output verbatim
|
||||
buf.WriteString(token.String())
|
||||
|
||||
if token.Type == html.StartTagToken {
|
||||
stackNum++
|
||||
}
|
||||
|
||||
// If this is the close tag to the outer-most, we are done
|
||||
if token.Type == html.EndTagToken && strings.EqualFold(tagName, token.Data) {
|
||||
stackNum--
|
||||
|
||||
if stackNum == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
continue OUTER_LOOP
|
||||
}
|
||||
|
||||
if !com.IsSliceContainsStr(noEndTags, token.Data) {
|
||||
startTags = append(startTags, token.Data)
|
||||
}
|
||||
|
||||
case html.EndTagToken:
|
||||
if len(startTags) == 0 {
|
||||
buf.WriteString(token.String())
|
||||
break
|
||||
}
|
||||
|
||||
buf.Write(leftAngleBracket)
|
||||
buf.WriteString(startTags[len(startTags)-1])
|
||||
buf.Write(rightAngleBracket)
|
||||
startTags = startTags[:len(startTags)-1]
|
||||
default:
|
||||
buf.WriteString(token.String())
|
||||
}
|
||||
}
|
||||
|
||||
if io.EOF == tokenizer.Err() {
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// If we are not at the end of the input, then some other parsing error has occurred,
|
||||
// so return the input verbatim.
|
||||
return rawHtml
|
||||
}
|
||||
|
||||
func RenderMarkdown(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
|
||||
result := PreProcessMarkdown(rawBytes, urlPrefix)
|
||||
result = RenderRawMarkdown(result, urlPrefix)
|
||||
result = PostProcessMarkdown(result, urlPrefix, metas)
|
||||
result = Sanitizer.SanitizeBytes(result)
|
||||
return result
|
||||
}
|
||||
|
||||
func RenderMarkdownString(raw, urlPrefix string, metas map[string]string) string {
|
||||
return string(RenderMarkdown([]byte(raw), urlPrefix, metas))
|
||||
}
|
||||
@@ -15,22 +15,21 @@ import (
|
||||
"hash"
|
||||
"html/template"
|
||||
"math"
|
||||
"regexp"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/Unknwon/i18n"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
|
||||
"github.com/gogits/chardet"
|
||||
|
||||
"github.com/gogits/gogs/modules/avatar"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
var Sanitizer = bluemonday.UGCPolicy().AllowAttrs("class").Matching(regexp.MustCompile(`[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&]*`)).OnElements("code")
|
||||
|
||||
// EncodeMD5 encodes string to md5 hex value.
|
||||
func EncodeMD5(str string) string {
|
||||
m := md5.New()
|
||||
@@ -53,11 +52,18 @@ func ShortSha(sha1 string) string {
|
||||
}
|
||||
|
||||
func DetectEncoding(content []byte) (string, error) {
|
||||
detector := chardet.NewTextDetector()
|
||||
result, err := detector.DetectBest(content)
|
||||
if utf8.Valid(content) {
|
||||
log.Debug("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)
|
||||
return setting.Repository.AnsiCharset, err
|
||||
}
|
||||
|
||||
log.Debug("Detected encoding: %s", result.Charset)
|
||||
return result.Charset, err
|
||||
}
|
||||
|
||||
@@ -188,17 +194,22 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string
|
||||
return code
|
||||
}
|
||||
|
||||
// AvatarLink returns avatar link by given e-mail.
|
||||
// HashEmail hashes email address to MD5 string.
|
||||
// https://en.gravatar.com/site/implement/hash/
|
||||
func HashEmail(email string) string {
|
||||
email = strings.ToLower(strings.TrimSpace(email))
|
||||
h := md5.New()
|
||||
h.Write([]byte(email))
|
||||
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.jpg"
|
||||
}
|
||||
|
||||
gravatarHash := avatar.HashEmail(email)
|
||||
if setting.Service.EnableCacheAvatar {
|
||||
return setting.AppSubUrl + "/avatar/" + gravatarHash
|
||||
}
|
||||
return setting.GravatarSource + gravatarHash
|
||||
return setting.GravatarSource + HashEmail(email)
|
||||
}
|
||||
|
||||
// Seconds-based time units
|
||||
@@ -444,6 +455,15 @@ func Subtract(left interface{}, right interface{}) interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
// EllipsisString returns a truncated short string,
|
||||
// it appends '...' in the end of the length of string is too large.
|
||||
func EllipsisString(str string, length int) string {
|
||||
if len(str) < length {
|
||||
return str
|
||||
}
|
||||
return str[:length-3] + "..."
|
||||
}
|
||||
|
||||
// StringsToInt64s converts a slice of string to a slice of int64.
|
||||
func StringsToInt64s(strs []string) []int64 {
|
||||
ints := make([]int64, len(strs))
|
||||
@@ -470,3 +490,25 @@ func Int64sToMap(ints []int64) map[int64]bool {
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// IsLetter reports whether the rune is a letter (category L).
|
||||
// https://github.com/golang/go/blob/master/src/go/scanner/scanner.go#L257
|
||||
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
|
||||
}
|
||||
return contentType, false
|
||||
}
|
||||
|
||||
func IsImageFile(data []byte) (string, bool) {
|
||||
contentType := http.DetectContentType(data)
|
||||
if strings.Index(contentType, "image/") != -1 {
|
||||
return contentType, true
|
||||
}
|
||||
return contentType, false
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,27 +0,0 @@
|
||||
package cron
|
||||
|
||||
import "time"
|
||||
|
||||
// ConstantDelaySchedule represents a simple recurring duty cycle, e.g. "Every 5 minutes".
|
||||
// It does not support jobs more frequent than once a second.
|
||||
type ConstantDelaySchedule struct {
|
||||
Delay time.Duration
|
||||
}
|
||||
|
||||
// Every returns a crontab Schedule that activates once every duration.
|
||||
// Delays of less than a second are not supported (will round up to 1 second).
|
||||
// Any fields less than a Second are truncated.
|
||||
func Every(duration time.Duration) ConstantDelaySchedule {
|
||||
if duration < time.Second {
|
||||
duration = time.Second
|
||||
}
|
||||
return ConstantDelaySchedule{
|
||||
Delay: duration - time.Duration(duration.Nanoseconds())%time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
// Next returns the next time this should be run.
|
||||
// This rounds so that the next activation time will be on the second.
|
||||
func (schedule ConstantDelaySchedule) Next(t time.Time) time.Time {
|
||||
return t.Add(schedule.Delay - time.Duration(t.Nanosecond())*time.Nanosecond)
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestConstantDelayNext(t *testing.T) {
|
||||
tests := []struct {
|
||||
time string
|
||||
delay time.Duration
|
||||
expected string
|
||||
}{
|
||||
// Simple cases
|
||||
{"Mon Jul 9 14:45 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"},
|
||||
{"Mon Jul 9 14:59 2012", 15 * time.Minute, "Mon Jul 9 15:14 2012"},
|
||||
{"Mon Jul 9 14:59:59 2012", 15 * time.Minute, "Mon Jul 9 15:14:59 2012"},
|
||||
|
||||
// Wrap around hours
|
||||
{"Mon Jul 9 15:45 2012", 35 * time.Minute, "Mon Jul 9 16:20 2012"},
|
||||
|
||||
// Wrap around days
|
||||
{"Mon Jul 9 23:46 2012", 14 * time.Minute, "Tue Jul 10 00:00 2012"},
|
||||
{"Mon Jul 9 23:45 2012", 35 * time.Minute, "Tue Jul 10 00:20 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", 44*time.Minute + 24*time.Second, "Tue Jul 10 00:20:15 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", 25*time.Hour + 44*time.Minute + 24*time.Second, "Thu Jul 11 01:20:15 2012"},
|
||||
|
||||
// Wrap around months
|
||||
{"Mon Jul 9 23:35 2012", 91*24*time.Hour + 25*time.Minute, "Thu Oct 9 00:00 2012"},
|
||||
|
||||
// Wrap around minute, hour, day, month, and year
|
||||
{"Mon Dec 31 23:59:45 2012", 15 * time.Second, "Tue Jan 1 00:00:00 2013"},
|
||||
|
||||
// Round to nearest second on the delay
|
||||
{"Mon Jul 9 14:45 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"},
|
||||
|
||||
// Round up to 1 second if the duration is less.
|
||||
{"Mon Jul 9 14:45:00 2012", 15 * time.Millisecond, "Mon Jul 9 14:45:01 2012"},
|
||||
|
||||
// Round to nearest second when calculating the next time.
|
||||
{"Mon Jul 9 14:45:00.005 2012", 15 * time.Minute, "Mon Jul 9 15:00 2012"},
|
||||
|
||||
// Round to nearest second for both.
|
||||
{"Mon Jul 9 14:45:00.005 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"},
|
||||
}
|
||||
|
||||
for _, c := range tests {
|
||||
actual := Every(c.delay).Next(getTime(c.time))
|
||||
expected := getTime(c.expected)
|
||||
if actual != expected {
|
||||
t.Errorf("%s, \"%s\": (expected) %v != %v (actual)", c.time, c.delay, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// Copyright 2012 Rob Figueiredo. All rights reserved.
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
@@ -6,207 +5,59 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/gogits/cron"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
// Cron keeps track of any number of entries, invoking the associated func as
|
||||
// specified by the schedule. It may be started, stopped, and the entries may
|
||||
// be inspected while running.
|
||||
type Cron struct {
|
||||
entries []*Entry
|
||||
stop chan struct{}
|
||||
add chan *Entry
|
||||
snapshot chan []*Entry
|
||||
running bool
|
||||
}
|
||||
var c = cron.New()
|
||||
|
||||
// Job is an interface for submitted cron jobs.
|
||||
type Job interface {
|
||||
Run()
|
||||
}
|
||||
|
||||
// The Schedule describes a job's duty cycle.
|
||||
type Schedule interface {
|
||||
// Return the next activation time, later than the given time.
|
||||
// Next is invoked initially, and then each time the job is run.
|
||||
Next(time.Time) time.Time
|
||||
}
|
||||
|
||||
// Entry consists of a schedule and the func to execute on that schedule.
|
||||
type Entry struct {
|
||||
Description string
|
||||
Spec string
|
||||
|
||||
// The schedule on which this job should be run.
|
||||
Schedule Schedule
|
||||
|
||||
// The next time the job will run. This is the zero time if Cron has not been
|
||||
// started or this entry's schedule is unsatisfiable
|
||||
Next time.Time
|
||||
|
||||
// The last time this job was run. This is the zero time if the job has never
|
||||
// been run.
|
||||
Prev time.Time
|
||||
|
||||
// The Job to run.
|
||||
Job Job
|
||||
|
||||
ExecTimes int // Execute times count.
|
||||
}
|
||||
|
||||
// byTime is a wrapper for sorting the entry array by time
|
||||
// (with zero time at the end).
|
||||
type byTime []*Entry
|
||||
|
||||
func (s byTime) Len() int { return len(s) }
|
||||
func (s byTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s byTime) Less(i, j int) bool {
|
||||
// Two zero times should return false.
|
||||
// Otherwise, zero is "greater" than any other time.
|
||||
// (To sort it at the end of the list.)
|
||||
if s[i].Next.IsZero() {
|
||||
return false
|
||||
}
|
||||
if s[j].Next.IsZero() {
|
||||
return true
|
||||
}
|
||||
return s[i].Next.Before(s[j].Next)
|
||||
}
|
||||
|
||||
// New returns a new Cron job runner.
|
||||
func New() *Cron {
|
||||
return &Cron{
|
||||
entries: nil,
|
||||
add: make(chan *Entry),
|
||||
stop: make(chan struct{}),
|
||||
snapshot: make(chan []*Entry),
|
||||
running: false,
|
||||
}
|
||||
}
|
||||
|
||||
// A wrapper that turns a func() into a cron.Job
|
||||
type FuncJob func()
|
||||
|
||||
func (f FuncJob) Run() { f() }
|
||||
|
||||
// AddFunc adds a func to the Cron to be run on the given schedule.
|
||||
func (c *Cron) AddFunc(desc, spec string, cmd func()) (*Entry, error) {
|
||||
return c.AddJob(desc, spec, FuncJob(cmd))
|
||||
}
|
||||
|
||||
// AddFunc adds a Job to the Cron to be run on the given schedule.
|
||||
func (c *Cron) AddJob(desc, spec string, cmd Job) (*Entry, error) {
|
||||
schedule, err := Parse(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.Schedule(desc, spec, schedule, cmd), nil
|
||||
}
|
||||
|
||||
// Schedule adds a Job to the Cron to be run on the given schedule.
|
||||
func (c *Cron) Schedule(desc, spec string, schedule Schedule, cmd Job) *Entry {
|
||||
entry := &Entry{
|
||||
Description: desc,
|
||||
Spec: spec,
|
||||
Schedule: schedule,
|
||||
Job: cmd,
|
||||
}
|
||||
if c.running {
|
||||
c.add <- entry
|
||||
} else {
|
||||
c.entries = append(c.entries, entry)
|
||||
}
|
||||
return entry
|
||||
}
|
||||
|
||||
// Entries returns a snapshot of the cron entries.
|
||||
func (c *Cron) Entries() []*Entry {
|
||||
if c.running {
|
||||
c.snapshot <- nil
|
||||
x := <-c.snapshot
|
||||
return x
|
||||
}
|
||||
return c.entrySnapshot()
|
||||
}
|
||||
|
||||
// Start the cron scheduler in its own go-routine.
|
||||
func (c *Cron) Start() {
|
||||
c.running = true
|
||||
go c.run()
|
||||
}
|
||||
|
||||
// Run the scheduler.. this is private just due to the need to synchronize
|
||||
// access to the 'running' state variable.
|
||||
func (c *Cron) run() {
|
||||
// Figure out the next activation times for each entry.
|
||||
now := time.Now().Local()
|
||||
for _, entry := range c.entries {
|
||||
entry.Next = entry.Schedule.Next(now)
|
||||
}
|
||||
|
||||
for {
|
||||
// Determine the next entry to run.
|
||||
sort.Sort(byTime(c.entries))
|
||||
|
||||
var effective time.Time
|
||||
if len(c.entries) == 0 || c.entries[0].Next.IsZero() {
|
||||
// If there are no entries yet, just sleep - it still handles new entries
|
||||
// and stop requests.
|
||||
effective = now.AddDate(10, 0, 0)
|
||||
} else {
|
||||
effective = c.entries[0].Next
|
||||
func NewContext() {
|
||||
var (
|
||||
entry *cron.Entry
|
||||
err error
|
||||
)
|
||||
if setting.Cron.UpdateMirror.Enabled {
|
||||
entry, err = c.AddFunc("Update mirrors", setting.Cron.UpdateMirror.Schedule, models.MirrorUpdate)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Update mirrors]: %v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case now = <-time.After(effective.Sub(now)):
|
||||
// Run every entry whose next time was this effective time.
|
||||
for _, e := range c.entries {
|
||||
if e.Next != effective {
|
||||
break
|
||||
}
|
||||
go e.Job.Run()
|
||||
e.ExecTimes++
|
||||
e.Prev = e.Next
|
||||
e.Next = e.Schedule.Next(effective)
|
||||
}
|
||||
continue
|
||||
|
||||
case newEntry := <-c.add:
|
||||
c.entries = append(c.entries, newEntry)
|
||||
newEntry.Next = newEntry.Schedule.Next(now)
|
||||
|
||||
case <-c.snapshot:
|
||||
c.snapshot <- c.entrySnapshot()
|
||||
|
||||
case <-c.stop:
|
||||
return
|
||||
if setting.Cron.UpdateMirror.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
entry.ExecTimes++
|
||||
go models.MirrorUpdate()
|
||||
}
|
||||
|
||||
// 'now' should be updated after newEntry and snapshot cases.
|
||||
now = time.Now().Local()
|
||||
}
|
||||
}
|
||||
|
||||
// Stop the cron scheduler.
|
||||
func (c *Cron) Stop() {
|
||||
c.stop <- struct{}{}
|
||||
c.running = false
|
||||
}
|
||||
|
||||
// entrySnapshot returns a copy of the current cron entry list.
|
||||
func (c *Cron) entrySnapshot() []*Entry {
|
||||
entries := make([]*Entry, 0, len(c.entries))
|
||||
for _, e := range c.entries {
|
||||
entries = append(entries, &Entry{
|
||||
Description: e.Description,
|
||||
Spec: e.Spec,
|
||||
Schedule: e.Schedule,
|
||||
Next: e.Next,
|
||||
Prev: e.Prev,
|
||||
Job: e.Job,
|
||||
ExecTimes: e.ExecTimes,
|
||||
})
|
||||
if setting.Cron.RepoHealthCheck.Enabled {
|
||||
entry, err = c.AddFunc("Repository health check", setting.Cron.RepoHealthCheck.Schedule, models.GitFsck)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Repository health check]: %v", err)
|
||||
}
|
||||
if setting.Cron.RepoHealthCheck.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
entry.ExecTimes++
|
||||
go models.GitFsck()
|
||||
}
|
||||
}
|
||||
return entries
|
||||
if setting.Cron.CheckRepoStats.Enabled {
|
||||
entry, err = c.AddFunc("Check repository statistics", setting.Cron.CheckRepoStats.Schedule, models.CheckRepoStats)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Check repository statistics]: %v", err)
|
||||
}
|
||||
if setting.Cron.CheckRepoStats.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
entry.ExecTimes++
|
||||
go models.CheckRepoStats()
|
||||
}
|
||||
}
|
||||
c.Start()
|
||||
}
|
||||
|
||||
// ListTasks returns all running cron tasks.
|
||||
func ListTasks() []*cron.Entry {
|
||||
return c.Entries()
|
||||
}
|
||||
|
||||
@@ -1,255 +0,0 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Many tests schedule a job for every second, and then wait at most a second
|
||||
// for it to run. This amount is just slightly larger than 1 second to
|
||||
// compensate for a few milliseconds of runtime.
|
||||
const ONE_SECOND = 1*time.Second + 10*time.Millisecond
|
||||
|
||||
// Start and stop cron with no entries.
|
||||
func TestNoEntries(t *testing.T) {
|
||||
cron := New()
|
||||
cron.Start()
|
||||
|
||||
select {
|
||||
case <-time.After(ONE_SECOND):
|
||||
t.FailNow()
|
||||
case <-stop(cron):
|
||||
}
|
||||
}
|
||||
|
||||
// Start, stop, then add an entry. Verify entry doesn't run.
|
||||
func TestStopCausesJobsToNotRun(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := New()
|
||||
cron.Start()
|
||||
cron.Stop()
|
||||
cron.AddFunc("", "* * * * * ?", func() { wg.Done() })
|
||||
|
||||
select {
|
||||
case <-time.After(ONE_SECOND):
|
||||
// No job ran!
|
||||
case <-wait(wg):
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Add a job, start cron, expect it runs.
|
||||
func TestAddBeforeRunning(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := New()
|
||||
cron.AddFunc("", "* * * * * ?", func() { wg.Done() })
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
// Give cron 2 seconds to run our job (which is always activated).
|
||||
select {
|
||||
case <-time.After(ONE_SECOND):
|
||||
t.FailNow()
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Start cron, add a job, expect it runs.
|
||||
func TestAddWhileRunning(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := New()
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
cron.AddFunc("", "* * * * * ?", func() { wg.Done() })
|
||||
|
||||
select {
|
||||
case <-time.After(ONE_SECOND):
|
||||
t.FailNow()
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Test timing with Entries.
|
||||
func TestSnapshotEntries(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := New()
|
||||
cron.AddFunc("", "@every 2s", func() { wg.Done() })
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
// Cron should fire in 2 seconds. After 1 second, call Entries.
|
||||
select {
|
||||
case <-time.After(ONE_SECOND):
|
||||
cron.Entries()
|
||||
}
|
||||
|
||||
// Even though Entries was called, the cron should fire at the 2 second mark.
|
||||
select {
|
||||
case <-time.After(ONE_SECOND):
|
||||
t.FailNow()
|
||||
case <-wait(wg):
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Test that the entries are correctly sorted.
|
||||
// Add a bunch of long-in-the-future entries, and an immediate entry, and ensure
|
||||
// that the immediate entry runs immediately.
|
||||
// Also: Test that multiple jobs run in the same instant.
|
||||
func TestMultipleEntries(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
cron := New()
|
||||
cron.AddFunc("", "0 0 0 1 1 ?", func() {})
|
||||
cron.AddFunc("", "* * * * * ?", func() { wg.Done() })
|
||||
cron.AddFunc("", "0 0 0 31 12 ?", func() {})
|
||||
cron.AddFunc("", "* * * * * ?", func() { wg.Done() })
|
||||
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(ONE_SECOND):
|
||||
t.FailNow()
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Test running the same job twice.
|
||||
func TestRunningJobTwice(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
cron := New()
|
||||
cron.AddFunc("", "0 0 0 1 1 ?", func() {})
|
||||
cron.AddFunc("", "0 0 0 31 12 ?", func() {})
|
||||
cron.AddFunc("", "* * * * * ?", func() { wg.Done() })
|
||||
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(2 * ONE_SECOND):
|
||||
t.FailNow()
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunningMultipleSchedules(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
cron := New()
|
||||
cron.AddFunc("", "0 0 0 1 1 ?", func() {})
|
||||
cron.AddFunc("", "0 0 0 31 12 ?", func() {})
|
||||
cron.AddFunc("", "* * * * * ?", func() { wg.Done() })
|
||||
cron.Schedule("", "", Every(time.Minute), FuncJob(func() {}))
|
||||
cron.Schedule("", "", Every(time.Second), FuncJob(func() { wg.Done() }))
|
||||
cron.Schedule("", "", Every(time.Hour), FuncJob(func() {}))
|
||||
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(2 * ONE_SECOND):
|
||||
t.FailNow()
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Test that the cron is run in the local time zone (as opposed to UTC).
|
||||
func TestLocalTimezone(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
now := time.Now().Local()
|
||||
spec := fmt.Sprintf("%d %d %d %d %d ?",
|
||||
now.Second()+1, now.Minute(), now.Hour(), now.Day(), now.Month())
|
||||
|
||||
cron := New()
|
||||
cron.AddFunc("", spec, func() { wg.Done() })
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(ONE_SECOND):
|
||||
t.FailNow()
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
type testJob struct {
|
||||
wg *sync.WaitGroup
|
||||
name string
|
||||
}
|
||||
|
||||
func (t testJob) Run() {
|
||||
t.wg.Done()
|
||||
}
|
||||
|
||||
// Simple test using Runnables.
|
||||
func TestJob(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := New()
|
||||
cron.AddJob("", "0 0 0 30 Feb ?", testJob{wg, "job0"})
|
||||
cron.AddJob("", "0 0 0 1 1 ?", testJob{wg, "job1"})
|
||||
cron.AddJob("", "* * * * * ?", testJob{wg, "job2"})
|
||||
cron.AddJob("", "1 0 0 1 1 ?", testJob{wg, "job3"})
|
||||
cron.Schedule("", "", Every(5*time.Second+5*time.Nanosecond), testJob{wg, "job4"})
|
||||
cron.Schedule("", "", Every(5*time.Minute), testJob{wg, "job5"})
|
||||
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(ONE_SECOND):
|
||||
t.FailNow()
|
||||
case <-wait(wg):
|
||||
}
|
||||
|
||||
// Ensure the entries are in the right order.
|
||||
expecteds := []string{"job2", "job4", "job5", "job1", "job3", "job0"}
|
||||
|
||||
var actuals []string
|
||||
for _, entry := range cron.Entries() {
|
||||
actuals = append(actuals, entry.Job.(testJob).name)
|
||||
}
|
||||
|
||||
for i, expected := range expecteds {
|
||||
if actuals[i] != expected {
|
||||
t.Errorf("Jobs not in the right order. (expected) %s != %s (actual)", expecteds, actuals)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func wait(wg *sync.WaitGroup) chan bool {
|
||||
ch := make(chan bool)
|
||||
go func() {
|
||||
wg.Wait()
|
||||
ch <- true
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
func stop(cron *Cron) chan bool {
|
||||
ch := make(chan bool)
|
||||
go func() {
|
||||
cron.Stop()
|
||||
ch <- true
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
Package cron implements a cron spec parser and job runner.
|
||||
|
||||
Usage
|
||||
|
||||
Callers may register Funcs to be invoked on a given schedule. Cron will run
|
||||
them in their own goroutines.
|
||||
|
||||
c := cron.New()
|
||||
c.AddFunc("Every hour on the half hour","0 30 * * * *", func() { fmt.Println("Every hour on the half hour") })
|
||||
c.AddFunc("Every hour","@hourly", func() { fmt.Println("Every hour") })
|
||||
c.AddFunc("Every hour and a half","@every 1h30m", func() { fmt.Println("Every hour thirty") })
|
||||
c.Start()
|
||||
..
|
||||
// Funcs are invoked in their own goroutine, asynchronously.
|
||||
...
|
||||
// Funcs may also be added to a running Cron
|
||||
c.AddFunc("@daily", func() { fmt.Println("Every day") })
|
||||
..
|
||||
// Inspect the cron job entries' next and previous run times.
|
||||
inspect(c.Entries())
|
||||
..
|
||||
c.Stop() // Stop the scheduler (does not stop any jobs already running).
|
||||
|
||||
CRON Expression Format
|
||||
|
||||
A cron expression represents a set of times, using 6 space-separated fields.
|
||||
|
||||
Field name | Mandatory? | Allowed values | Allowed special characters
|
||||
---------- | ---------- | -------------- | --------------------------
|
||||
Seconds | Yes | 0-59 | * / , -
|
||||
Minutes | Yes | 0-59 | * / , -
|
||||
Hours | Yes | 0-23 | * / , -
|
||||
Day of month | Yes | 1-31 | * / , - ?
|
||||
Month | Yes | 1-12 or JAN-DEC | * / , -
|
||||
Day of week | Yes | 0-6 or SUN-SAT | * / , - ?
|
||||
|
||||
Note: Month and Day-of-week field values are case insensitive. "SUN", "Sun",
|
||||
and "sun" are equally accepted.
|
||||
|
||||
Special Characters
|
||||
|
||||
Asterisk ( * )
|
||||
|
||||
The asterisk indicates that the cron expression will match for all values of the
|
||||
field; e.g., using an asterisk in the 5th field (month) would indicate every
|
||||
month.
|
||||
|
||||
Slash ( / )
|
||||
|
||||
Slashes are used to describe increments of ranges. For example 3-59/15 in the
|
||||
1st field (minutes) would indicate the 3rd minute of the hour and every 15
|
||||
minutes thereafter. The form "*\/..." is equivalent to the form "first-last/...",
|
||||
that is, an increment over the largest possible range of the field. The form
|
||||
"N/..." is accepted as meaning "N-MAX/...", that is, starting at N, use the
|
||||
increment until the end of that specific range. It does not wrap around.
|
||||
|
||||
Comma ( , )
|
||||
|
||||
Commas are used to separate items of a list. For example, using "MON,WED,FRI" in
|
||||
the 5th field (day of week) would mean Mondays, Wednesdays and Fridays.
|
||||
|
||||
Hyphen ( - )
|
||||
|
||||
Hyphens are used to define ranges. For example, 9-17 would indicate every
|
||||
hour between 9am and 5pm inclusive.
|
||||
|
||||
Question mark ( ? )
|
||||
|
||||
Question mark may be used instead of '*' for leaving either day-of-month or
|
||||
day-of-week blank.
|
||||
|
||||
Predefined schedules
|
||||
|
||||
You may use one of several pre-defined schedules in place of a cron expression.
|
||||
|
||||
Entry | Description | Equivalent To
|
||||
----- | ----------- | -------------
|
||||
@yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 0 1 1 *
|
||||
@monthly | Run once a month, midnight, first of month | 0 0 0 1 * *
|
||||
@weekly | Run once a week, midnight on Sunday | 0 0 0 * * 0
|
||||
@daily (or @midnight) | Run once a day, midnight | 0 0 0 * * *
|
||||
@hourly | Run once an hour, beginning of hour | 0 0 * * * *
|
||||
|
||||
Intervals
|
||||
|
||||
You may also schedule a job to execute at fixed intervals. This is supported by
|
||||
formatting the cron spec like this:
|
||||
|
||||
@every <duration>
|
||||
|
||||
where "duration" is a string accepted by time.ParseDuration
|
||||
(http://golang.org/pkg/time/#ParseDuration).
|
||||
|
||||
For example, "@every 1h30m10s" would indicate a schedule that activates every
|
||||
1 hour, 30 minutes, 10 seconds.
|
||||
|
||||
Note: The interval does not take the job runtime into account. For example,
|
||||
if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes,
|
||||
it will have only 2 minutes of idle time between each run.
|
||||
|
||||
Time zones
|
||||
|
||||
All interpretation and scheduling is done in the machine's local time zone (as
|
||||
provided by the Go time package (http://www.golang.org/pkg/time).
|
||||
|
||||
Be aware that jobs scheduled during daylight-savings leap-ahead transitions will
|
||||
not be run!
|
||||
|
||||
Thread safety
|
||||
|
||||
Since the Cron service runs concurrently with the calling code, some amount of
|
||||
care must be taken to ensure proper synchronization.
|
||||
|
||||
All cron methods are designed to be correctly synchronized as long as the caller
|
||||
ensures that invocations have a clear happens-before ordering between them.
|
||||
|
||||
Implementation
|
||||
|
||||
Cron entries are stored in an array, sorted by their next activation time. Cron
|
||||
sleeps until the next job is due to be run.
|
||||
|
||||
Upon waking:
|
||||
- it runs each entry that is active on that second
|
||||
- it calculates the next run times for the jobs that were run
|
||||
- it re-sorts the array of entries by next activation time.
|
||||
- it goes to sleep until the soonest job.
|
||||
*/
|
||||
package cron
|
||||
@@ -1,231 +0,0 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Parse returns a new crontab schedule representing the given spec.
|
||||
// It returns a descriptive error if the spec is not valid.
|
||||
//
|
||||
// It accepts
|
||||
// - Full crontab specs, e.g. "* * * * * ?"
|
||||
// - Descriptors, e.g. "@midnight", "@every 1h30m"
|
||||
func Parse(spec string) (_ Schedule, err error) {
|
||||
// Convert panics into errors
|
||||
defer func() {
|
||||
if recovered := recover(); recovered != nil {
|
||||
err = fmt.Errorf("%v", recovered)
|
||||
}
|
||||
}()
|
||||
|
||||
if spec[0] == '@' {
|
||||
return parseDescriptor(spec), nil
|
||||
}
|
||||
|
||||
// Split on whitespace. We require 5 or 6 fields.
|
||||
// (second) (minute) (hour) (day of month) (month) (day of week, optional)
|
||||
fields := strings.Fields(spec)
|
||||
if len(fields) != 5 && len(fields) != 6 {
|
||||
log.Panicf("Expected 5 or 6 fields, found %d: %s", len(fields), spec)
|
||||
}
|
||||
|
||||
// If a sixth field is not provided (DayOfWeek), then it is equivalent to star.
|
||||
if len(fields) == 5 {
|
||||
fields = append(fields, "*")
|
||||
}
|
||||
|
||||
schedule := &SpecSchedule{
|
||||
Second: getField(fields[0], seconds),
|
||||
Minute: getField(fields[1], minutes),
|
||||
Hour: getField(fields[2], hours),
|
||||
Dom: getField(fields[3], dom),
|
||||
Month: getField(fields[4], months),
|
||||
Dow: getField(fields[5], dow),
|
||||
}
|
||||
|
||||
return schedule, nil
|
||||
}
|
||||
|
||||
// getField returns an Int with the bits set representing all of the times that
|
||||
// the field represents. A "field" is a comma-separated list of "ranges".
|
||||
func getField(field string, r bounds) uint64 {
|
||||
// list = range {"," range}
|
||||
var bits uint64
|
||||
ranges := strings.FieldsFunc(field, func(r rune) bool { return r == ',' })
|
||||
for _, expr := range ranges {
|
||||
bits |= getRange(expr, r)
|
||||
}
|
||||
return bits
|
||||
}
|
||||
|
||||
// getRange returns the bits indicated by the given expression:
|
||||
// number | number "-" number [ "/" number ]
|
||||
func getRange(expr string, r bounds) uint64 {
|
||||
|
||||
var (
|
||||
start, end, step uint
|
||||
rangeAndStep = strings.Split(expr, "/")
|
||||
lowAndHigh = strings.Split(rangeAndStep[0], "-")
|
||||
singleDigit = len(lowAndHigh) == 1
|
||||
)
|
||||
|
||||
var extra_star uint64
|
||||
if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" {
|
||||
start = r.min
|
||||
end = r.max
|
||||
extra_star = starBit
|
||||
} else {
|
||||
start = parseIntOrName(lowAndHigh[0], r.names)
|
||||
switch len(lowAndHigh) {
|
||||
case 1:
|
||||
end = start
|
||||
case 2:
|
||||
end = parseIntOrName(lowAndHigh[1], r.names)
|
||||
default:
|
||||
log.Panicf("Too many hyphens: %s", expr)
|
||||
}
|
||||
}
|
||||
|
||||
switch len(rangeAndStep) {
|
||||
case 1:
|
||||
step = 1
|
||||
case 2:
|
||||
step = mustParseInt(rangeAndStep[1])
|
||||
|
||||
// Special handling: "N/step" means "N-max/step".
|
||||
if singleDigit {
|
||||
end = r.max
|
||||
}
|
||||
default:
|
||||
log.Panicf("Too many slashes: %s", expr)
|
||||
}
|
||||
|
||||
if start < r.min {
|
||||
log.Panicf("Beginning of range (%d) below minimum (%d): %s", start, r.min, expr)
|
||||
}
|
||||
if end > r.max {
|
||||
log.Panicf("End of range (%d) above maximum (%d): %s", end, r.max, expr)
|
||||
}
|
||||
if start > end {
|
||||
log.Panicf("Beginning of range (%d) beyond end of range (%d): %s", start, end, expr)
|
||||
}
|
||||
|
||||
return getBits(start, end, step) | extra_star
|
||||
}
|
||||
|
||||
// parseIntOrName returns the (possibly-named) integer contained in expr.
|
||||
func parseIntOrName(expr string, names map[string]uint) uint {
|
||||
if names != nil {
|
||||
if namedInt, ok := names[strings.ToLower(expr)]; ok {
|
||||
return namedInt
|
||||
}
|
||||
}
|
||||
return mustParseInt(expr)
|
||||
}
|
||||
|
||||
// mustParseInt parses the given expression as an int or panics.
|
||||
func mustParseInt(expr string) uint {
|
||||
num, err := strconv.Atoi(expr)
|
||||
if err != nil {
|
||||
log.Panicf("Failed to parse int from %s: %s", expr, err)
|
||||
}
|
||||
if num < 0 {
|
||||
log.Panicf("Negative number (%d) not allowed: %s", num, expr)
|
||||
}
|
||||
|
||||
return uint(num)
|
||||
}
|
||||
|
||||
// getBits sets all bits in the range [min, max], modulo the given step size.
|
||||
func getBits(min, max, step uint) uint64 {
|
||||
var bits uint64
|
||||
|
||||
// If step is 1, use shifts.
|
||||
if step == 1 {
|
||||
return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min)
|
||||
}
|
||||
|
||||
// Else, use a simple loop.
|
||||
for i := min; i <= max; i += step {
|
||||
bits |= 1 << i
|
||||
}
|
||||
return bits
|
||||
}
|
||||
|
||||
// all returns all bits within the given bounds. (plus the star bit)
|
||||
func all(r bounds) uint64 {
|
||||
return getBits(r.min, r.max, 1) | starBit
|
||||
}
|
||||
|
||||
// parseDescriptor returns a pre-defined schedule for the expression, or panics
|
||||
// if none matches.
|
||||
func parseDescriptor(spec string) Schedule {
|
||||
switch spec {
|
||||
case "@yearly", "@annually":
|
||||
return &SpecSchedule{
|
||||
Second: 1 << seconds.min,
|
||||
Minute: 1 << minutes.min,
|
||||
Hour: 1 << hours.min,
|
||||
Dom: 1 << dom.min,
|
||||
Month: 1 << months.min,
|
||||
Dow: all(dow),
|
||||
}
|
||||
|
||||
case "@monthly":
|
||||
return &SpecSchedule{
|
||||
Second: 1 << seconds.min,
|
||||
Minute: 1 << minutes.min,
|
||||
Hour: 1 << hours.min,
|
||||
Dom: 1 << dom.min,
|
||||
Month: all(months),
|
||||
Dow: all(dow),
|
||||
}
|
||||
|
||||
case "@weekly":
|
||||
return &SpecSchedule{
|
||||
Second: 1 << seconds.min,
|
||||
Minute: 1 << minutes.min,
|
||||
Hour: 1 << hours.min,
|
||||
Dom: all(dom),
|
||||
Month: all(months),
|
||||
Dow: 1 << dow.min,
|
||||
}
|
||||
|
||||
case "@daily", "@midnight":
|
||||
return &SpecSchedule{
|
||||
Second: 1 << seconds.min,
|
||||
Minute: 1 << minutes.min,
|
||||
Hour: 1 << hours.min,
|
||||
Dom: all(dom),
|
||||
Month: all(months),
|
||||
Dow: all(dow),
|
||||
}
|
||||
|
||||
case "@hourly":
|
||||
return &SpecSchedule{
|
||||
Second: 1 << seconds.min,
|
||||
Minute: 1 << minutes.min,
|
||||
Hour: all(hours),
|
||||
Dom: all(dom),
|
||||
Month: all(months),
|
||||
Dow: all(dow),
|
||||
}
|
||||
}
|
||||
|
||||
const every = "@every "
|
||||
if strings.HasPrefix(spec, every) {
|
||||
duration, err := time.ParseDuration(spec[len(every):])
|
||||
if err != nil {
|
||||
log.Panicf("Failed to parse duration %s: %s", spec, err)
|
||||
}
|
||||
return Every(duration)
|
||||
}
|
||||
|
||||
log.Panicf("Unrecognized descriptor: %s", spec)
|
||||
return nil
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRange(t *testing.T) {
|
||||
ranges := []struct {
|
||||
expr string
|
||||
min, max uint
|
||||
expected uint64
|
||||
}{
|
||||
{"5", 0, 7, 1 << 5},
|
||||
{"0", 0, 7, 1 << 0},
|
||||
{"7", 0, 7, 1 << 7},
|
||||
|
||||
{"5-5", 0, 7, 1 << 5},
|
||||
{"5-6", 0, 7, 1<<5 | 1<<6},
|
||||
{"5-7", 0, 7, 1<<5 | 1<<6 | 1<<7},
|
||||
|
||||
{"5-6/2", 0, 7, 1 << 5},
|
||||
{"5-7/2", 0, 7, 1<<5 | 1<<7},
|
||||
{"5-7/1", 0, 7, 1<<5 | 1<<6 | 1<<7},
|
||||
|
||||
{"*", 1, 3, 1<<1 | 1<<2 | 1<<3 | starBit},
|
||||
{"*/2", 1, 3, 1<<1 | 1<<3 | starBit},
|
||||
}
|
||||
|
||||
for _, c := range ranges {
|
||||
actual := getRange(c.expr, bounds{c.min, c.max, nil})
|
||||
if actual != c.expected {
|
||||
t.Errorf("%s => (expected) %d != %d (actual)", c.expr, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestField(t *testing.T) {
|
||||
fields := []struct {
|
||||
expr string
|
||||
min, max uint
|
||||
expected uint64
|
||||
}{
|
||||
{"5", 1, 7, 1 << 5},
|
||||
{"5,6", 1, 7, 1<<5 | 1<<6},
|
||||
{"5,6,7", 1, 7, 1<<5 | 1<<6 | 1<<7},
|
||||
{"1,5-7/2,3", 1, 7, 1<<1 | 1<<5 | 1<<7 | 1<<3},
|
||||
}
|
||||
|
||||
for _, c := range fields {
|
||||
actual := getField(c.expr, bounds{c.min, c.max, nil})
|
||||
if actual != c.expected {
|
||||
t.Errorf("%s => (expected) %d != %d (actual)", c.expr, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBits(t *testing.T) {
|
||||
allBits := []struct {
|
||||
r bounds
|
||||
expected uint64
|
||||
}{
|
||||
{minutes, 0xfffffffffffffff}, // 0-59: 60 ones
|
||||
{hours, 0xffffff}, // 0-23: 24 ones
|
||||
{dom, 0xfffffffe}, // 1-31: 31 ones, 1 zero
|
||||
{months, 0x1ffe}, // 1-12: 12 ones, 1 zero
|
||||
{dow, 0x7f}, // 0-6: 7 ones
|
||||
}
|
||||
|
||||
for _, c := range allBits {
|
||||
actual := all(c.r) // all() adds the starBit, so compensate for that..
|
||||
if c.expected|starBit != actual {
|
||||
t.Errorf("%d-%d/%d => (expected) %b != %b (actual)",
|
||||
c.r.min, c.r.max, 1, c.expected|starBit, actual)
|
||||
}
|
||||
}
|
||||
|
||||
bits := []struct {
|
||||
min, max, step uint
|
||||
expected uint64
|
||||
}{
|
||||
|
||||
{0, 0, 1, 0x1},
|
||||
{1, 1, 1, 0x2},
|
||||
{1, 5, 2, 0x2a}, // 101010
|
||||
{1, 4, 2, 0xa}, // 1010
|
||||
}
|
||||
|
||||
for _, c := range bits {
|
||||
actual := getBits(c.min, c.max, c.step)
|
||||
if c.expected != actual {
|
||||
t.Errorf("%d-%d/%d => (expected) %b != %b (actual)",
|
||||
c.min, c.max, c.step, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpecSchedule(t *testing.T) {
|
||||
entries := []struct {
|
||||
expr string
|
||||
expected Schedule
|
||||
}{
|
||||
{"* 5 * * * *", &SpecSchedule{all(seconds), 1 << 5, all(hours), all(dom), all(months), all(dow)}},
|
||||
{"@every 5m", ConstantDelaySchedule{time.Duration(5) * time.Minute}},
|
||||
}
|
||||
|
||||
for _, c := range entries {
|
||||
actual, err := Parse(c.expr)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !reflect.DeepEqual(actual, c.expected) {
|
||||
t.Errorf("%s => (expected) %v != %v (actual)", c.expr, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// SpecSchedule specifies a duty cycle (to the second granularity), based on a
|
||||
// traditional crontab specification. It is computed initially and stored as bit sets.
|
||||
type SpecSchedule struct {
|
||||
Second, Minute, Hour, Dom, Month, Dow uint64
|
||||
}
|
||||
|
||||
// bounds provides a range of acceptable values (plus a map of name to value).
|
||||
type bounds struct {
|
||||
min, max uint
|
||||
names map[string]uint
|
||||
}
|
||||
|
||||
// The bounds for each field.
|
||||
var (
|
||||
seconds = bounds{0, 59, nil}
|
||||
minutes = bounds{0, 59, nil}
|
||||
hours = bounds{0, 23, nil}
|
||||
dom = bounds{1, 31, nil}
|
||||
months = bounds{1, 12, map[string]uint{
|
||||
"jan": 1,
|
||||
"feb": 2,
|
||||
"mar": 3,
|
||||
"apr": 4,
|
||||
"may": 5,
|
||||
"jun": 6,
|
||||
"jul": 7,
|
||||
"aug": 8,
|
||||
"sep": 9,
|
||||
"oct": 10,
|
||||
"nov": 11,
|
||||
"dec": 12,
|
||||
}}
|
||||
dow = bounds{0, 6, map[string]uint{
|
||||
"sun": 0,
|
||||
"mon": 1,
|
||||
"tue": 2,
|
||||
"wed": 3,
|
||||
"thu": 4,
|
||||
"fri": 5,
|
||||
"sat": 6,
|
||||
}}
|
||||
)
|
||||
|
||||
const (
|
||||
// Set the top bit if a star was included in the expression.
|
||||
starBit = 1 << 63
|
||||
)
|
||||
|
||||
// Next returns the next time this schedule is activated, greater than the given
|
||||
// time. If no time can be found to satisfy the schedule, return the zero time.
|
||||
func (s *SpecSchedule) Next(t time.Time) time.Time {
|
||||
// General approach:
|
||||
// For Month, Day, Hour, Minute, Second:
|
||||
// Check if the time value matches. If yes, continue to the next field.
|
||||
// If the field doesn't match the schedule, then increment the field until it matches.
|
||||
// While incrementing the field, a wrap-around brings it back to the beginning
|
||||
// of the field list (since it is necessary to re-verify previous field
|
||||
// values)
|
||||
|
||||
// Start at the earliest possible time (the upcoming second).
|
||||
t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond)
|
||||
|
||||
// This flag indicates whether a field has been incremented.
|
||||
added := false
|
||||
|
||||
// If no time is found within five years, return zero.
|
||||
yearLimit := t.Year() + 5
|
||||
|
||||
WRAP:
|
||||
if t.Year() > yearLimit {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// Find the first applicable month.
|
||||
// If it's this month, then do nothing.
|
||||
for 1<<uint(t.Month())&s.Month == 0 {
|
||||
// If we have to add a month, reset the other parts to 0.
|
||||
if !added {
|
||||
added = true
|
||||
// Otherwise, set the date at the beginning (since the current time is irrelevant).
|
||||
t = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
|
||||
}
|
||||
t = t.AddDate(0, 1, 0)
|
||||
|
||||
// Wrapped around.
|
||||
if t.Month() == time.January {
|
||||
goto WRAP
|
||||
}
|
||||
}
|
||||
|
||||
// Now get a day in that month.
|
||||
for !dayMatches(s, t) {
|
||||
if !added {
|
||||
added = true
|
||||
t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
||||
}
|
||||
t = t.AddDate(0, 0, 1)
|
||||
|
||||
if t.Day() == 1 {
|
||||
goto WRAP
|
||||
}
|
||||
}
|
||||
|
||||
for 1<<uint(t.Hour())&s.Hour == 0 {
|
||||
if !added {
|
||||
added = true
|
||||
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 0, 0, 0, t.Location())
|
||||
}
|
||||
t = t.Add(1 * time.Hour)
|
||||
|
||||
if t.Hour() == 0 {
|
||||
goto WRAP
|
||||
}
|
||||
}
|
||||
|
||||
for 1<<uint(t.Minute())&s.Minute == 0 {
|
||||
if !added {
|
||||
added = true
|
||||
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), 0, 0, t.Location())
|
||||
}
|
||||
t = t.Add(1 * time.Minute)
|
||||
|
||||
if t.Minute() == 0 {
|
||||
goto WRAP
|
||||
}
|
||||
}
|
||||
|
||||
for 1<<uint(t.Second())&s.Second == 0 {
|
||||
if !added {
|
||||
added = true
|
||||
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), 0, t.Location())
|
||||
}
|
||||
t = t.Add(1 * time.Second)
|
||||
|
||||
if t.Second() == 0 {
|
||||
goto WRAP
|
||||
}
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// dayMatches returns true if the schedule's day-of-week and day-of-month
|
||||
// restrictions are satisfied by the given time.
|
||||
func dayMatches(s *SpecSchedule, t time.Time) bool {
|
||||
var (
|
||||
domMatch bool = 1<<uint(t.Day())&s.Dom > 0
|
||||
dowMatch bool = 1<<uint(t.Weekday())&s.Dow > 0
|
||||
)
|
||||
|
||||
if s.Dom&starBit > 0 || s.Dow&starBit > 0 {
|
||||
return domMatch && dowMatch
|
||||
}
|
||||
return domMatch || dowMatch
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestActivation(t *testing.T) {
|
||||
tests := []struct {
|
||||
time, spec string
|
||||
expected bool
|
||||
}{
|
||||
// Every fifteen minutes.
|
||||
{"Mon Jul 9 15:00 2012", "0 0/15 * * *", true},
|
||||
{"Mon Jul 9 15:45 2012", "0 0/15 * * *", true},
|
||||
{"Mon Jul 9 15:40 2012", "0 0/15 * * *", false},
|
||||
|
||||
// Every fifteen minutes, starting at 5 minutes.
|
||||
{"Mon Jul 9 15:05 2012", "0 5/15 * * *", true},
|
||||
{"Mon Jul 9 15:20 2012", "0 5/15 * * *", true},
|
||||
{"Mon Jul 9 15:50 2012", "0 5/15 * * *", true},
|
||||
|
||||
// Named months
|
||||
{"Sun Jul 15 15:00 2012", "0 0/15 * * Jul", true},
|
||||
{"Sun Jul 15 15:00 2012", "0 0/15 * * Jun", false},
|
||||
|
||||
// Everything set.
|
||||
{"Sun Jul 15 08:30 2012", "0 30 08 ? Jul Sun", true},
|
||||
{"Sun Jul 15 08:30 2012", "0 30 08 15 Jul ?", true},
|
||||
{"Mon Jul 16 08:30 2012", "0 30 08 ? Jul Sun", false},
|
||||
{"Mon Jul 16 08:30 2012", "0 30 08 15 Jul ?", false},
|
||||
|
||||
// Predefined schedules
|
||||
{"Mon Jul 9 15:00 2012", "@hourly", true},
|
||||
{"Mon Jul 9 15:04 2012", "@hourly", false},
|
||||
{"Mon Jul 9 15:00 2012", "@daily", false},
|
||||
{"Mon Jul 9 00:00 2012", "@daily", true},
|
||||
{"Mon Jul 9 00:00 2012", "@weekly", false},
|
||||
{"Sun Jul 8 00:00 2012", "@weekly", true},
|
||||
{"Sun Jul 8 01:00 2012", "@weekly", false},
|
||||
{"Sun Jul 8 00:00 2012", "@monthly", false},
|
||||
{"Sun Jul 1 00:00 2012", "@monthly", true},
|
||||
|
||||
// Test interaction of DOW and DOM.
|
||||
// If both are specified, then only one needs to match.
|
||||
{"Sun Jul 15 00:00 2012", "0 * * 1,15 * Sun", true},
|
||||
{"Fri Jun 15 00:00 2012", "0 * * 1,15 * Sun", true},
|
||||
{"Wed Aug 1 00:00 2012", "0 * * 1,15 * Sun", true},
|
||||
|
||||
// However, if one has a star, then both need to match.
|
||||
{"Sun Jul 15 00:00 2012", "0 * * * * Mon", false},
|
||||
{"Sun Jul 15 00:00 2012", "0 * * */10 * Sun", false},
|
||||
{"Mon Jul 9 00:00 2012", "0 * * 1,15 * *", false},
|
||||
{"Sun Jul 15 00:00 2012", "0 * * 1,15 * *", true},
|
||||
{"Sun Jul 15 00:00 2012", "0 * * */2 * Sun", true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
sched, err := Parse(test.spec)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
actual := sched.Next(getTime(test.time).Add(-1 * time.Second))
|
||||
expected := getTime(test.time)
|
||||
if test.expected && expected != actual || !test.expected && expected == actual {
|
||||
t.Errorf("Fail evaluating %s on %s: (expected) %s != %s (actual)",
|
||||
test.spec, test.time, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNext(t *testing.T) {
|
||||
runs := []struct {
|
||||
time, spec string
|
||||
expected string
|
||||
}{
|
||||
// Simple cases
|
||||
{"Mon Jul 9 14:45 2012", "0 0/15 * * *", "Mon Jul 9 15:00 2012"},
|
||||
{"Mon Jul 9 14:59 2012", "0 0/15 * * *", "Mon Jul 9 15:00 2012"},
|
||||
{"Mon Jul 9 14:59:59 2012", "0 0/15 * * *", "Mon Jul 9 15:00 2012"},
|
||||
|
||||
// Wrap around hours
|
||||
{"Mon Jul 9 15:45 2012", "0 20-35/15 * * *", "Mon Jul 9 16:20 2012"},
|
||||
|
||||
// Wrap around days
|
||||
{"Mon Jul 9 23:46 2012", "0 */15 * * *", "Tue Jul 10 00:00 2012"},
|
||||
{"Mon Jul 9 23:45 2012", "0 20-35/15 * * *", "Tue Jul 10 00:20 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * * *", "Tue Jul 10 00:20:15 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 1/2 * *", "Tue Jul 10 01:20:15 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 10-12 * *", "Tue Jul 10 10:20:15 2012"},
|
||||
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 1/2 */2 * *", "Thu Jul 11 01:20:15 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * 9-20 * *", "Wed Jul 10 00:20:15 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * 9-20 Jul *", "Wed Jul 10 00:20:15 2012"},
|
||||
|
||||
// Wrap around months
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 9 Apr-Oct ?", "Thu Aug 9 00:00 2012"},
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 */5 Apr,Aug,Oct Mon", "Mon Aug 6 00:00 2012"},
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 */5 Oct Mon", "Mon Oct 1 00:00 2012"},
|
||||
|
||||
// Wrap around years
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 * Feb Mon", "Mon Feb 4 00:00 2013"},
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 * Feb Mon/2", "Fri Feb 1 00:00 2013"},
|
||||
|
||||
// Wrap around minute, hour, day, month, and year
|
||||
{"Mon Dec 31 23:59:45 2012", "0 * * * * *", "Tue Jan 1 00:00:00 2013"},
|
||||
|
||||
// Leap year
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 29 Feb ?", "Mon Feb 29 00:00 2016"},
|
||||
|
||||
// Daylight savings time EST -> EDT
|
||||
{"2012-03-11T00:00:00-0500", "0 30 2 11 Mar ?", "2013-03-11T02:30:00-0400"},
|
||||
|
||||
// Daylight savings time EDT -> EST
|
||||
{"2012-11-04T00:00:00-0400", "0 30 2 04 Nov ?", "2012-11-04T02:30:00-0500"},
|
||||
{"2012-11-04T01:45:00-0400", "0 30 1 04 Nov ?", "2012-11-04T01:30:00-0500"},
|
||||
|
||||
// Unsatisfiable
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 30 Feb ?", ""},
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 31 Apr ?", ""},
|
||||
}
|
||||
|
||||
for _, c := range runs {
|
||||
sched, err := Parse(c.spec)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
actual := sched.Next(getTime(c.time))
|
||||
expected := getTime(c.expected)
|
||||
if !actual.Equal(expected) {
|
||||
t.Errorf("%s, \"%s\": (expected) %v != %v (actual)", c.time, c.spec, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrors(t *testing.T) {
|
||||
invalidSpecs := []string{
|
||||
"xyz",
|
||||
"60 0 * * *",
|
||||
"0 60 * * *",
|
||||
"0 0 * * XYZ",
|
||||
}
|
||||
for _, spec := range invalidSpecs {
|
||||
_, err := Parse(spec)
|
||||
if err == nil {
|
||||
t.Error("expected an error parsing: ", spec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getTime(value string) time.Time {
|
||||
if value == "" {
|
||||
return time.Time{}
|
||||
}
|
||||
t, err := time.Parse("Mon Jan 2 15:04 2006", value)
|
||||
if err != nil {
|
||||
t, err = time.Parse("Mon Jan 2 15:04:05 2006", value)
|
||||
if err != nil {
|
||||
t, err = time.Parse("2006-01-02T15:04:05-0700", value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Daylight savings time tests require location
|
||||
if ny, err := time.LoadLocation("America/New_York"); err == nil {
|
||||
t = t.In(ny)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
// Copyright 2013 The Beego Authors. All rights reserved.
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package httplib
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestResponse(t *testing.T) {
|
||||
req := Get("http://httpbin.org/get")
|
||||
resp, err := req.Response()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(resp)
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
req := Get("http://httpbin.org/get")
|
||||
b, err := req.Bytes()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(b)
|
||||
|
||||
s, err := req.String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(s)
|
||||
|
||||
if string(b) != s {
|
||||
t.Fatal("request data not match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimplePost(t *testing.T) {
|
||||
v := "smallfish"
|
||||
req := Post("http://httpbin.org/post")
|
||||
req.Param("username", v)
|
||||
|
||||
str, err := req.String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(str, v)
|
||||
if n == -1 {
|
||||
t.Fatal(v + " not found in post")
|
||||
}
|
||||
}
|
||||
|
||||
// func TestPostFile(t *testing.T) {
|
||||
// v := "smallfish"
|
||||
// req := Post("http://httpbin.org/post")
|
||||
// req.Param("username", v)
|
||||
// req.PostFile("uploadfile", "httplib_test.go")
|
||||
|
||||
// str, err := req.String()
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// t.Log(str)
|
||||
|
||||
// n := strings.Index(str, v)
|
||||
// if n == -1 {
|
||||
// t.Fatal(v + " not found in post")
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestSimplePut(t *testing.T) {
|
||||
str, err := Put("http://httpbin.org/put").String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
}
|
||||
|
||||
func TestSimpleDelete(t *testing.T) {
|
||||
str, err := Delete("http://httpbin.org/delete").String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
}
|
||||
|
||||
func TestWithCookie(t *testing.T) {
|
||||
v := "smallfish"
|
||||
str, err := Get("http://httpbin.org/cookies/set?k1=" + v).SetEnableCookie(true).String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
str, err = Get("http://httpbin.org/cookies").SetEnableCookie(true).String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(str, v)
|
||||
if n == -1 {
|
||||
t.Fatal(v + " not found in cookie")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithBasicAuth(t *testing.T) {
|
||||
str, err := Get("http://httpbin.org/basic-auth/user/passwd").SetBasicAuth("user", "passwd").String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
n := strings.Index(str, "authenticated")
|
||||
if n == -1 {
|
||||
t.Fatal("authenticated not found in response")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithUserAgent(t *testing.T) {
|
||||
v := "beego"
|
||||
str, err := Get("http://httpbin.org/headers").SetUserAgent(v).String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(str, v)
|
||||
if n == -1 {
|
||||
t.Fatal(v + " not found in user-agent")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithSetting(t *testing.T) {
|
||||
v := "beego"
|
||||
var setting BeegoHttpSettings
|
||||
setting.EnableCookie = true
|
||||
setting.UserAgent = v
|
||||
setting.Transport = nil
|
||||
SetDefaultSetting(setting)
|
||||
|
||||
str, err := Get("http://httpbin.org/get").String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(str, v)
|
||||
if n == -1 {
|
||||
t.Fatal(v + " not found in user-agent")
|
||||
}
|
||||
}
|
||||
|
||||
func TestToJson(t *testing.T) {
|
||||
req := Get("http://httpbin.org/ip")
|
||||
resp, err := req.Response()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(resp)
|
||||
|
||||
// httpbin will return http remote addr
|
||||
type Ip struct {
|
||||
Origin string `json:"origin"`
|
||||
}
|
||||
var ip Ip
|
||||
err = req.ToJson(&ip)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(ip.Origin)
|
||||
|
||||
if n := strings.Count(ip.Origin, "."); n != 3 {
|
||||
t.Fatal("response is not valid ip")
|
||||
}
|
||||
}
|
||||
|
||||
func TestToFile(t *testing.T) {
|
||||
f := "beego_testfile"
|
||||
req := Get("http://httpbin.org/ip")
|
||||
err := req.ToFile(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(f)
|
||||
b, err := ioutil.ReadFile(f)
|
||||
if n := strings.Index(string(b), "origin"); n == -1 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeader(t *testing.T) {
|
||||
req := Get("http://httpbin.org/headers")
|
||||
req.Header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36")
|
||||
str, err := req.String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
}
|
||||
@@ -37,6 +37,7 @@ func NewLogger(bufLen int64, mode, config string) {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: use same log level as other loggers.
|
||||
func NewGitLogger(logPath string) {
|
||||
os.MkdirAll(path.Dir(logPath), os.ModePerm)
|
||||
GitLogger = newLogger(0)
|
||||
|
||||
@@ -7,12 +7,14 @@ package mailer
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"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/markdown"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
@@ -125,7 +127,7 @@ func SendIssueNotifyMail(u, owner *models.User, repo *models.Repository, issue *
|
||||
|
||||
subject := fmt.Sprintf("[%s] %s (#%d)", repo.Name, issue.Name, issue.Index)
|
||||
content := fmt.Sprintf("%s<br>-<br> <a href=\"%s%s/%s/issues/%d\">View it on Gogs</a>.",
|
||||
base.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name, repo.ComposeMetas()),
|
||||
markdown.RenderSpecialLink([]byte(strings.Replace(issue.Content, "\n", "<br>", -1)), owner.Name+"/"+repo.Name, repo.ComposeMetas()),
|
||||
setting.AppUrl, owner.Name, repo.Name, issue.Index)
|
||||
msg := NewMessage(tos, subject, content)
|
||||
msg.Info = fmt.Sprintf("Subject: %s, issue notify", subject)
|
||||
@@ -148,7 +150,7 @@ func SendIssueMentionMail(r macaron.Render, u, owner *models.User,
|
||||
data["IssueLink"] = fmt.Sprintf("%s/%s/issues/%d", owner.Name, repo.Name, issue.Index)
|
||||
data["Subject"] = subject
|
||||
data["ActUserName"] = u.DisplayName()
|
||||
data["Content"] = string(base.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name, repo.ComposeMetas()))
|
||||
data["Content"] = string(markdown.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name, repo.ComposeMetas()))
|
||||
|
||||
body, err := r.HTMLString(string(NOTIFY_MENTION), data)
|
||||
if err != nil {
|
||||
|
||||
@@ -111,7 +111,7 @@ func (s *Sender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
|
||||
client, err := smtp.NewClient(conn, host)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("NewClient: %v", err)
|
||||
}
|
||||
|
||||
if !setting.MailService.DisableHelo {
|
||||
@@ -124,7 +124,7 @@ func (s *Sender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
}
|
||||
|
||||
if err = client.Hello(hostname); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Hello: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ func (s *Sender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
hasStartTLS, _ := client.Extension("STARTTLS")
|
||||
if !isSecureConn && hasStartTLS {
|
||||
if err = client.StartTLS(tlsconfig); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("StartTLS: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,28 +151,28 @@ func (s *Sender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
|
||||
if auth != nil {
|
||||
if err = client.Auth(auth); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Auth: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = client.Mail(from); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Mail: %v", err)
|
||||
}
|
||||
|
||||
for _, rec := range to {
|
||||
if err = client.Rcpt(rec); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Rcpt: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
w, err := client.Data()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Data: %v", err)
|
||||
} else if _, err = msg.WriteTo(w); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("WriteTo: %v", err)
|
||||
} else if err = w.Close(); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Close: %v", err)
|
||||
}
|
||||
|
||||
return client.Quit()
|
||||
@@ -197,7 +197,10 @@ func processMailQueue() {
|
||||
var mailQueue chan *Message
|
||||
|
||||
func NewContext() {
|
||||
if setting.MailService == nil {
|
||||
// Need to check if mailQueue is nil because in during reinstall (user had installed
|
||||
// before but swithed install lock off), this function will be called again
|
||||
// while mail queue is already processing tasks, and produces a race condition.
|
||||
if setting.MailService == nil || mailQueue != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
369
modules/markdown/markdown.go
Normal file
369
modules/markdown/markdown.go
Normal file
@@ -0,0 +1,369 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package markdown
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
"github.com/russross/blackfriday"
|
||||
"golang.org/x/net/html"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
var Sanitizer = bluemonday.UGCPolicy()
|
||||
|
||||
// BuildSanitizer initializes sanitizer with allowed attributes based on settings.
|
||||
// This function should only be called once during entire application lifecycle.
|
||||
func BuildSanitizer() {
|
||||
// Normal markdown-stuff
|
||||
Sanitizer.AllowAttrs("class").Matching(regexp.MustCompile(`[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&]*`)).OnElements("code")
|
||||
|
||||
// Checkboxes
|
||||
Sanitizer.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")
|
||||
Sanitizer.AllowAttrs("checked", "disabled").OnElements("input")
|
||||
|
||||
// Custom URL-Schemes
|
||||
Sanitizer.AllowURLSchemes(setting.Markdown.CustomURLSchemes...)
|
||||
}
|
||||
|
||||
var validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`)
|
||||
|
||||
// isLink reports whether link fits valid format.
|
||||
func isLink(link []byte) bool {
|
||||
return validLinksPattern.Match(link)
|
||||
}
|
||||
|
||||
// IsMarkdownFile reports whether name looks like a Markdown file
|
||||
// based on its extension.
|
||||
func IsMarkdownFile(name string) bool {
|
||||
name = strings.ToLower(name)
|
||||
switch filepath.Ext(name) {
|
||||
case ".md", ".markdown", ".mdown", ".mkd":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsReadmeFile reports whether name looks like a README file
|
||||
// based on its extension.
|
||||
func IsReadmeFile(name string) bool {
|
||||
name = strings.ToLower(name)
|
||||
if len(name) < 6 {
|
||||
return false
|
||||
} else if len(name) == 6 {
|
||||
return name == "readme"
|
||||
}
|
||||
return name[:7] == "readme."
|
||||
}
|
||||
|
||||
var (
|
||||
// MentionPattern matches string that mentions someone, e.g. @Unknwon
|
||||
MentionPattern = regexp.MustCompile(`(\s|^)@[0-9a-zA-Z_\.]+`)
|
||||
|
||||
// CommitPattern matches link to certain commit with or without trailing hash,
|
||||
// e.g. https://try.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2
|
||||
CommitPattern = regexp.MustCompile(`(\s|^)https?.*commit/[0-9a-zA-Z]+(#+[0-9a-zA-Z-]*)?`)
|
||||
|
||||
// IssueFullPattern matches link to an issue with or without trailing hash,
|
||||
// e.g. https://try.gogs.io/gogs/gogs/issues/4#issue-685
|
||||
IssueFullPattern = regexp.MustCompile(`(\s|^)https?.*issues/[0-9]+(#+[0-9a-zA-Z-]*)?`)
|
||||
// IssueIndexPattern matches string that references to an issue, e.g. #1287
|
||||
IssueIndexPattern = regexp.MustCompile(`( |^|\()#[0-9]+\b`)
|
||||
|
||||
// Sha1CurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae
|
||||
Sha1CurrentPattern = regexp.MustCompile(`\b[0-9a-f]{40}\b`)
|
||||
)
|
||||
|
||||
// Renderer is a extended version of underlying render object.
|
||||
type Renderer struct {
|
||||
blackfriday.Renderer
|
||||
urlPrefix string
|
||||
}
|
||||
|
||||
// Link defines how formal links should be processed to produce corresponding HTML elements.
|
||||
func (r *Renderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
|
||||
if len(link) > 0 && !isLink(link) {
|
||||
if link[0] != '#' {
|
||||
link = []byte(path.Join(r.urlPrefix, string(link)))
|
||||
}
|
||||
}
|
||||
|
||||
r.Renderer.Link(out, link, title, content)
|
||||
}
|
||||
|
||||
// AutoLink defines how auto-detected links should be processed to produce corresponding HTML elements.
|
||||
// Reference for kind: https://github.com/russross/blackfriday/blob/master/markdown.go#L69-L76
|
||||
func (r *Renderer) AutoLink(out *bytes.Buffer, link []byte, kind int) {
|
||||
if kind != blackfriday.LINK_TYPE_NORMAL {
|
||||
r.Renderer.AutoLink(out, link, kind)
|
||||
return
|
||||
}
|
||||
|
||||
// Since this method could only possibly serve one link at a time,
|
||||
// we do not need to find all.
|
||||
m := CommitPattern.Find(link)
|
||||
if m != nil {
|
||||
m = bytes.TrimSpace(m)
|
||||
i := strings.Index(string(m), "commit/")
|
||||
j := strings.Index(string(m), "#")
|
||||
if j == -1 {
|
||||
j = len(m)
|
||||
}
|
||||
out.WriteString(fmt.Sprintf(` <code><a href="%s">%s</a></code>`, m, base.ShortSha(string(m[i+7:j]))))
|
||||
return
|
||||
}
|
||||
|
||||
m = IssueFullPattern.Find(link)
|
||||
if m != nil {
|
||||
m = bytes.TrimSpace(m)
|
||||
i := strings.Index(string(m), "issues/")
|
||||
j := strings.Index(string(m), "#")
|
||||
if j == -1 {
|
||||
j = len(m)
|
||||
}
|
||||
out.WriteString(fmt.Sprintf(` <a href="%s">#%s</a>`, m, base.ShortSha(string(m[i+7:j]))))
|
||||
return
|
||||
}
|
||||
|
||||
r.Renderer.AutoLink(out, link, kind)
|
||||
}
|
||||
|
||||
// ListItem defines how list items should be processed to produce corresponding HTML elements.
|
||||
func (options *Renderer) ListItem(out *bytes.Buffer, text []byte, flags int) {
|
||||
// Detect procedures to draw checkboxes.
|
||||
switch {
|
||||
case bytes.HasPrefix(text, []byte("[ ] ")):
|
||||
text = append([]byte(`<input type="checkbox" disabled="" />`), text[3:]...)
|
||||
case bytes.HasPrefix(text, []byte("[x] ")):
|
||||
text = append([]byte(`<input type="checkbox" disabled="" checked="" />`), text[3:]...)
|
||||
}
|
||||
options.Renderer.ListItem(out, text, flags)
|
||||
}
|
||||
|
||||
// Note: this section is for purpose of increase performance and
|
||||
// reduce memory allocation at runtime since they are constant literals.
|
||||
var (
|
||||
svgSuffix = []byte(".svg")
|
||||
svgSuffixWithMark = []byte(".svg?")
|
||||
spaceBytes = []byte(" ")
|
||||
spaceEncodedBytes = []byte("%20")
|
||||
)
|
||||
|
||||
// Image defines how images should be processed to produce corresponding HTML elements.
|
||||
func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
||||
prefix := strings.Replace(r.urlPrefix, "/src/", "/raw/", 1)
|
||||
if len(link) > 0 {
|
||||
if isLink(link) {
|
||||
// External link with .svg suffix usually means CI status.
|
||||
// TODO: define a keyword to allow non-svg images render as external link.
|
||||
if bytes.HasSuffix(link, svgSuffix) || bytes.Contains(link, svgSuffixWithMark) {
|
||||
r.Renderer.Image(out, link, title, alt)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if link[0] != '/' {
|
||||
prefix += "/"
|
||||
}
|
||||
link = bytes.Replace([]byte((prefix + string(link))), spaceBytes, spaceEncodedBytes, -1)
|
||||
fmt.Println(333, string(link))
|
||||
}
|
||||
}
|
||||
|
||||
out.WriteString(`<a href="`)
|
||||
out.Write(link)
|
||||
out.WriteString(`">`)
|
||||
r.Renderer.Image(out, link, title, alt)
|
||||
out.WriteString("</a>")
|
||||
}
|
||||
|
||||
// cutoutVerbosePrefix cutouts URL prefix including sub-path to
|
||||
// return a clean unified string of request URL path.
|
||||
func cutoutVerbosePrefix(prefix string) string {
|
||||
count := 0
|
||||
for i := 0; i < len(prefix); i++ {
|
||||
if prefix[i] == '/' {
|
||||
count++
|
||||
}
|
||||
if count >= 3+setting.AppSubUrlDepth {
|
||||
return prefix[:i]
|
||||
}
|
||||
}
|
||||
return prefix
|
||||
}
|
||||
|
||||
// RenderIssueIndexPattern renders issue indexes to corresponding links.
|
||||
func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
|
||||
urlPrefix = cutoutVerbosePrefix(urlPrefix)
|
||||
ms := IssueIndexPattern.FindAll(rawBytes, -1)
|
||||
for _, m := range ms {
|
||||
var space string
|
||||
if m[0] != '#' {
|
||||
space = string(m[0])
|
||||
m = m[1:]
|
||||
}
|
||||
if metas == nil {
|
||||
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s/issues/%s">%s</a>`,
|
||||
space, urlPrefix, m[1:], m)), 1)
|
||||
} else {
|
||||
// Support for external issue tracker
|
||||
metas["index"] = string(m[1:])
|
||||
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s">%s</a>`,
|
||||
space, com.Expand(metas["format"], metas), m)), 1)
|
||||
}
|
||||
}
|
||||
return rawBytes
|
||||
}
|
||||
|
||||
// RenderSha1CurrentPattern renders SHA1 strings to corresponding links that assumes in the same repository.
|
||||
func RenderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte {
|
||||
ms := Sha1CurrentPattern.FindAll(rawBytes, -1)
|
||||
for _, m := range ms {
|
||||
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
|
||||
`<a href="%s/commit/%s"><code>%s</code></a>`, urlPrefix, m, base.ShortSha(string(m)))), -1)
|
||||
}
|
||||
return rawBytes
|
||||
}
|
||||
|
||||
// RenderSpecialLink renders mentions, indexes and SHA1 strings to corresponding links.
|
||||
func RenderSpecialLink(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
|
||||
ms := MentionPattern.FindAll(rawBytes, -1)
|
||||
for _, m := range ms {
|
||||
m = bytes.TrimSpace(m)
|
||||
rawBytes = bytes.Replace(rawBytes, m,
|
||||
[]byte(fmt.Sprintf(`<a href="%s/%s">%s</a>`, setting.AppSubUrl, m[1:], m)), -1)
|
||||
}
|
||||
|
||||
rawBytes = RenderIssueIndexPattern(rawBytes, urlPrefix, metas)
|
||||
rawBytes = RenderSha1CurrentPattern(rawBytes, urlPrefix)
|
||||
return rawBytes
|
||||
}
|
||||
|
||||
// RenderRaw renders Markdown to HTML without handling special links.
|
||||
func RenderRaw(body []byte, urlPrefix string) []byte {
|
||||
htmlFlags := 0
|
||||
htmlFlags |= blackfriday.HTML_SKIP_STYLE
|
||||
htmlFlags |= blackfriday.HTML_OMIT_CONTENTS
|
||||
renderer := &Renderer{
|
||||
Renderer: blackfriday.HtmlRenderer(htmlFlags, "", ""),
|
||||
urlPrefix: urlPrefix,
|
||||
}
|
||||
|
||||
// set up the parser
|
||||
extensions := 0
|
||||
extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
|
||||
extensions |= blackfriday.EXTENSION_TABLES
|
||||
extensions |= blackfriday.EXTENSION_FENCED_CODE
|
||||
extensions |= blackfriday.EXTENSION_AUTOLINK
|
||||
extensions |= blackfriday.EXTENSION_STRIKETHROUGH
|
||||
extensions |= blackfriday.EXTENSION_SPACE_HEADERS
|
||||
extensions |= blackfriday.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK
|
||||
|
||||
if setting.Markdown.EnableHardLineBreak {
|
||||
extensions |= blackfriday.EXTENSION_HARD_LINE_BREAK
|
||||
}
|
||||
|
||||
body = blackfriday.Markdown(body, renderer, extensions)
|
||||
return body
|
||||
}
|
||||
|
||||
var (
|
||||
leftAngleBracket = []byte("</")
|
||||
rightAngleBracket = []byte(">")
|
||||
)
|
||||
|
||||
var noEndTags = []string{"img", "input", "br", "hr"}
|
||||
|
||||
// PostProcess treats different types of HTML differently,
|
||||
// and only renders special links for plain text blocks.
|
||||
func PostProcess(rawHtml []byte, urlPrefix string, metas map[string]string) []byte {
|
||||
startTags := make([]string, 0, 5)
|
||||
var buf bytes.Buffer
|
||||
tokenizer := html.NewTokenizer(bytes.NewReader(rawHtml))
|
||||
|
||||
OUTER_LOOP:
|
||||
for html.ErrorToken != tokenizer.Next() {
|
||||
token := tokenizer.Token()
|
||||
switch token.Type {
|
||||
case html.TextToken:
|
||||
buf.Write(RenderSpecialLink([]byte(token.String()), urlPrefix, metas))
|
||||
|
||||
case html.StartTagToken:
|
||||
buf.WriteString(token.String())
|
||||
tagName := token.Data
|
||||
// If this is an excluded tag, we skip processing all output until a close tag is encountered.
|
||||
if strings.EqualFold("a", tagName) || strings.EqualFold("code", tagName) || strings.EqualFold("pre", tagName) {
|
||||
stackNum := 1
|
||||
for html.ErrorToken != tokenizer.Next() {
|
||||
token = tokenizer.Token()
|
||||
|
||||
// Copy the token to the output verbatim
|
||||
buf.WriteString(token.String())
|
||||
|
||||
if token.Type == html.StartTagToken {
|
||||
stackNum++
|
||||
}
|
||||
|
||||
// If this is the close tag to the outer-most, we are done
|
||||
if token.Type == html.EndTagToken {
|
||||
stackNum--
|
||||
|
||||
if stackNum <= 0 && strings.EqualFold(tagName, token.Data) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
continue OUTER_LOOP
|
||||
}
|
||||
|
||||
if !com.IsSliceContainsStr(noEndTags, token.Data) {
|
||||
startTags = append(startTags, token.Data)
|
||||
}
|
||||
|
||||
case html.EndTagToken:
|
||||
if len(startTags) == 0 {
|
||||
buf.WriteString(token.String())
|
||||
break
|
||||
}
|
||||
|
||||
buf.Write(leftAngleBracket)
|
||||
buf.WriteString(startTags[len(startTags)-1])
|
||||
buf.Write(rightAngleBracket)
|
||||
startTags = startTags[:len(startTags)-1]
|
||||
default:
|
||||
buf.WriteString(token.String())
|
||||
}
|
||||
}
|
||||
|
||||
if io.EOF == tokenizer.Err() {
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// If we are not at the end of the input, then some other parsing error has occurred,
|
||||
// so return the input verbatim.
|
||||
return rawHtml
|
||||
}
|
||||
|
||||
// Render renders Markdown to HTML with special links.
|
||||
func Render(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
|
||||
result := RenderRaw(rawBytes, urlPrefix)
|
||||
result = PostProcess(result, urlPrefix, metas)
|
||||
result = Sanitizer.SanitizeBytes(result)
|
||||
return result
|
||||
}
|
||||
|
||||
// RenderString renders Markdown to HTML with special links and returns string type.
|
||||
func RenderString(raw, urlPrefix string, metas map[string]string) string {
|
||||
return string(Render([]byte(raw), urlPrefix, metas))
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"github.com/go-macaron/session"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"github.com/gogits/git-shell"
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
@@ -65,7 +65,8 @@ type Context struct {
|
||||
Org struct {
|
||||
IsOwner bool
|
||||
IsMember bool
|
||||
IsAdminTeam bool // In owner team or team that has admin permission level.
|
||||
IsTeamMember bool // Is member of team.
|
||||
IsTeamAdmin bool // In owner team or team that has admin permission level.
|
||||
Organization *models.User
|
||||
OrgLink string
|
||||
|
||||
@@ -125,6 +126,7 @@ func (ctx *Context) HasValue(name string) bool {
|
||||
|
||||
// HTML calls Context.HTML and converts template name to string.
|
||||
func (ctx *Context) HTML(status int, name base.TplName) {
|
||||
log.Debug("Template: %s", name)
|
||||
ctx.Context.HTML(status, string(name))
|
||||
}
|
||||
|
||||
@@ -241,6 +243,8 @@ func Contexter() macaron.Handler {
|
||||
|
||||
ctx.Data["CsrfToken"] = x.GetToken()
|
||||
ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + x.GetToken() + `">`)
|
||||
log.Debug("Session ID: %s", sess.ID())
|
||||
log.Debug("CSRF Token: %v", ctx.Data["CsrfToken"])
|
||||
|
||||
ctx.Data["ShowRegistrationButton"] = setting.Service.ShowRegistrationButton
|
||||
ctx.Data["ShowFooterBranding"] = setting.ShowFooterBranding
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
@@ -13,9 +15,10 @@ import (
|
||||
|
||||
func HandleOrgAssignment(ctx *Context, args ...bool) {
|
||||
var (
|
||||
requireMember bool
|
||||
requireOwner bool
|
||||
requireAdminTeam bool
|
||||
requireMember bool
|
||||
requireOwner bool
|
||||
requireTeamMember bool
|
||||
requireTeamAdmin bool
|
||||
)
|
||||
if len(args) >= 1 {
|
||||
requireMember = args[0]
|
||||
@@ -24,7 +27,10 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
|
||||
requireOwner = args[1]
|
||||
}
|
||||
if len(args) >= 3 {
|
||||
requireAdminTeam = args[2]
|
||||
requireTeamMember = args[2]
|
||||
}
|
||||
if len(args) >= 4 {
|
||||
requireTeamAdmin = args[3]
|
||||
}
|
||||
|
||||
orgName := ctx.Params(":org")
|
||||
@@ -52,12 +58,14 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
|
||||
if ctx.IsSigned && ctx.User.IsAdmin {
|
||||
ctx.Org.IsOwner = true
|
||||
ctx.Org.IsMember = true
|
||||
ctx.Org.IsAdminTeam = true
|
||||
ctx.Org.IsTeamMember = true
|
||||
ctx.Org.IsTeamAdmin = true
|
||||
} else if ctx.IsSigned {
|
||||
ctx.Org.IsOwner = org.IsOwnedBy(ctx.User.Id)
|
||||
if ctx.Org.IsOwner {
|
||||
ctx.Org.IsMember = true
|
||||
ctx.Org.IsAdminTeam = true
|
||||
ctx.Org.IsTeamMember = true
|
||||
ctx.Org.IsTeamAdmin = true
|
||||
} else {
|
||||
if org.IsOrgMember(ctx.User.Id) {
|
||||
ctx.Org.IsMember = true
|
||||
@@ -79,24 +87,50 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
|
||||
ctx.Data["OrgLink"] = ctx.Org.OrgLink
|
||||
|
||||
// Team.
|
||||
if ctx.Org.IsMember {
|
||||
if ctx.Org.IsOwner {
|
||||
if err := org.GetTeams(); err != nil {
|
||||
ctx.Handle(500, "GetUserTeams", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if err := org.GetUserTeams(ctx.User.Id); err != nil {
|
||||
ctx.Handle(500, "GetUserTeams", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
teamName := ctx.Params(":team")
|
||||
if len(teamName) > 0 {
|
||||
ctx.Org.Team, err = org.GetTeam(teamName)
|
||||
if err != nil {
|
||||
if err == models.ErrTeamNotExist {
|
||||
ctx.Handle(404, "GetTeam", err)
|
||||
} else {
|
||||
ctx.Handle(500, "GetTeam", err)
|
||||
teamExists := false
|
||||
for _, team := range org.Teams {
|
||||
if team.LowerName == strings.ToLower(teamName) {
|
||||
teamExists = true
|
||||
ctx.Org.Team = team
|
||||
ctx.Org.IsTeamMember = true
|
||||
ctx.Data["Team"] = ctx.Org.Team
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !teamExists {
|
||||
ctx.Handle(404, "OrgAssignment", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsTeamMember"] = ctx.Org.IsTeamMember
|
||||
if requireTeamMember && !ctx.Org.IsTeamMember {
|
||||
ctx.Handle(404, "OrgAssignment", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Org.IsTeamAdmin = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.Authorize >= models.ACCESS_MODE_ADMIN
|
||||
ctx.Data["IsTeamAdmin"] = ctx.Org.IsTeamAdmin
|
||||
if requireTeamAdmin && !ctx.Org.IsTeamAdmin {
|
||||
ctx.Handle(404, "OrgAssignment", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Team"] = ctx.Org.Team
|
||||
ctx.Org.IsAdminTeam = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.Authorize >= models.ACCESS_MODE_ADMIN
|
||||
}
|
||||
ctx.Data["IsAdminTeam"] = ctx.Org.IsAdminTeam
|
||||
if requireAdminTeam && !ctx.Org.IsAdminTeam {
|
||||
ctx.Handle(404, "OrgAssignment", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"github.com/gogits/git-shell"
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
@@ -167,7 +167,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
|
||||
ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
|
||||
ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
|
||||
ctx.Data["IsRepositoryPusher"] = ctx.Repo.IsPusher()
|
||||
ctx.Data["CanPullRequest"] = ctx.Repo.IsAdmin() && repo.BaseRepo != nil && repo.BaseRepo.EnablePulls
|
||||
ctx.Data["CanPullRequest"] = ctx.Repo.IsAdmin() && repo.BaseRepo != nil && repo.BaseRepo.AllowsPulls()
|
||||
|
||||
ctx.Data["DisableSSH"] = setting.DisableSSH
|
||||
ctx.Data["CloneLink"] = repo.CloneLink()
|
||||
@@ -216,7 +216,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
|
||||
|
||||
if ctx.Query("go-get") == "1" {
|
||||
ctx.Data["GoGetImport"] = path.Join(setting.Domain, setting.AppSubUrl, owner.Name, repo.Name)
|
||||
prefix := path.Join(setting.AppUrl, owner.Name, repo.Name, "src", ctx.Repo.BranchName)
|
||||
prefix := setting.AppUrl + path.Join(owner.Name, repo.Name, "src", ctx.Repo.BranchName)
|
||||
ctx.Data["GoDocDirectory"] = prefix + "{/dir}"
|
||||
ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}"
|
||||
}
|
||||
|
||||
15
modules/setting/miniwinsvc.go
Normal file
15
modules/setting/miniwinsvc.go
Normal file
@@ -0,0 +1,15 @@
|
||||
// +build miniwinsvc
|
||||
|
||||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package setting
|
||||
|
||||
import (
|
||||
_ "github.com/kardianos/minwinsvc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SupportMiniWinService = true
|
||||
}
|
||||
@@ -43,27 +43,29 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// Build information.
|
||||
// Build information
|
||||
BuildTime string
|
||||
BuildGitHash string
|
||||
|
||||
// App settings.
|
||||
AppVer string
|
||||
AppName string
|
||||
AppUrl string
|
||||
AppSubUrl string
|
||||
AppPath string
|
||||
AppDataPath = "data"
|
||||
// App settings
|
||||
AppVer string
|
||||
AppName string
|
||||
AppUrl string
|
||||
AppSubUrl string
|
||||
AppSubUrlDepth int // Number of slashes
|
||||
AppPath string
|
||||
AppDataPath = "data"
|
||||
|
||||
// Server settings.
|
||||
// Server settings
|
||||
Protocol Scheme
|
||||
Domain string
|
||||
HttpAddr, HttpPort string
|
||||
LocalUrl string
|
||||
LocalURL string
|
||||
DisableSSH bool
|
||||
StartSSHServer bool
|
||||
SSHDomain string
|
||||
SSHPort int
|
||||
SSHRootPath string
|
||||
OfflineMode bool
|
||||
DisableRouterLog bool
|
||||
CertFile, KeyFile string
|
||||
@@ -71,7 +73,7 @@ var (
|
||||
EnableGzip bool
|
||||
LandingPageUrl LandingPage
|
||||
|
||||
// Security settings.
|
||||
// Security settings
|
||||
InstallLock bool
|
||||
SecretKey string
|
||||
LogInRememberDays int
|
||||
@@ -79,13 +81,13 @@ var (
|
||||
CookieRememberName string
|
||||
ReverseProxyAuthUser string
|
||||
|
||||
// Database settings.
|
||||
// Database settings
|
||||
UseSQLite3 bool
|
||||
UseMySQL bool
|
||||
UsePostgreSQL bool
|
||||
UseTiDB bool
|
||||
|
||||
// Webhook settings.
|
||||
// Webhook settings
|
||||
Webhook struct {
|
||||
QueueLength int
|
||||
DeliverTimeout int
|
||||
@@ -94,7 +96,7 @@ var (
|
||||
PagingNum int
|
||||
}
|
||||
|
||||
// Repository settings.
|
||||
// Repository settings
|
||||
Repository struct {
|
||||
AnsiCharset string
|
||||
ForcePrivate bool
|
||||
@@ -104,7 +106,7 @@ var (
|
||||
RepoRootPath string
|
||||
ScriptType string
|
||||
|
||||
// UI settings.
|
||||
// UI settings
|
||||
ExplorePagingNum int
|
||||
IssuePagingNum int
|
||||
FeedMaxCommitNum int
|
||||
@@ -112,48 +114,50 @@ var (
|
||||
AdminRepoPagingNum int
|
||||
AdminNoticePagingNum int
|
||||
AdminOrgPagingNum int
|
||||
ThemeColorMetaTag string
|
||||
|
||||
// Markdown sttings.
|
||||
// Markdown sttings
|
||||
Markdown struct {
|
||||
EnableHardLineBreak bool
|
||||
CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
|
||||
}
|
||||
|
||||
// Picture settings.
|
||||
// Picture settings
|
||||
PictureService string
|
||||
AvatarUploadPath string
|
||||
GravatarSource string
|
||||
DisableGravatar bool
|
||||
|
||||
// Log settings.
|
||||
// Log settings
|
||||
LogRootPath string
|
||||
LogModes []string
|
||||
LogConfigs []string
|
||||
|
||||
// Attachment settings.
|
||||
// Attachment settings
|
||||
AttachmentPath string
|
||||
AttachmentAllowedTypes string
|
||||
AttachmentMaxSize int64
|
||||
AttachmentMaxFiles int
|
||||
AttachmentEnabled bool
|
||||
|
||||
// Time settings.
|
||||
// Time settings
|
||||
TimeFormat string
|
||||
|
||||
// Cache settings.
|
||||
// Cache settings
|
||||
CacheAdapter string
|
||||
CacheInternal int
|
||||
CacheConn string
|
||||
|
||||
// Session settings.
|
||||
// Session settings
|
||||
SessionConfig session.Options
|
||||
|
||||
// Git settings.
|
||||
// Git settings
|
||||
Git struct {
|
||||
MaxGitDiffLines int
|
||||
GcArgs []string `delim:" "`
|
||||
}
|
||||
|
||||
// Cron tasks.
|
||||
// Cron tasks
|
||||
Cron struct {
|
||||
UpdateMirror struct {
|
||||
Enabled bool
|
||||
@@ -174,17 +178,20 @@ var (
|
||||
} `ini:"cron.check_repo_stats"`
|
||||
}
|
||||
|
||||
// I18n settings.
|
||||
// I18n settings
|
||||
Langs, Names []string
|
||||
dateLangs map[string]string
|
||||
|
||||
// Other settings.
|
||||
ShowFooterBranding bool
|
||||
ShowFooterVersion bool
|
||||
// Highlight settings are loaded in modules/template/hightlight.go
|
||||
|
||||
// Global setting objects.
|
||||
// Other settings
|
||||
ShowFooterBranding bool
|
||||
ShowFooterVersion bool
|
||||
SupportMiniWinService bool
|
||||
|
||||
// Global setting objects
|
||||
Cfg *ini.File
|
||||
CustomPath string // Custom directory path.
|
||||
CustomPath string // Custom directory path
|
||||
CustomConf string
|
||||
ProdMode bool
|
||||
RunUser string
|
||||
@@ -270,10 +277,16 @@ func NewContext() {
|
||||
log.Fatal(4, "Fail to load custom conf '%s': %v", CustomConf, err)
|
||||
}
|
||||
} else {
|
||||
log.Warn("Custom config (%s) not found, ignore this if you're running first time", CustomConf)
|
||||
log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf)
|
||||
}
|
||||
Cfg.NameMapper = ini.AllCapsUnderscore
|
||||
|
||||
homeDir, err := com.HomeDir()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Fail to get home directory: %v", err)
|
||||
}
|
||||
homeDir = strings.Replace(homeDir, "\\", "/", -1)
|
||||
|
||||
LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(workDir, "log"))
|
||||
forcePathSeparator(LogRootPath)
|
||||
|
||||
@@ -287,9 +300,11 @@ func NewContext() {
|
||||
// Check if has app suburl.
|
||||
url, err := url.Parse(AppUrl)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Invalid ROOT_URL(%s): %s", AppUrl, err)
|
||||
log.Fatal(4, "Invalid ROOT_URL '%s': %s", AppUrl, err)
|
||||
}
|
||||
// Suburl should start with '/' and end without '/', such as '/{subpath}'.
|
||||
AppSubUrl = strings.TrimSuffix(url.Path, "/")
|
||||
AppSubUrlDepth = strings.Count(AppSubUrl, "/")
|
||||
|
||||
Protocol = HTTP
|
||||
if sec.Key("PROTOCOL").String() == "https" {
|
||||
@@ -302,13 +317,17 @@ func NewContext() {
|
||||
Domain = sec.Key("DOMAIN").MustString("localhost")
|
||||
HttpAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
|
||||
HttpPort = sec.Key("HTTP_PORT").MustString("3000")
|
||||
LocalUrl = sec.Key("LOCAL_ROOT_URL").MustString("http://localhost:" + HttpPort + "/")
|
||||
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString("http://localhost:" + HttpPort + "/")
|
||||
DisableSSH = sec.Key("DISABLE_SSH").MustBool()
|
||||
if !DisableSSH {
|
||||
StartSSHServer = sec.Key("START_SSH_SERVER").MustBool()
|
||||
}
|
||||
SSHDomain = sec.Key("SSH_DOMAIN").MustString(Domain)
|
||||
SSHPort = sec.Key("SSH_PORT").MustInt(22)
|
||||
SSHRootPath = sec.Key("SSH_ROOT_PATH").MustString(path.Join(homeDir, ".ssh"))
|
||||
if err := os.MkdirAll(SSHRootPath, 0700); err != nil {
|
||||
log.Fatal(4, "Fail to create '%s': %v", SSHRootPath, err)
|
||||
}
|
||||
OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
|
||||
DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
|
||||
StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir)
|
||||
@@ -365,12 +384,6 @@ func NewContext() {
|
||||
}
|
||||
|
||||
// Determine and create root git repository path.
|
||||
homeDir, err := com.HomeDir()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Fail to get home directory: %v", err)
|
||||
}
|
||||
homeDir = strings.Replace(homeDir, "\\", "/", -1)
|
||||
|
||||
sec = Cfg.Section("repository")
|
||||
RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gogs-repositories"))
|
||||
forcePathSeparator(RepoRootPath)
|
||||
@@ -395,6 +408,7 @@ func NewContext() {
|
||||
AdminRepoPagingNum = sec.Key("REPO_PAGING_NUM").MustInt(50)
|
||||
AdminNoticePagingNum = sec.Key("NOTICE_PAGING_NUM").MustInt(50)
|
||||
AdminOrgPagingNum = sec.Key("ORG_PAGING_NUM").MustInt(50)
|
||||
ThemeColorMetaTag = sec.Key("THEME_COLOR_META_TAG").MustString("#ff5343")
|
||||
|
||||
sec = Cfg.Section("picture")
|
||||
PictureService = sec.Key("SERVICE").In("server", []string{"server"})
|
||||
@@ -407,7 +421,7 @@ func NewContext() {
|
||||
case "duoshuo":
|
||||
GravatarSource = "http://gravatar.duoshuo.com/avatar/"
|
||||
case "gravatar":
|
||||
GravatarSource = "//1.gravatar.com/avatar/"
|
||||
GravatarSource = "https://secure.gravatar.com/avatar/"
|
||||
default:
|
||||
GravatarSource = source
|
||||
}
|
||||
@@ -420,7 +434,7 @@ func NewContext() {
|
||||
log.Fatal(4, "Fail to map Markdown settings: %v", err)
|
||||
} else if err = Cfg.Section("git").MapTo(&Git); err != nil {
|
||||
log.Fatal(4, "Fail to map Git settings: %v", err)
|
||||
} else if Cfg.Section("cron").MapTo(&Cron); err != nil {
|
||||
} else if err = Cfg.Section("cron").MapTo(&Cron); err != nil {
|
||||
log.Fatal(4, "Fail to map Cron settings: %v", err)
|
||||
}
|
||||
|
||||
@@ -441,12 +455,9 @@ var Service struct {
|
||||
DisableRegistration bool
|
||||
ShowRegistrationButton bool
|
||||
RequireSignInView bool
|
||||
EnableCacheAvatar bool
|
||||
EnableNotifyMail bool
|
||||
EnableReverseProxyAuth bool
|
||||
EnableReverseProxyAutoRegister bool
|
||||
DisableMinimumKeySizeCheck bool
|
||||
MinimumKeySizes map[string]int
|
||||
EnableCaptcha bool
|
||||
}
|
||||
|
||||
@@ -457,17 +468,9 @@ func newService() {
|
||||
Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
|
||||
Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!Service.DisableRegistration)
|
||||
Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
|
||||
Service.EnableCacheAvatar = sec.Key("ENABLE_CACHE_AVATAR").MustBool()
|
||||
Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
|
||||
Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
|
||||
Service.DisableMinimumKeySizeCheck = sec.Key("DISABLE_MINIMUM_KEY_SIZE_CHECK").MustBool()
|
||||
Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool()
|
||||
|
||||
minimumKeySizes := Cfg.Section("service.minimum_key_sizes").Keys()
|
||||
Service.MinimumKeySizes = make(map[string]int)
|
||||
for _, key := range minimumKeySizes {
|
||||
Service.MinimumKeySizes[key.Name()] = key.MustInt()
|
||||
}
|
||||
}
|
||||
|
||||
var logLevels = map[string]string{
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// +build go1.4
|
||||
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
@@ -53,7 +51,8 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
|
||||
case "env":
|
||||
args := strings.Split(strings.Replace(payload, "\x00", "", -1), "\v")
|
||||
if len(args) != 2 {
|
||||
return
|
||||
log.Warn("SSH: Invalid env arguments: '%#v'", args)
|
||||
continue
|
||||
}
|
||||
args[0] = strings.TrimLeft(args[0], "\x04")
|
||||
_, _, err := com.ExecCmdBytes("env", args[0]+"="+args[1])
|
||||
@@ -64,40 +63,41 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
|
||||
case "exec":
|
||||
cmdName := strings.TrimLeft(payload, "'()")
|
||||
os.Setenv("SSH_ORIGINAL_COMMAND", cmdName)
|
||||
log.Trace("Payload: %v", cmdName)
|
||||
log.Trace("SSH: Payload: %v", cmdName)
|
||||
|
||||
args := []string{"serv", "key-" + keyID, "--config=" + setting.CustomConf}
|
||||
log.Trace("Arguments: %v", args)
|
||||
log.Trace("SSH: Arguments: %v", args)
|
||||
cmd := exec.Command(setting.AppPath, args...)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
log.Error(3, "StdoutPipe: %v", err)
|
||||
log.Error(3, "SSH: StdoutPipe: %v", err)
|
||||
return
|
||||
}
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
log.Error(3, "StderrPipe: %v", err)
|
||||
log.Error(3, "SSH: StderrPipe: %v", err)
|
||||
return
|
||||
}
|
||||
input, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
log.Error(3, "StdinPipe: %v", err)
|
||||
log.Error(3, "SSH: StdinPipe: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// FIXME: check timeout
|
||||
if err = cmd.Start(); err != nil {
|
||||
log.Error(3, "Start: %v", err)
|
||||
log.Error(3, "SSH: Start: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
req.Reply(true, nil)
|
||||
go io.Copy(input, ch)
|
||||
io.Copy(ch, stdout)
|
||||
io.Copy(ch.Stderr(), stderr)
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
log.Error(3, "Wait: %v", err)
|
||||
log.Error(3, "SSH: Wait: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -119,20 +119,31 @@ func listen(config *ssh.ServerConfig, port int) {
|
||||
// Once a ServerConfig has been configured, connections can be accepted.
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
log.Error(3, "Error accepting incoming connection: %v", err)
|
||||
continue
|
||||
}
|
||||
// Before use, a handshake must be performed on the incoming net.Conn.
|
||||
sConn, chans, reqs, err := ssh.NewServerConn(conn, config)
|
||||
if err != nil {
|
||||
log.Error(3, "Error on handshaking: %v", err)
|
||||
log.Error(3, "SSH: Error accepting incoming connection: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Trace("Connection from %s (%s)", sConn.RemoteAddr(), sConn.ClientVersion())
|
||||
// The incoming Request channel must be serviced.
|
||||
go ssh.DiscardRequests(reqs)
|
||||
go handleServerConn(sConn.Permissions.Extensions["key-id"], chans)
|
||||
// Before use, a handshake must be performed on the incoming net.Conn.
|
||||
// It must be handled in a separate goroutine,
|
||||
// otherwise one user could easily block entire loop.
|
||||
// For example, user could be asked to trust server key fingerprint and hangs.
|
||||
go func() {
|
||||
log.Trace("SSH: Handshaking for %s", conn.RemoteAddr())
|
||||
sConn, chans, reqs, err := ssh.NewServerConn(conn, config)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
log.Warn("SSH: Handshaking was terminated: %v", err)
|
||||
} else {
|
||||
log.Error(3, "SSH: Error on handshaking: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("SSH: Connection from %s (%s)", sConn.RemoteAddr(), sConn.ClientVersion())
|
||||
// The incoming Request channel must be serviced.
|
||||
go ssh.DiscardRequests(reqs)
|
||||
go handleServerConn(sConn.Permissions.Extensions["key-id"], chans)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,16 +167,16 @@ func Listen(port int) {
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Fail to generate private key: %v - %s", err, stderr))
|
||||
}
|
||||
log.Trace("New private key is generateed: %s", keyPath)
|
||||
log.Trace("SSH: New private key is generateed: %s", keyPath)
|
||||
}
|
||||
|
||||
privateBytes, err := ioutil.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
panic("Fail to load private key")
|
||||
panic("SSH: Fail to load private key")
|
||||
}
|
||||
private, err := ssh.ParsePrivateKey(privateBytes)
|
||||
if err != nil {
|
||||
panic("Fail to parse private key")
|
||||
panic("SSH: Fail to parse private key")
|
||||
}
|
||||
config.AddHostKey(private)
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// +build !go1.4
|
||||
|
||||
package ssh
|
||||
|
||||
func Listen(port int) {
|
||||
panic("Gogs requires Go 1.4 for starting a SSH server")
|
||||
}
|
||||
97
modules/template/highlight/highlight.go
Normal file
97
modules/template/highlight/highlight.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// 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 highlight
|
||||
|
||||
import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
var (
|
||||
// File name should ignore highlight.
|
||||
ignoreFileNames = map[string]bool{
|
||||
"license": true,
|
||||
"copying": true,
|
||||
}
|
||||
|
||||
// File names that are representing highlight classes.
|
||||
highlightFileNames = map[string]bool{
|
||||
"dockerfile": true,
|
||||
"makefile": true,
|
||||
}
|
||||
|
||||
// Extensions that are same as highlight classes.
|
||||
highlightExts = map[string]bool{
|
||||
".arm": true,
|
||||
".as": true,
|
||||
".sh": true,
|
||||
".cs": true,
|
||||
".cpp": true,
|
||||
".c": true,
|
||||
".css": true,
|
||||
".cmake": true,
|
||||
".bat": true,
|
||||
".dart": true,
|
||||
".patch": true,
|
||||
".elixir": true,
|
||||
".erlang": true,
|
||||
".go": true,
|
||||
".html": true,
|
||||
".xml": true,
|
||||
".hs": true,
|
||||
".ini": true,
|
||||
".json": true,
|
||||
".java": true,
|
||||
".js": true,
|
||||
".less": true,
|
||||
".lua": true,
|
||||
".php": true,
|
||||
".py": true,
|
||||
".rb": true,
|
||||
".scss": true,
|
||||
".sql": true,
|
||||
".scala": true,
|
||||
".swift": true,
|
||||
".ts": true,
|
||||
".vb": true,
|
||||
}
|
||||
|
||||
// Extensions that are not same as highlight classes.
|
||||
highlightMapping = map[string]string{}
|
||||
)
|
||||
|
||||
func NewContext() {
|
||||
keys := setting.Cfg.Section("highlight.mapping").Keys()
|
||||
for i := range keys {
|
||||
highlightMapping[keys[i].Name()] = keys[i].Value()
|
||||
}
|
||||
}
|
||||
|
||||
// FileNameToHighlightClass returns the best match for highlight class name
|
||||
// based on the rule of highlight.js.
|
||||
func FileNameToHighlightClass(fname string) string {
|
||||
fname = strings.ToLower(fname)
|
||||
if ignoreFileNames[fname] {
|
||||
return "nohighlight"
|
||||
}
|
||||
|
||||
if highlightFileNames[fname] {
|
||||
return fname
|
||||
}
|
||||
|
||||
ext := path.Ext(fname)
|
||||
if highlightExts[ext] {
|
||||
return ext[1:]
|
||||
}
|
||||
|
||||
name, ok := highlightMapping[ext]
|
||||
if ok {
|
||||
return name
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/markdown"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
@@ -34,6 +35,9 @@ var Funcs template.FuncMap = map[string]interface{}{
|
||||
"AppSubUrl": func() string {
|
||||
return setting.AppSubUrl
|
||||
},
|
||||
"AppUrl": func() string {
|
||||
return setting.AppUrl
|
||||
},
|
||||
"AppVer": func() string {
|
||||
return setting.AppVer
|
||||
},
|
||||
@@ -95,6 +99,9 @@ var Funcs template.FuncMap = map[string]interface{}{
|
||||
return strings.Replace(strings.Replace(str, "%", "%25", -1), "#", "%23", -1)
|
||||
},
|
||||
"RenderCommitMessage": RenderCommitMessage,
|
||||
"ThemeColorMetaTag": func() string {
|
||||
return setting.ThemeColorMetaTag
|
||||
},
|
||||
}
|
||||
|
||||
func Safe(raw string) template.HTML {
|
||||
@@ -102,7 +109,7 @@ func Safe(raw string) template.HTML {
|
||||
}
|
||||
|
||||
func Str2html(raw string) template.HTML {
|
||||
return template.HTML(base.Sanitizer.Sanitize(raw))
|
||||
return template.HTML(markdown.Sanitizer.Sanitize(raw))
|
||||
}
|
||||
|
||||
func Range(l int) []int {
|
||||
@@ -130,21 +137,18 @@ func ToUtf8WithErr(content []byte) (error, string) {
|
||||
charsetLabel, err := base.DetectEncoding(content)
|
||||
if err != nil {
|
||||
return err, ""
|
||||
}
|
||||
|
||||
if charsetLabel == "UTF-8" {
|
||||
} else if charsetLabel == "UTF-8" {
|
||||
return nil, string(content)
|
||||
}
|
||||
|
||||
encoding, _ := charset.Lookup(charsetLabel)
|
||||
if encoding == nil {
|
||||
return fmt.Errorf("unknown char decoder %s", charsetLabel), string(content)
|
||||
return fmt.Errorf("Unknown encoding: %s", charsetLabel), string(content)
|
||||
}
|
||||
|
||||
result, n, err := transform.String(encoding.NewDecoder(), string(content))
|
||||
|
||||
// If there is an error, we concatenate the nicely decoded part and the
|
||||
// original left over. This way we won't loose data.
|
||||
result, n, err := transform.String(encoding.NewDecoder(), string(content))
|
||||
if err != nil {
|
||||
result = result + string(content[n:])
|
||||
}
|
||||
@@ -185,7 +189,7 @@ func ReplaceLeft(s, old, new string) string {
|
||||
// RenderCommitMessage renders commit message with XSS-safe and special links.
|
||||
func RenderCommitMessage(full bool, msg, urlPrefix string, metas map[string]string) template.HTML {
|
||||
cleanMsg := template.HTMLEscapeString(msg)
|
||||
fullMessage := string(base.RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix, metas))
|
||||
fullMessage := string(markdown.RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix, metas))
|
||||
msgLines := strings.Split(strings.TrimSpace(fullMessage), "\n")
|
||||
numLines := len(msgLines)
|
||||
if numLines == 0 {
|
||||
@@ -225,11 +229,11 @@ type Actioner interface {
|
||||
// and returns a icon class name.
|
||||
func ActionIcon(opType int) string {
|
||||
switch opType {
|
||||
case 1, 8: // Create, transfer repository
|
||||
case 1, 8: // Create and transfer repository
|
||||
return "repo"
|
||||
case 5, 9: // Commit repository
|
||||
return "git-commit"
|
||||
case 6: // Create issue
|
||||
case 6, 13: // Create and reopen issue
|
||||
return "issue-opened"
|
||||
case 7: // New pull request
|
||||
return "git-pull-request"
|
||||
@@ -237,6 +241,8 @@ func ActionIcon(opType int) string {
|
||||
return "comment"
|
||||
case 11: // Merge pull request
|
||||
return "git-merge"
|
||||
case 12: // Close issue
|
||||
return "issue-closed"
|
||||
default:
|
||||
return "invalid type"
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
# UUID package for Go language
|
||||
|
||||
[](https://travis-ci.org/satori/go.uuid)
|
||||
[](http://godoc.org/github.com/satori/go.uuid)
|
||||
|
||||
This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs.
|
||||
|
||||
With 100% test coverage and benchmarks out of box.
|
||||
|
||||
Supported versions:
|
||||
* Version 1, based on timestamp and MAC address (RFC 4122)
|
||||
* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1)
|
||||
* Version 3, based on MD5 hashing (RFC 4122)
|
||||
* Version 4, based on random numbers (RFC 4122)
|
||||
* Version 5, based on SHA-1 hashing (RFC 4122)
|
||||
|
||||
## Installation
|
||||
|
||||
Use the `go` command:
|
||||
|
||||
$ go get github.com/satori/go.uuid
|
||||
|
||||
## Requirements
|
||||
|
||||
UUID package requires any stable version of Go Programming Language.
|
||||
|
||||
It is tested against following versions of Go: 1.0, 1.1, 1.2
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Creating UUID Version 4
|
||||
u1 := uuid.NewV4()
|
||||
fmt.Printf("UUIDv4: %s\n", u1)
|
||||
|
||||
// Parsing UUID from string input
|
||||
u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||
if err != nil {
|
||||
fmt.Printf("Something gone wrong: %s", err)
|
||||
}
|
||||
fmt.Printf("Successfully parsed: %s", u2)
|
||||
}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project.
|
||||
|
||||
## Links
|
||||
* [RFC 4122](http://tools.ietf.org/html/rfc4122)
|
||||
* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01)
|
||||
|
||||
## Copyright
|
||||
|
||||
Copyright (C) 2013 by Maxim Bublis <b@codemonkey.ru>.
|
||||
|
||||
UUID package released under MIT License.
|
||||
See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user