Compare commits

..

21 Commits

Author SHA1 Message Date
Lunny Xiao
34182c87ec release notes for v1.1.4 2017-09-04 15:34:29 +02:00
Lunny Xiao
c401788383 bug fixed 2017-09-04 14:27:53 +08:00
Ethan Koenig
8335b556d1 Fix rendering of external links (#2292) (#2315) 2017-08-17 15:03:41 +08:00
Lunny Xiao
09fff9e1c1 fix 500 error when view an issue which's milestone deleted (#2297) (#2299) 2017-08-14 10:45:06 +08:00
Lunny Xiao
622552b709 Fix deleted milestone bug (#1942) (#2300)
* Fix deleted milestone bug

* Use locale for ghost milestone name

* Fix pointer bug
2017-08-13 19:18:57 -03:00
Lunny Xiao
1709297701 Fix SHA1 hash linking (#2143) (#2293)
This changes the regex to look for a hash from 7 to 40 characters,
to match the use of abbreviated hash lookups in both git and github.
The restriction of not being a pure number is also removed because
1234567 is now considered a valid abbreviated hash, as is deadbeef.

A note has been added to the top of the code to state that the
literal regex match is fine, but no extra validation is currently
performed so some false positives are expected.

A future change could ensure that the hash exists in the repository
before rendering it as a link, although this might incur a slight
performance penalty.

Reverts part of commit 4a46613 and fixes #2053.
2017-08-12 09:32:56 +08:00
Bo-Yi Wu
5fe8fee933 back port from #1709 (#2291)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-11 10:32:26 +08:00
Bo-Yi Wu
5bb20be8b2 update sig file (#2269)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-06 21:56:17 +03:00
Lunny Xiao
06a554c22a ignore coverage for release (#2263) 2017-08-05 12:14:59 +03:00
Lunny Xiao
00bd47ae5c add changelog of release v1.1.3 (#2251) 2017-08-03 16:50:21 +08:00
Lunny Xiao
b20f1ab47f fix some bug 2017-07-28 14:36:18 +08:00
Ethan Koenig
9a7f59ef35 Fix fast-forward PR bug (#2137)
* Fix fast-forward PR bug

* Don't ignore error in getMergeCommit (#1843)
2017-07-11 09:51:39 -05:00
Ethan Koenig
6a6f0616f2 Fix diff of renamed and modified file (#2136) 2017-07-11 02:19:10 -05:00
Ethan Koenig
6caf04c129 Don't ignore gravatar error (#2138) 2017-07-11 01:00:43 -05:00
Antoine GIRARD
406f5de18c Fix missing less sources for oauth (backport #1288) (#2135) 2017-07-11 09:25:30 +08:00
Andrey Nering
39cb1ac517 Merge pull request #2043 from lunny/lunny/fix_markdown_render_list
Fix markdown rendering (#1530)
2017-06-23 10:17:45 -03:00
Morlinest
58dcbaf20b Fix markdown rendering (#1530) 2017-06-23 17:19:38 +08:00
Kim "BKC" Carlbäcker
5f212ff4e9 Fix PR template error (#2008) 2017-06-19 09:18:53 +02:00
Ethan Koenig
45fa822ac4 Fix PR template error 2017-06-18 22:01:20 -04:00
Kim "BKC" Carlbäcker
1ac8646845 Merge pull request #1944 from appleboy/release/v1.1
[ci skip] add 1.1.2 change log.
2017-06-12 15:26:43 +02:00
Bo-Yi Wu
13e284c7cf [ci skip] add 1.1.2 change log.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-06-12 17:04:29 +08:00
22 changed files with 229 additions and 168 deletions

View File

@@ -57,11 +57,11 @@ pipeline:
when: when:
event: [ push, tag, pull_request ] event: [ push, tag, pull_request ]
coverage: # coverage:
image: plugins/coverage # image: plugins/coverage
server: https://coverage.gitea.io # server: https://coverage.gitea.io
when: # when:
event: [ push, tag, pull_request ] # event: [ push, tag, pull_request ]
docker: docker:
image: plugins/docker image: plugins/docker

View File

@@ -1 +1 @@
eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9zcnYvYXBwCiAgcGF0aDogc3JjL2NvZGUuZ2l0ZWEuaW8vZ2l0ZWEKCnBpcGVsaW5lOgogIGNsb25lOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0CiAgICB0YWdzOiB0cnVlCgogIHRlc3Q6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgVEFHUzogYmluZGF0YSBzcWxpdGUKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gYXBrIC1VIGFkZCBvcGVuc3NoLWNsaWVudAogICAgICAtIG1ha2UgY2xlYW4KICAgICAgLSBtYWtlIGdlbmVyYXRlCiAgICAgIC0gbWFrZSB2ZXQKICAgICAgLSBtYWtlIGxpbnQKICAgICAgLSBtYWtlIHRlc3QKICAgICAgLSBtYWtlIGJ1aWxkCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIHRlc3QtbXlzcWw6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgVEFHUzogYmluZGF0YQogICAgICBHT1BBVEg6IC9zcnYvYXBwCiAgICBjb21tYW5kczoKICAgICAgLSBtYWtlIHRlc3QtbXlzcWwKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2gsIHRhZywgcHVsbF9yZXF1ZXN0IF0KCiAgdGVzdC1wZ3NxbDoKICAgIGltYWdlOiB3ZWJoaXBwaWUvZ29sYW5nOmVkZ2UKICAgIHB1bGw6IHRydWUKICAgIGVudmlyb25tZW50OgogICAgICBUQUdTOiBiaW5kYXRhCiAgICAgIEdPUEFUSDogL3Nydi9hcHAKICAgIGNvbW1hbmRzOgogICAgICAtIG1ha2UgdGVzdC1wZ3NxbAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICBzdGF0aWM6CiAgICBpbWFnZToga2FyYWxhYmUveGdvLWxhdGVzdDpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGVudmlyb25tZW50OgogICAgICBUQUdTOiBiaW5kYXRhIHNxbGl0ZQogICAgICBHT1BBVEg6IC9zcnYvYXBwCiAgICBjb21tYW5kczoKICAgICAgLSBtYWtlIHJlbGVhc2UKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2gsIHRhZywgcHVsbF9yZXF1ZXN0IF0KCiAgY292ZXJhZ2U6CiAgICBpbWFnZTogcGx1Z2lucy9jb3ZlcmFnZQogICAgc2VydmVyOiBodHRwczovL2NvdmVyYWdlLmdpdGVhLmlvCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIGRvY2tlcjoKICAgIGltYWdlOiBwbHVnaW5zL2RvY2tlcgogICAgcmVwbzogZ2l0ZWEvZ2l0ZWEKICAgIHRhZ3M6IFsgJyR7RFJPTkVfVEFHIyN2fScgXQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgdGFnIF0KICAgICAgYnJhbmNoOiBbIHJlZnMvdGFncy8qIF0KCiAgZG9ja2VyOgogICAgaW1hZ2U6IHBsdWdpbnMvZG9ja2VyCiAgICByZXBvOiBnaXRlYS9naXRlYQogICAgdGFnczogWyAnJHtEUk9ORV9CUkFOQ0gjI3JlbGVhc2Uvdn0nIF0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQogICAgICBicmFuY2g6IFsgcmVsZWFzZS8qIF0KCiAgZG9ja2VyOgogICAgaW1hZ2U6IHBsdWdpbnMvZG9ja2VyCiAgICByZXBvOiBnaXRlYS9naXRlYQogICAgdGFnczogWyAnbGF0ZXN0JyBdCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIG1hc3RlciBdCgogIHJlbGVhc2U6CiAgICBpbWFnZTogcGx1Z2lucy9zMwogICAgcGF0aF9zdHlsZTogdHJ1ZQogICAgc3RyaXBfcHJlZml4OiBkaXN0L3JlbGVhc2UvCiAgICBzb3VyY2U6IGRpc3QvcmVsZWFzZS8qCiAgICB0YXJnZXQ6IC9naXRlYS8ke0RST05FX1RBRyMjdn0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHRhZyBdCiAgICAgIGJyYW5jaDogWyByZWZzL3RhZ3MvKiBdCgogIHJlbGVhc2U6CiAgICBpbWFnZTogcGx1Z2lucy9zMwogICAgcGF0aF9zdHlsZTogdHJ1ZQogICAgc3RyaXBfcHJlZml4OiBkaXN0L3JlbGVhc2UvCiAgICBzb3VyY2U6IGRpc3QvcmVsZWFzZS8qCiAgICB0YXJnZXQ6IC9naXRlYS8ke0RST05FX0JSQU5DSCMjcmVsZWFzZS92fQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCiAgICAgIGJyYW5jaDogWyByZWxlYXNlLyogXQoKICByZWxlYXNlOgogICAgaW1hZ2U6IHBsdWdpbnMvczMKICAgIHBhdGhfc3R5bGU6IHRydWUKICAgIHN0cmlwX3ByZWZpeDogZGlzdC9yZWxlYXNlLwogICAgc291cmNlOiBkaXN0L3JlbGVhc2UvKgogICAgdGFyZ2V0OiAvZ2l0ZWEvbWFzdGVyCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIG1hc3RlciBdCgogIGdpdGh1YjoKICAgIGltYWdlOiBwbHVnaW5zL2dpdGh1Yi1yZWxlYXNlCiAgICBmaWxlczoKICAgICAgLSBkaXN0L3JlbGVhc2UvKgogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgdGFnIF0KICAgICAgYnJhbmNoOiBbIHJlZnMvdGFncy8qIF0KCiAgZ2l0dGVyOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0dGVyCgpzZXJ2aWNlczoKICBteXNxbDoKICAgIGltYWdlOiBteXNxbDo1LjcKICAgIGVudmlyb25tZW50OgogICAgICAtIE1ZU1FMX0RBVEFCQVNFPXRlc3QKICAgICAgLSBNWVNRTF9BTExPV19FTVBUWV9QQVNTV09SRD15ZXMKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2gsIHRhZywgcHVsbF9yZXF1ZXN0IF0KCiAgcGdzcWw6CiAgICBpbWFnZTogcG9zdGdyZXM6OS41CiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBQT1NUR1JFU19EQj10ZXN0CiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCg.hp6IsxbFIQOaxJdmGv32Vf34-Nra3KqVIWzH52W687I eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9zcnYvYXBwCiAgcGF0aDogc3JjL2NvZGUuZ2l0ZWEuaW8vZ2l0ZWEKCnBpcGVsaW5lOgogIGNsb25lOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0CiAgICB0YWdzOiB0cnVlCgogIHRlc3Q6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgVEFHUzogYmluZGF0YSBzcWxpdGUKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gYXBrIC1VIGFkZCBvcGVuc3NoLWNsaWVudAogICAgICAtIG1ha2UgY2xlYW4KICAgICAgLSBtYWtlIGdlbmVyYXRlCiAgICAgIC0gbWFrZSB2ZXQKICAgICAgLSBtYWtlIGxpbnQKICAgICAgLSBtYWtlIHRlc3QKICAgICAgLSBtYWtlIGJ1aWxkCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIHRlc3QtbXlzcWw6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgVEFHUzogYmluZGF0YQogICAgICBHT1BBVEg6IC9zcnYvYXBwCiAgICBjb21tYW5kczoKICAgICAgLSBtYWtlIHRlc3QtbXlzcWwKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2gsIHRhZywgcHVsbF9yZXF1ZXN0IF0KCiAgdGVzdC1wZ3NxbDoKICAgIGltYWdlOiB3ZWJoaXBwaWUvZ29sYW5nOmVkZ2UKICAgIHB1bGw6IHRydWUKICAgIGVudmlyb25tZW50OgogICAgICBUQUdTOiBiaW5kYXRhCiAgICAgIEdPUEFUSDogL3Nydi9hcHAKICAgIGNvbW1hbmRzOgogICAgICAtIG1ha2UgdGVzdC1wZ3NxbAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICBzdGF0aWM6CiAgICBpbWFnZToga2FyYWxhYmUveGdvLWxhdGVzdDpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGVudmlyb25tZW50OgogICAgICBUQUdTOiBiaW5kYXRhIHNxbGl0ZQogICAgICBHT1BBVEg6IC9zcnYvYXBwCiAgICBjb21tYW5kczoKICAgICAgLSBtYWtlIHJlbGVhc2UKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2gsIHRhZywgcHVsbF9yZXF1ZXN0IF0KCiAgIyBjb3ZlcmFnZToKICAjICAgaW1hZ2U6IHBsdWdpbnMvY292ZXJhZ2UKICAjICAgc2VydmVyOiBodHRwczovL2NvdmVyYWdlLmdpdGVhLmlvCiAgIyAgIHdoZW46CiAgIyAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICBkb2NrZXI6CiAgICBpbWFnZTogcGx1Z2lucy9kb2NrZXIKICAgIHJlcG86IGdpdGVhL2dpdGVhCiAgICB0YWdzOiBbICcke0RST05FX1RBRyMjdn0nIF0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHRhZyBdCiAgICAgIGJyYW5jaDogWyByZWZzL3RhZ3MvKiBdCgogIGRvY2tlcjoKICAgIGltYWdlOiBwbHVnaW5zL2RvY2tlcgogICAgcmVwbzogZ2l0ZWEvZ2l0ZWEKICAgIHRhZ3M6IFsgJyR7RFJPTkVfQlJBTkNIIyNyZWxlYXNlL3Z9JyBdCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIHJlbGVhc2UvKiBdCgogIGRvY2tlcjoKICAgIGltYWdlOiBwbHVnaW5zL2RvY2tlcgogICAgcmVwbzogZ2l0ZWEvZ2l0ZWEKICAgIHRhZ3M6IFsgJ2xhdGVzdCcgXQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCiAgICAgIGJyYW5jaDogWyBtYXN0ZXIgXQoKICByZWxlYXNlOgogICAgaW1hZ2U6IHBsdWdpbnMvczMKICAgIHBhdGhfc3R5bGU6IHRydWUKICAgIHN0cmlwX3ByZWZpeDogZGlzdC9yZWxlYXNlLwogICAgc291cmNlOiBkaXN0L3JlbGVhc2UvKgogICAgdGFyZ2V0OiAvZ2l0ZWEvJHtEUk9ORV9UQUcjI3Z9CiAgICB3aGVuOgogICAgICBldmVudDogWyB0YWcgXQogICAgICBicmFuY2g6IFsgcmVmcy90YWdzLyogXQoKICByZWxlYXNlOgogICAgaW1hZ2U6IHBsdWdpbnMvczMKICAgIHBhdGhfc3R5bGU6IHRydWUKICAgIHN0cmlwX3ByZWZpeDogZGlzdC9yZWxlYXNlLwogICAgc291cmNlOiBkaXN0L3JlbGVhc2UvKgogICAgdGFyZ2V0OiAvZ2l0ZWEvJHtEUk9ORV9CUkFOQ0gjI3JlbGVhc2Uvdn0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQogICAgICBicmFuY2g6IFsgcmVsZWFzZS8qIF0KCiAgcmVsZWFzZToKICAgIGltYWdlOiBwbHVnaW5zL3MzCiAgICBwYXRoX3N0eWxlOiB0cnVlCiAgICBzdHJpcF9wcmVmaXg6IGRpc3QvcmVsZWFzZS8KICAgIHNvdXJjZTogZGlzdC9yZWxlYXNlLyoKICAgIHRhcmdldDogL2dpdGVhL21hc3RlcgogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCiAgICAgIGJyYW5jaDogWyBtYXN0ZXIgXQoKICBnaXRodWI6CiAgICBpbWFnZTogcGx1Z2lucy9naXRodWItcmVsZWFzZQogICAgZmlsZXM6CiAgICAgIC0gZGlzdC9yZWxlYXNlLyoKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHRhZyBdCiAgICAgIGJyYW5jaDogWyByZWZzL3RhZ3MvKiBdCgogIGdpdHRlcjoKICAgIGltYWdlOiBwbHVnaW5zL2dpdHRlcgoKc2VydmljZXM6CiAgbXlzcWw6CiAgICBpbWFnZTogbXlzcWw6NS43CiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBNWVNRTF9EQVRBQkFTRT10ZXN0CiAgICAgIC0gTVlTUUxfQUxMT1dfRU1QVFlfUEFTU1dPUkQ9eWVzCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIHBnc3FsOgogICAgaW1hZ2U6IHBvc3RncmVzOjkuNQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfREI9dGVzdAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQo.uf02h57dWfCrxG3rcNcYlZPQP2XsFhKvcF2geGTpG50

View File

@@ -1,5 +1,34 @@
# Changelog # Changelog
## [1.1.4](https://github.com/go-gitea/gitea/releases/tag/v1.1.4) - 2017-09-04
* BUGFIXES
* Fix rendering of external links (#2292) (#2315)
* Fix deleted milestone bug (#1942) (#2300)
* fix 500 error when view an issue which's milestone deleted (#2297) (#2299)
* Fix SHA1 hash linking (#2143) (#2293)
* back port from #1709 (#2291)
## [1.1.3](https://github.com/go-gitea/gitea/releases/tag/v1.1.3) - 2017-08-03
* BUGFIXES
* Fix PR template error (#2008)
* Fix markdown rendering (fix #1530) (#2043)
* Fix missing less sources for oauth (backport #1288) (#2135)
* Don't ignore gravatar error (#2138)
* Fix diff of renamed and modified file (#2136)
* Fix fast-forward PR bug (#2137)
* Fix some security bugs
## [1.1.2](https://github.com/go-gitea/gitea/releases/tag/v1.1.2) - 2017-06-13
* BUGFIXES
* Enforce netgo build tag while cross-compilation (Backport of #1690) (#1731)
* fix update avatar
* fix delete user failed on sqlite (#1321)
* fix bug not to trim space of login username (#1806)
* Backport bugfixes #1220 and #1393 to v1.1 (#1758)
## [1.1.1](https://github.com/go-gitea/gitea/releases/tag/v1.1.1) - 2017-05-04 ## [1.1.1](https://github.com/go-gitea/gitea/releases/tag/v1.1.1) - 2017-05-04
* BUGFIXES * BUGFIXES

View File

@@ -366,10 +366,12 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
} }
curFile = &DiffFile{ curFile = &DiffFile{
Name: a, Name: b,
Index: len(diff.Files) + 1, OldName: a,
Type: DiffFileChange, Index: len(diff.Files) + 1,
Sections: make([]*DiffSection, 0, 10), Type: DiffFileChange,
Sections: make([]*DiffSection, 0, 10),
IsRenamed: a != b,
} }
diff.Files = append(diff.Files, curFile) diff.Files = append(diff.Files, curFile)
if len(diff.Files) >= maxFiles { if len(diff.Files) >= maxFiles {
@@ -402,9 +404,6 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
curFile.Type = DiffFileChange curFile.Type = DiffFileChange
case strings.HasPrefix(line, "similarity index 100%"): case strings.HasPrefix(line, "similarity index 100%"):
curFile.Type = DiffFileRename curFile.Type = DiffFileRename
curFile.IsRenamed = true
curFile.OldName = curFile.Name
curFile.Name = b
} }
if curFile.Type > 0 { if curFile.Type > 0 {
if strings.HasSuffix(line, " 160000\n") { if strings.HasSuffix(line, " 160000\n") {

View File

@@ -146,7 +146,7 @@ func (issue *Issue) loadAttributes(e Engine) (err error) {
if issue.Milestone == nil && issue.MilestoneID > 0 { if issue.Milestone == nil && issue.MilestoneID > 0 {
issue.Milestone, err = getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID) issue.Milestone, err = getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
if err != nil { if err != nil && !IsErrMilestoneNotExist(err) {
return fmt.Errorf("getMilestoneByRepoID [repo_id: %d, milestone_id: %d]: %v", issue.RepoID, issue.MilestoneID, err) return fmt.Errorf("getMilestoneByRepoID [repo_id: %d, milestone_id: %d]: %v", issue.RepoID, issue.MilestoneID, err)
} }
} }

View File

@@ -231,12 +231,9 @@ func (c *Comment) LoadMilestone() error {
has, err := x.ID(c.OldMilestoneID).Get(&oldMilestone) has, err := x.ID(c.OldMilestoneID).Get(&oldMilestone)
if err != nil { if err != nil {
return err return err
} else if !has { } else if has {
return ErrMilestoneNotExist{ c.OldMilestone = &oldMilestone
ID: c.OldMilestoneID,
}
} }
c.OldMilestone = &oldMilestone
} }
if c.MilestoneID > 0 { if c.MilestoneID > 0 {
@@ -244,12 +241,9 @@ func (c *Comment) LoadMilestone() error {
has, err := x.ID(c.MilestoneID).Get(&milestone) has, err := x.ID(c.MilestoneID).Get(&milestone)
if err != nil { if err != nil {
return err return err
} else if !has { } else if has {
return ErrMilestoneNotExist{ c.Milestone = &milestone
ID: c.MilestoneID,
}
} }
c.Milestone = &milestone
} }
return nil return nil
} }

View File

@@ -499,9 +499,15 @@ func (pr *PullRequest) getMergeCommit() (*git.Commit, error) {
return nil, fmt.Errorf("git merge-base --is-ancestor: %v %v", stderr, err) return nil, fmt.Errorf("git merge-base --is-ancestor: %v %v", stderr, err)
} }
// We can ignore this error since we only get here when there's a valid commit in headFile commitIDBytes, err := ioutil.ReadFile(pr.BaseRepo.RepoPath() + "/" + headFile)
commitID, _ := ioutil.ReadFile(pr.BaseRepo.RepoPath() + "/" + headFile) if err != nil {
cmd := string(commitID)[:40] + ".." + pr.BaseBranch return nil, fmt.Errorf("ReadFile(%s): %v", headFile, err)
}
commitID := string(commitIDBytes)
if len(commitID) < 40 {
return nil, fmt.Errorf(`ReadFile(%s): invalid commit-ID "%s"`, headFile, commitID)
}
cmd := commitID[:40] + ".." + pr.BaseBranch
// Get the commit from BaseBranch where the pull request got merged // Get the commit from BaseBranch where the pull request got merged
mergeCommit, stderr, err := process.GetManager().ExecDirEnv(-1, "", fmt.Sprintf("isMerged (git rev-list --ancestry-path --merges --reverse): %d", pr.BaseRepo.ID), mergeCommit, stderr, err := process.GetManager().ExecDirEnv(-1, "", fmt.Sprintf("isMerged (git rev-list --ancestry-path --merges --reverse): %d", pr.BaseRepo.ID),
@@ -510,6 +516,9 @@ func (pr *PullRequest) getMergeCommit() (*git.Commit, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %v %v", stderr, err) return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %v %v", stderr, err)
} else if len(mergeCommit) < 40 {
// PR was fast-forwarded, so just use last commit of PR
mergeCommit = commitID[:40]
} }
gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath()) gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())

View File

@@ -328,15 +328,14 @@ func (u *User) generateRandomAvatar(e Engine) error {
// which includes app sub-url as prefix. However, it is possible // which includes app sub-url as prefix. However, it is possible
// to return full URL if user enables Gravatar-like service. // to return full URL if user enables Gravatar-like service.
func (u *User) RelAvatarLink() string { func (u *User) RelAvatarLink() string {
defaultImgURL := setting.AppSubURL + "/img/avatar_default.png"
if u.ID == -1 { if u.ID == -1 {
return defaultImgURL return base.DefaultAvatarLink()
} }
switch { switch {
case u.UseCustomAvatar: case u.UseCustomAvatar:
if !com.IsFile(u.CustomAvatarPath()) { if !com.IsFile(u.CustomAvatarPath()) {
return defaultImgURL return base.DefaultAvatarLink()
} }
return setting.AppSubURL + "/avatars/" + u.Avatar return setting.AppSubURL + "/avatars/" + u.Avatar
case setting.DisableGravatar, setting.OfflineMode: case setting.DisableGravatar, setting.OfflineMode:

View File

@@ -192,13 +192,21 @@ func HashEmail(email string) string {
return EncodeMD5(strings.ToLower(strings.TrimSpace(email))) return EncodeMD5(strings.ToLower(strings.TrimSpace(email)))
} }
// DefaultAvatarLink the default avatar link
func DefaultAvatarLink() string {
return setting.AppSubURL + "/img/avatar_default.png"
}
// AvatarLink returns relative avatar link to the site domain by given email, // AvatarLink returns relative avatar link to the site domain by given email,
// which includes app sub-url as prefix. However, it is possible // which includes app sub-url as prefix. However, it is possible
// to return full URL if user enables Gravatar-like service. // to return full URL if user enables Gravatar-like service.
func AvatarLink(email string) string { func AvatarLink(email string) string {
if setting.EnableFederatedAvatar && setting.LibravatarService != nil { if setting.EnableFederatedAvatar && setting.LibravatarService != nil {
// TODO: This doesn't check any error. AvatarLink should return (string, error) url, err := setting.LibravatarService.FromEmail(email)
url, _ := setting.LibravatarService.FromEmail(email) if err != nil {
log.Error(4, "LibravatarService.FromEmail(email=%s): error %v", email, err)
return DefaultAvatarLink()
}
return url return url
} }
@@ -206,7 +214,7 @@ func AvatarLink(email string) string {
return setting.GravatarSource + HashEmail(email) return setting.GravatarSource + HashEmail(email)
} }
return setting.AppSubURL + "/img/avatar_default.png" return DefaultAvatarLink()
} }
// Seconds-based time units // Seconds-based time units

View File

@@ -334,13 +334,11 @@ func RepoAssignment(args ...bool) macaron.Handler {
if ctx.Repo.IsWriter() || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID)) { if ctx.Repo.IsWriter() || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID)) {
// Pull request is allowed if this is a fork repository // Pull request is allowed if this is a fork repository
// and base repository accepts pull requests. // and base repository accepts pull requests.
if repo.BaseRepo != nil { if repo.BaseRepo != nil && repo.BaseRepo.AllowsPulls() {
if repo.BaseRepo.AllowsPulls() { ctx.Data["BaseRepo"] = repo.BaseRepo
ctx.Data["BaseRepo"] = repo.BaseRepo ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo
ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo ctx.Repo.PullRequest.Allowed = true
ctx.Repo.PullRequest.Allowed = true ctx.Repo.PullRequest.HeadInfo = ctx.Repo.Owner.Name + ":" + ctx.Repo.BranchName
ctx.Repo.PullRequest.HeadInfo = ctx.Repo.Owner.Name + ":" + ctx.Repo.BranchName
}
} else { } else {
// Or, this is repository accepts pull requests between branches. // Or, this is repository accepts pull requests between branches.
if repo.AllowsPulls() { if repo.AllowsPulls() {

View File

@@ -53,6 +53,10 @@ func IsReadmeFile(name string) bool {
} }
var ( var (
// NOTE: All below regex matching do not perform any extra validation.
// Thus a link is produced even if the user does not exist, the issue does not exist, the commit does not exist, etc.
// While fast, this is also incorrect and lead to false positives.
// MentionPattern matches string that mentions someone, e.g. @Unknwon // MentionPattern matches string that mentions someone, e.g. @Unknwon
MentionPattern = regexp.MustCompile(`(\s|^|\W)@[0-9a-zA-Z-_\.]+`) MentionPattern = regexp.MustCompile(`(\s|^|\W)@[0-9a-zA-Z-_\.]+`)
@@ -65,9 +69,9 @@ var (
CrossReferenceIssueNumericPattern = regexp.MustCompile(`( |^)[0-9a-zA-Z]+/[0-9a-zA-Z]+#[0-9]+\b`) CrossReferenceIssueNumericPattern = regexp.MustCompile(`( |^)[0-9a-zA-Z]+/[0-9a-zA-Z]+#[0-9]+\b`)
// Sha1CurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae // Sha1CurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae
// FIXME: this pattern matches pure numbers as well, right now we do a hack to check in renderSha1CurrentPattern // Although SHA1 hashes are 40 chars long, the regex matches the hash from 7 to 40 chars in length
// by converting string to a number. // so that abbreviated hash links can be used as well. This matches git and github useability.
Sha1CurrentPattern = regexp.MustCompile(`(?:^|\s|\()[0-9a-f]{40}\b`) Sha1CurrentPattern = regexp.MustCompile(`(?:^|\s|\()([0-9a-f]{7,40})\b`)
// ShortLinkPattern matches short but difficult to parse [[name|link|arg=test]] syntax // ShortLinkPattern matches short but difficult to parse [[name|link|arg=test]] syntax
ShortLinkPattern = regexp.MustCompile(`(\[\[.*\]\]\w*)`) ShortLinkPattern = regexp.MustCompile(`(\[\[.*\]\]\w*)`)
@@ -75,12 +79,29 @@ var (
// AnySHA1Pattern allows to split url containing SHA into parts // AnySHA1Pattern allows to split url containing SHA into parts
AnySHA1Pattern = regexp.MustCompile(`(http\S*)://(\S+)/(\S+)/(\S+)/(\S+)/([0-9a-f]{40})(?:/?([^#\s]+)?(?:#(\S+))?)?`) AnySHA1Pattern = regexp.MustCompile(`(http\S*)://(\S+)/(\S+)/(\S+)/(\S+)/([0-9a-f]{40})(?:/?([^#\s]+)?(?:#(\S+))?)?`)
// IssueFullPattern allows to split issue (and pull) URLs into parts
IssueFullPattern = regexp.MustCompile(`(?:^|\s|\()(http\S*)://((?:[^\s/]+/)+)((?:\w{1,10}-)?[1-9][0-9]*)([\?|#]\S+.(\S+)?)?\b`)
validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`) validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`)
) )
// regexp for full links to issues/pulls
var issueFullPattern *regexp.Regexp
// InitMarkdown initialize regexps for markdown parsing
func InitMarkdown() {
getIssueFullPattern()
}
func getIssueFullPattern() *regexp.Regexp {
if issueFullPattern == nil {
appURL := setting.AppURL
if len(appURL) > 0 && appURL[len(appURL)-1] != '/' {
appURL += "/"
}
issueFullPattern = regexp.MustCompile(appURL +
`\w+/\w+/(?:issues|pulls)/((?:\w{1,10}-)?[1-9][0-9]*)([\?|#]\S+.(\S+)?)?\b`)
}
return issueFullPattern
}
// isLink reports whether link fits valid format. // isLink reports whether link fits valid format.
func isLink(link []byte) bool { func isLink(link []byte) bool {
return validLinksPattern.Match(link) return validLinksPattern.Match(link)
@@ -155,12 +176,15 @@ func (r *Renderer) ListItem(out *bytes.Buffer, text []byte, flags int) {
} }
switch { switch {
case bytes.HasPrefix(text, []byte(prefix+"[ ] ")): case bytes.HasPrefix(text, []byte(prefix+"[ ] ")):
text = append([]byte(`<div class="ui fitted disabled checkbox"><input type="checkbox" disabled="disabled" /><label /></div>`), text[3+len(prefix):]...) text = append([]byte(`<span class="ui fitted disabled checkbox"><input type="checkbox" disabled="disabled" /><label /></span>`), text[3+len(prefix):]...)
if prefix != "" {
text = bytes.Replace(text, []byte(prefix), []byte{}, 1)
}
case bytes.HasPrefix(text, []byte(prefix+"[x] ")): case bytes.HasPrefix(text, []byte(prefix+"[x] ")):
text = append([]byte(`<div class="ui checked fitted disabled checkbox"><input type="checkbox" checked="" disabled="disabled" /><label /></div>`), text[3+len(prefix):]...) text = append([]byte(`<span class="ui checked fitted disabled checkbox"><input type="checkbox" checked="" disabled="disabled" /><label /></span>`), text[3+len(prefix):]...)
} if prefix != "" {
if prefix != "" { text = bytes.Replace(text, []byte(prefix), []byte{}, 1)
text = bytes.Replace(text, []byte("</p>"), []byte{}, 1) }
} }
r.Renderer.ListItem(out, text, flags) r.Renderer.ListItem(out, text, flags)
} }
@@ -345,32 +369,17 @@ func renderFullSha1Pattern(rawBytes []byte, urlPrefix string) []byte {
return rawBytes return rawBytes
} }
// renderFullIssuePattern renders issues-like URLs // RenderFullIssuePattern renders issues-like URLs
func renderFullIssuePattern(rawBytes []byte, urlPrefix string) []byte { func RenderFullIssuePattern(rawBytes []byte) []byte {
ms := IssueFullPattern.FindAllSubmatch(rawBytes, -1) ms := getIssueFullPattern().FindAllSubmatch(rawBytes, -1)
for _, m := range ms { for _, m := range ms {
all := m[0] all := m[0]
protocol := string(m[1]) id := string(m[1])
paths := bytes.Split(m[2], []byte("/"))
paths = paths[:len(paths)-1]
if bytes.HasPrefix(paths[0], []byte("gist.")) {
continue
}
path := protocol + "://" + string(m[2])
id := string(m[3])
path = URLJoin(path, id)
var comment []byte
if len(m) > 3 {
comment = m[4]
}
urlSuffix := ""
text := "#" + id text := "#" + id
if comment != nil { // TODO if m[2] is not nil, then link is to a comment,
urlSuffix += string(comment) // and we should indicate that in the text somehow
text += " <i class='comment icon'></i>"
}
rawBytes = bytes.Replace(rawBytes, all, []byte(fmt.Sprintf( rawBytes = bytes.Replace(rawBytes, all, []byte(fmt.Sprintf(
`<a href="%s%s">%s</a>`, path, urlSuffix, text)), -1) `<a href="%s">%s</a>`, string(all), text)), -1)
} }
return rawBytes return rawBytes
} }
@@ -550,12 +559,15 @@ func RenderCrossReferenceIssueIndexPattern(rawBytes []byte, urlPrefix string, me
func renderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte { func renderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte {
ms := Sha1CurrentPattern.FindAllSubmatch(rawBytes, -1) ms := Sha1CurrentPattern.FindAllSubmatch(rawBytes, -1)
for _, m := range ms { for _, m := range ms {
all := m[0] hash := m[1]
if com.StrTo(all).MustInt() > 0 { // The regex does not lie, it matches the hash pattern.
continue // However, a regex cannot know if a hash actually exists or not.
} // We could assume that a SHA1 hash should probably contain alphas AND numerics
rawBytes = bytes.Replace(rawBytes, all, []byte(fmt.Sprintf( // but that is not always the case.
`<a href="%s">%s</a>`, URLJoin(urlPrefix, "commit", string(all)), base.ShortSha(string(all)))), -1) // Although unlikely, deadbeef and 1234567 are valid short forms of SHA1 hash
// as used by git and github for linking and thus we have to do similar.
rawBytes = bytes.Replace(rawBytes, hash, []byte(fmt.Sprintf(
`<a href="%s">%s</a>`, URLJoin(urlPrefix, "commit", string(hash)), base.ShortSha(string(hash)))), -1)
} }
return rawBytes return rawBytes
} }
@@ -569,12 +581,12 @@ func RenderSpecialLink(rawBytes []byte, urlPrefix string, metas map[string]strin
[]byte(fmt.Sprintf(`<a href="%s">%s</a>`, URLJoin(setting.AppURL, string(m[1:])), m)), -1) []byte(fmt.Sprintf(`<a href="%s">%s</a>`, URLJoin(setting.AppURL, string(m[1:])), m)), -1)
} }
rawBytes = RenderFullIssuePattern(rawBytes)
rawBytes = RenderShortLinks(rawBytes, urlPrefix, false, isWikiMarkdown) rawBytes = RenderShortLinks(rawBytes, urlPrefix, false, isWikiMarkdown)
rawBytes = RenderIssueIndexPattern(rawBytes, urlPrefix, metas) rawBytes = RenderIssueIndexPattern(rawBytes, urlPrefix, metas)
rawBytes = RenderCrossReferenceIssueIndexPattern(rawBytes, urlPrefix, metas) rawBytes = RenderCrossReferenceIssueIndexPattern(rawBytes, urlPrefix, metas)
rawBytes = renderFullSha1Pattern(rawBytes, urlPrefix) rawBytes = renderFullSha1Pattern(rawBytes, urlPrefix)
rawBytes = renderSha1CurrentPattern(rawBytes, urlPrefix) rawBytes = renderSha1CurrentPattern(rawBytes, urlPrefix)
rawBytes = renderFullIssuePattern(rawBytes, urlPrefix)
return rawBytes return rawBytes
} }
@@ -638,10 +650,8 @@ OUTER_LOOP:
// Copy the token to the output verbatim // Copy the token to the output verbatim
buf.Write(RenderShortLinks([]byte(token.String()), urlPrefix, true, isWikiMarkdown)) buf.Write(RenderShortLinks([]byte(token.String()), urlPrefix, true, isWikiMarkdown))
if token.Type == html.StartTagToken { if token.Type == html.StartTagToken && !com.IsSliceContainsStr(noEndTags, token.Data) {
if !com.IsSliceContainsStr(noEndTags, token.Data) { stackNum++
stackNum++
}
} }
// If this is the close tag to the outer-most, we are done // If this is the close tag to the outer-most, we are done
@@ -656,8 +666,8 @@ OUTER_LOOP:
continue OUTER_LOOP continue OUTER_LOOP
} }
if !com.IsSliceContainsStr(noEndTags, token.Data) { if !com.IsSliceContainsStr(noEndTags, tagName) {
startTags = append(startTags, token.Data) startTags = append(startTags, tagName)
} }
case html.EndTagToken: case html.EndTagToken:

View File

@@ -180,13 +180,15 @@ func TestRender_AutoLink(t *testing.T) {
numericIssueLink(URLJoin(setting.AppSubURL, "issues"), 3333)) numericIssueLink(URLJoin(setting.AppSubURL, "issues"), 3333))
// render external issue URLs // render external issue URLs
tmp := "http://1111/2222/ssss-issues/3333?param=blah&blahh=333" for _, externalURL := range []string{
test(tmp, "<a href=\""+tmp+"\">#3333 <i class='comment icon'></i></a>") "http://1111/2222/ssss-issues/3333?param=blah&blahh=333",
test("http://test.com/issues/33333", numericIssueLink("http://test.com/issues", 33333)) "http://test.com/issues/33333",
test("https://issues/333", numericIssueLink("https://issues", 333)) "https://issues/333"} {
test(externalURL, externalURL)
}
// render valid commit URLs // render valid commit URLs
tmp = URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae") tmp := URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae")
test(tmp, "<a href=\""+tmp+"\">d8a994ef24</a>") test(tmp, "<a href=\""+tmp+"\">d8a994ef24</a>")
tmp += "#diff-2" tmp += "#diff-2"
test(tmp, "<a href=\""+tmp+"\">d8a994ef24 (diff-2)</a>") test(tmp, "<a href=\""+tmp+"\">d8a994ef24 (diff-2)</a>")
@@ -290,6 +292,8 @@ func TestRender_Commits(t *testing.T) {
var src = strings.Replace(subtree, "/commit/", "/src/", -1) var src = strings.Replace(subtree, "/commit/", "/src/", -1)
test(sha, `<p><a href="`+commit+`" rel="nofollow">b6dd6210ea</a></p>`) test(sha, `<p><a href="`+commit+`" rel="nofollow">b6dd6210ea</a></p>`)
test(sha[:7], `<p><a href="`+commit[:len(commit)-(40-7)]+`" rel="nofollow">b6dd621</a></p>`)
test(sha[:39], `<p><a href="`+commit[:len(commit)-(40-39)]+`" rel="nofollow">b6dd6210ea</a></p>`)
test(commit, `<p><a href="`+commit+`" rel="nofollow">b6dd6210ea</a></p>`) test(commit, `<p><a href="`+commit+`" rel="nofollow">b6dd6210ea</a></p>`)
test(tree, `<p><a href="`+src+`" rel="nofollow">b6dd6210ea/src</a></p>`) test(tree, `<p><a href="`+src+`" rel="nofollow">b6dd6210ea/src</a></p>`)
} }
@@ -330,6 +334,22 @@ func TestRender_CrossReferences(t *testing.T) {
`<p><a href="`+URLJoin(AppURL, "gogits", "gogs", "issues", "12345")+`" rel="nofollow">gogits/gogs#12345</a></p>`) `<p><a href="`+URLJoin(AppURL, "gogits", "gogs", "issues", "12345")+`" rel="nofollow">gogits/gogs#12345</a></p>`)
} }
func TestRender_FullIssueURLs(t *testing.T) {
setting.AppURL = AppURL
setting.AppSubURL = AppSubURL
test := func(input, expected string) {
result := RenderFullIssuePattern([]byte(input))
assert.Equal(t, expected, string(result))
}
test("Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6",
"Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6")
test("Look here http://localhost:3000/person/repo/issues/4",
`Look here <a href="http://localhost:3000/person/repo/issues/4">#4</a>`)
test("http://localhost:3000/person/repo/issues/4#issuecomment-1234",
`<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234">#4</a>`)
}
func TestRegExp_MentionPattern(t *testing.T) { func TestRegExp_MentionPattern(t *testing.T) {
trueTestCases := []string{ trueTestCases := []string{
"@Unknwon", "@Unknwon",
@@ -520,50 +540,6 @@ func TestRegExp_AnySHA1Pattern(t *testing.T) {
} }
} }
func TestRegExp_IssueFullPattern(t *testing.T) {
testCases := map[string][]string{
"https://github.com/gogits/gogs/pull/3244": {
"https",
"github.com/gogits/gogs/pull/",
"3244",
"",
"",
},
"https://github.com/gogits/gogs/issues/3247#issuecomment-231517079": {
"https",
"github.com/gogits/gogs/issues/",
"3247",
"#issuecomment-231517079",
"",
},
"https://try.gogs.io/gogs/gogs/issues/4#issue-685": {
"https",
"try.gogs.io/gogs/gogs/issues/",
"4",
"#issue-685",
"",
},
"https://youtrack.jetbrains.com/issue/JT-36485": {
"https",
"youtrack.jetbrains.com/issue/",
"JT-36485",
"",
"",
},
"https://youtrack.jetbrains.com/issue/JT-36485#comment=27-1508676": {
"https",
"youtrack.jetbrains.com/issue/",
"JT-36485",
"#comment=27-1508676",
"",
},
}
for k, v := range testCases {
assert.Equal(t, IssueFullPattern.FindStringSubmatch(k)[1:], v)
}
}
func TestMisc_IsMarkdownFile(t *testing.T) { func TestMisc_IsMarkdownFile(t *testing.T) {
setting.Markdown.FileExtensions = []string{".md", ".markdown", ".mdown", ".mkd"} setting.Markdown.FileExtensions = []string{".md", ".markdown", ".mdown", ".mkd"}
trueTestCases := []string{ trueTestCases := []string{
@@ -632,7 +608,7 @@ var sameCases = []string{
Ideas and codes Ideas and codes
- Bezier widget (by @r-lyeh) https://github.com/ocornut/imgui/issues/786 - Bezier widget (by @r-lyeh) ` + AppURL + `ocornut/imgui/issues/786
- Node graph editors https://github.com/ocornut/imgui/issues/306 - Node graph editors https://github.com/ocornut/imgui/issues/306
- [[Memory Editor|memory_editor_example]] - [[Memory Editor|memory_editor_example]]
- [[Plot var helper|plot_var_example]]`, - [[Plot var helper|plot_var_example]]`,
@@ -668,8 +644,8 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
<p>Ideas and codes</p> <p>Ideas and codes</p>
<ul> <ul>
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>)<a href="https://github.com/ocornut/imgui/issues/786" rel="nofollow">#786</a></li> <li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/ocornut/imgui/issues/786" rel="nofollow">#786</a></li>
<li>Node graph editors<a href="https://github.com/ocornut/imgui/issues/306" rel="nofollow">#306</a></li> <li>Node graph editors https://github.com/ocornut/imgui/issues/306</li>
<li><a href="` + baseURLContent + `memory_editor_example" rel="nofollow">Memory Editor</a></li> <li><a href="` + baseURLContent + `memory_editor_example" rel="nofollow">Memory Editor</a></li>
<li><a href="` + baseURLContent + `plot_var_example" rel="nofollow">Plot var helper</a></li> <li><a href="` + baseURLContent + `plot_var_example" rel="nofollow">Plot var helper</a></li>
</ul> </ul>

View File

@@ -558,6 +558,7 @@ issues.remove_label_at = `removed the <div class="ui label" style="color: %s; ba
issues.add_milestone_at = `added this to the <b>%s</b> milestone %s` issues.add_milestone_at = `added this to the <b>%s</b> milestone %s`
issues.change_milestone_at = `modified the milestone from <b>%s</b> to <b>%s</b> %s` issues.change_milestone_at = `modified the milestone from <b>%s</b> to <b>%s</b> %s`
issues.remove_milestone_at = `removed this from the <b>%s</b> milestone %s` issues.remove_milestone_at = `removed this from the <b>%s</b> milestone %s`
issues.deleted_milestone = `(deleted)`
issues.self_assign_at = `self-assigned this %s` issues.self_assign_at = `self-assigned this %s`
issues.add_assignee_at = `was assigned by <b>%s</b> %s` issues.add_assignee_at = `was assigned by <b>%s</b> %s`
issues.remove_assignee_at = `removed their assignment %s` issues.remove_assignee_at = `removed their assignment %s`

View File

@@ -949,6 +949,23 @@ footer .ui.language .menu {
#create-page-form form textarea { #create-page-form form textarea {
width: 50%!important; width: 50%!important;
} }
.signin .oauth2 div {
display: inline-block;
}
.signin .oauth2 div p {
margin: 10px 5px 0 0;
float: left;
}
.signin .oauth2 a {
margin-right: 5px;
}
.signin .oauth2 a:last-child {
margin-right: 0px;
}
.signin .oauth2 img {
width: 32px;
height: 32px;
}
.user.activate form, .user.activate form,
.user.forgot.password form, .user.forgot.password form,
.user.reset.password form, .user.reset.password form,
@@ -2742,6 +2759,10 @@ footer .ui.language .menu {
.user.notification .octicon.blue { .user.notification .octicon.blue {
color: #2185d0; color: #2185d0;
} }
.user.link-account:not(.icon) {
padding-top: 15px;
padding-bottom: 5px;
}
.dashboard { .dashboard {
padding-top: 15px; padding-top: 15px;
padding-bottom: 80px; padding-bottom: 80px;
@@ -2983,24 +3004,3 @@ footer .ui.language .menu {
.ui.user.list .item .description a:hover { .ui.user.list .item .description a:hover {
text-decoration: underline; text-decoration: underline;
} }
.user.link-account:not(.icon) {
padding-top: 15px;
padding-bottom: 5px;
}
.signin .oauth2 div {
display: inline-block;
}
.signin .oauth2 div p {
margin: 10px 5px 0 0;
float: left;
}
.signin .oauth2 a {
margin-right: 5px;
}
.signin .oauth2 a:last-child {
margin-right: 0px;
}
.signin .oauth2 img {
width: 32px;
height: 32px;
}

View File

@@ -5,11 +5,13 @@ jQuery.fn.autolink = function() {
.each(function() { .each(function() {
$(this).each(function() { $(this).each(function() {
if (re.test($(this).text())) if (re.test($(this).text()))
$(this).replaceWith( if($(this).parents().filter('code').length === 0) {
$("<span />").html( $(this).replaceWith(
this.nodeValue.replace(re, "<a href='$1'>$1</a>") $("<span />").html(
) this.nodeValue.replace(re, "<a href='$1'>$1</a>")
); )
);
};
}); });
}); });
}; };

View File

@@ -46,6 +46,27 @@
} }
} }
.signin {
.oauth2{
div {
display: inline-block;
p {
margin: 10px 5px 0 0;
float: left;
}
}
a {
margin-right: 5px;
&:last-child {
margin-right: 0px;
}
}
img {
width: 32px;
height: 32px;
}
}
}
.user.activate, .user.activate,
.user.forgot.password, .user.forgot.password,
.user.reset.password, .user.reset.password,

View File

@@ -114,4 +114,8 @@
} }
} }
} }
&.link-account:not(.icon) {
padding-top: 15px;
padding-bottom: 5px;
}
} }

View File

@@ -341,7 +341,7 @@ func RegisterRoutes(m *macaron.Macaron) {
Post(bind(api.CreateKeyOption{}), repo.CreateDeployKey) Post(bind(api.CreateKeyOption{}), repo.CreateDeployKey)
m.Combo("/:id").Get(repo.GetDeployKey). m.Combo("/:id").Get(repo.GetDeployKey).
Delete(repo.DeleteDeploykey) Delete(repo.DeleteDeploykey)
}) }, reqRepoWriter())
m.Group("/issues", func() { m.Group("/issues", func() {
m.Combo("").Get(repo.ListIssues).Post(bind(api.CreateIssueOption{}), repo.CreateIssue) m.Combo("").Get(repo.ListIssues).Post(bind(api.CreateIssueOption{}), repo.CreateIssue)
m.Group("/comments", func() { m.Group("/comments", func() {

View File

@@ -75,7 +75,7 @@ func TestAPI_RenderGFM(t *testing.T) {
<ul> <ul>
<li><a href="` + AppSubURL + `wiki/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li> <li><a href="` + AppSubURL + `wiki/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li>
<li><a href="` + AppSubURL + `wiki/Tips" rel="nofollow">Tips</a></li> <li><a href="` + AppSubURL + `wiki/Tips" rel="nofollow">Tips</a></li>
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>)<a href="https://github.com/ocornut/imgui/issues/786" rel="nofollow">#786</a></li> <li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) https://github.com/ocornut/imgui/issues/786</li>
</ul> </ul>
`, `,
// wine-staging wiki home extract: special wiki syntax, images // wine-staging wiki home extract: special wiki syntax, images

View File

@@ -49,6 +49,7 @@ func GlobalInit() {
if setting.InstallLock { if setting.InstallLock {
highlight.NewContext() highlight.NewContext()
markdown.InitMarkdown()
markdown.NewSanitizer() markdown.NewSanitizer()
if err := models.NewEngine(); err != nil { if err := models.NewEngine(); err != nil {
log.Fatal(4, "Failed to initialize ORM engine: %v", err) log.Fatal(4, "Failed to initialize ORM engine: %v", err)

View File

@@ -596,6 +596,16 @@ func ViewIssue(ctx *context.Context) {
ctx.Handle(500, "LoadMilestone", err) ctx.Handle(500, "LoadMilestone", err)
return return
} }
ghostMilestone := &models.Milestone{
ID: -1,
Name: ctx.Tr("repo.issues.deleted_milestone"),
}
if comment.OldMilestoneID > 0 && comment.OldMilestone == nil {
comment.OldMilestone = ghostMilestone
}
if comment.MilestoneID > 0 && comment.Milestone == nil {
comment.Milestone = ghostMilestone
}
} else if comment.Type == models.CommentTypeAssignees { } else if comment.Type == models.CommentTypeAssignees {
if err = comment.LoadAssignees(); err != nil { if err = comment.LoadAssignees(); err != nil {
ctx.Handle(500, "LoadAssignees", err) ctx.Handle(500, "LoadAssignees", err)

View File

@@ -78,7 +78,7 @@
{{end}} {{end}}
</h4> </h4>
<div class="ui attached table segment"> <div class="ui attached table segment">
{{if not $file.IsRenamed}} {{if ne $file.Type 4}}
{{$isImage := (call $.IsImageFile $file.Name)}} {{$isImage := (call $.IsImageFile $file.Name)}}
{{if and $isImage}} {{if and $isImage}}
<div class="center"> <div class="center">