mirror of https://github.com/go-gitea/gitea
Integration test framework (#1290)
* Integration test framework * udpate drone sign * Formatting fixes and move router.go to routers/ * update sign for dronepull/1298/merge
parent
3012971e92
commit
c58708d3ee
@ -1 +1 @@ |
|||||||
eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9zcnYvYXBwCiAgcGF0aDogc3JjL2NvZGUuZ2l0ZWEuaW8vZ2l0ZWEKCnBpcGVsaW5lOgogIGNsb25lOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0CiAgICB0YWdzOiB0cnVlCgogIHRlc3Q6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgVEFHUzogYmluZGF0YSBzcWxpdGUKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gYXBrIC1VIGFkZCBvcGVuc3NoLWNsaWVudAogICAgICAtIG1ha2UgY2xlYW4KICAgICAgLSBtYWtlIGdlbmVyYXRlCiAgICAgIC0gbWFrZSB2ZXQKICAgICAgLSBtYWtlIGxpbnQKICAgICAgLSBtYWtlIHRlc3QtdmVuZG9yCiAgICAgIC0gbWFrZSB0ZXN0CiAgICAgIC0gbWFrZSBidWlsZAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICB0ZXN0LW15c3FsOgogICAgaW1hZ2U6IHdlYmhpcHBpZS9nb2xhbmc6ZWRnZQogICAgcHVsbDogdHJ1ZQogICAgZW52aXJvbm1lbnQ6CiAgICAgIFRBR1M6IGJpbmRhdGEKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gbWFrZSB0ZXN0LW15c3FsCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIHRlc3QtcGdzcWw6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgVEFHUzogYmluZGF0YQogICAgICBHT1BBVEg6IC9zcnYvYXBwCiAgICBjb21tYW5kczoKICAgICAgLSBtYWtlIHRlc3QtcGdzcWwKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2gsIHRhZywgcHVsbF9yZXF1ZXN0IF0KCiAgc3RhdGljOgogICAgaW1hZ2U6IGthcmFsYWJlL3hnby1sYXRlc3Q6bGF0ZXN0CiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgVEFHUzogYmluZGF0YSBzcWxpdGUKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gbWFrZSByZWxlYXNlCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIGNvdmVyYWdlOgogICAgaW1hZ2U6IHBsdWdpbnMvY292ZXJhZ2UKICAgIHNlcnZlcjogaHR0cHM6Ly9jb3ZlcmFnZS5naXRlYS5pbwogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICBkb2NrZXI6CiAgICBpbWFnZTogcGx1Z2lucy9kb2NrZXIKICAgIHJlcG86IGdpdGVhL2dpdGVhCiAgICB0YWdzOiBbICcke0RST05FX1RBRyMjdn0nIF0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHRhZyBdCiAgICAgIGJyYW5jaDogWyByZWZzL3RhZ3MvKiBdCgogIGRvY2tlcjoKICAgIGltYWdlOiBwbHVnaW5zL2RvY2tlcgogICAgcmVwbzogZ2l0ZWEvZ2l0ZWEKICAgIHRhZ3M6IFsgJyR7RFJPTkVfQlJBTkNIIyNyZWxlYXNlL3Z9JyBdCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIHJlbGVhc2UvKiBdCgogIGRvY2tlcjoKICAgIGltYWdlOiBwbHVnaW5zL2RvY2tlcgogICAgcmVwbzogZ2l0ZWEvZ2l0ZWEKICAgIHRhZ3M6IFsgJ2xhdGVzdCcgXQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCiAgICAgIGJyYW5jaDogWyBtYXN0ZXIgXQoKICByZWxlYXNlOgogICAgaW1hZ2U6IHBsdWdpbnMvczMKICAgIHBhdGhfc3R5bGU6IHRydWUKICAgIHN0cmlwX3ByZWZpeDogZGlzdC9yZWxlYXNlLwogICAgc291cmNlOiBkaXN0L3JlbGVhc2UvKgogICAgdGFyZ2V0OiAvZ2l0ZWEvJHtEUk9ORV9UQUcjI3Z9CiAgICB3aGVuOgogICAgICBldmVudDogWyB0YWcgXQogICAgICBicmFuY2g6IFsgcmVmcy90YWdzLyogXQoKICByZWxlYXNlOgogICAgaW1hZ2U6IHBsdWdpbnMvczMKICAgIHBhdGhfc3R5bGU6IHRydWUKICAgIHN0cmlwX3ByZWZpeDogZGlzdC9yZWxlYXNlLwogICAgc291cmNlOiBkaXN0L3JlbGVhc2UvKgogICAgdGFyZ2V0OiAvZ2l0ZWEvJHtEUk9ORV9CUkFOQ0gjI3JlbGVhc2Uvdn0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQogICAgICBicmFuY2g6IFsgcmVsZWFzZS8qIF0KCiAgcmVsZWFzZToKICAgIGltYWdlOiBwbHVnaW5zL3MzCiAgICBwYXRoX3N0eWxlOiB0cnVlCiAgICBzdHJpcF9wcmVmaXg6IGRpc3QvcmVsZWFzZS8KICAgIHNvdXJjZTogZGlzdC9yZWxlYXNlLyoKICAgIHRhcmdldDogL2dpdGVhL21hc3RlcgogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCiAgICAgIGJyYW5jaDogWyBtYXN0ZXIgXQoKICBnaXRodWI6CiAgICBpbWFnZTogcGx1Z2lucy9naXRodWItcmVsZWFzZQogICAgZmlsZXM6CiAgICAgIC0gZGlzdC9yZWxlYXNlLyoKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHRhZyBdCiAgICAgIGJyYW5jaDogWyByZWZzL3RhZ3MvKiBdCgogIGdpdHRlcjoKICAgIGltYWdlOiBwbHVnaW5zL2dpdHRlcgoKc2VydmljZXM6CiAgbXlzcWw6CiAgICBpbWFnZTogbXlzcWw6NS43CiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBNWVNRTF9EQVRBQkFTRT10ZXN0CiAgICAgIC0gTVlTUUxfQUxMT1dfRU1QVFlfUEFTU1dPUkQ9eWVzCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIHBnc3FsOgogICAgaW1hZ2U6IHBvc3RncmVzOjkuNQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfREI9dGVzdAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQo.C4Zwhff5mceN64UpDsVF263WmpDTnMMY0pcbB6KKdd0 |
eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9zcnYvYXBwCiAgcGF0aDogc3JjL2NvZGUuZ2l0ZWEuaW8vZ2l0ZWEKCnBpcGVsaW5lOgogIGNsb25lOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0CiAgICB0YWdzOiB0cnVlCgogIHRlc3Q6CiAgICBpbWFnZTogd2ViaGlwcGllL2dvbGFuZzplZGdlCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgVEFHUzogYmluZGF0YSBzcWxpdGUKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gYXBrIC1VIGFkZCBvcGVuc3NoLWNsaWVudAogICAgICAtIG1ha2UgY2xlYW4KICAgICAgLSBtYWtlIGdlbmVyYXRlCiAgICAgIC0gbWFrZSB2ZXQKICAgICAgLSBtYWtlIGxpbnQKICAgICAgLSBtYWtlIHRlc3QtdmVuZG9yCiAgICAgIC0gbWFrZSB0ZXN0CiAgICAgIC0gbWFrZSBidWlsZAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICB0ZXN0LXNxbGl0ZToKICAgIGltYWdlOiB3ZWJoaXBwaWUvZ29sYW5nOmVkZ2UKICAgIHB1bGw6IHRydWUKICAgIGVudmlyb25tZW50OgogICAgICBUQUdTOiBiaW5kYXRhCiAgICAgIEdPUEFUSDogL3Nydi9hcHAKICAgIGNvbW1hbmRzOgogICAgICAtIG1ha2UgdGVzdC1zcWxpdGUKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2gsIHRhZywgcHVsbF9yZXF1ZXN0IF0KCiAgdGVzdC1teXNxbDoKICAgIGltYWdlOiB3ZWJoaXBwaWUvZ29sYW5nOmVkZ2UKICAgIHB1bGw6IHRydWUKICAgIGVudmlyb25tZW50OgogICAgICBUQUdTOiBiaW5kYXRhCiAgICAgIEdPUEFUSDogL3Nydi9hcHAKICAgIGNvbW1hbmRzOgogICAgICAtIGVjaG8gbWFrZSB0ZXN0LW15c3FsICMgTm90IHJlYWR5IHlldAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICB0ZXN0LXBnc3FsOgogICAgaW1hZ2U6IHdlYmhpcHBpZS9nb2xhbmc6ZWRnZQogICAgcHVsbDogdHJ1ZQogICAgZW52aXJvbm1lbnQ6CiAgICAgIFRBR1M6IGJpbmRhdGEKICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gZWNobyBtYWtlIHRlc3QtcHFzcWwgIyBOb3QgcmVhZHkgeWV0CiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoLCB0YWcsIHB1bGxfcmVxdWVzdCBdCgogIHN0YXRpYzoKICAgIGltYWdlOiBrYXJhbGFiZS94Z28tbGF0ZXN0OmxhdGVzdAogICAgcHVsbDogdHJ1ZQogICAgZW52aXJvbm1lbnQ6CiAgICAgIFRBR1M6IGJpbmRhdGEgc3FsaXRlCiAgICAgIEdPUEFUSDogL3Nydi9hcHAKICAgIGNvbW1hbmRzOgogICAgICAtIG1ha2UgcmVsZWFzZQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICBjb3ZlcmFnZToKICAgIGltYWdlOiBwbHVnaW5zL2NvdmVyYWdlCiAgICBzZXJ2ZXI6IGh0dHBzOi8vY292ZXJhZ2UuZ2l0ZWEuaW8KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2gsIHRhZywgcHVsbF9yZXF1ZXN0IF0KCiAgZG9ja2VyOgogICAgaW1hZ2U6IHBsdWdpbnMvZG9ja2VyCiAgICByZXBvOiBnaXRlYS9naXRlYQogICAgdGFnczogWyAnJHtEUk9ORV9UQUcjI3Z9JyBdCiAgICB3aGVuOgogICAgICBldmVudDogWyB0YWcgXQogICAgICBicmFuY2g6IFsgcmVmcy90YWdzLyogXQoKICBkb2NrZXI6CiAgICBpbWFnZTogcGx1Z2lucy9kb2NrZXIKICAgIHJlcG86IGdpdGVhL2dpdGVhCiAgICB0YWdzOiBbICcke0RST05FX0JSQU5DSCMjcmVsZWFzZS92fScgXQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCBdCiAgICAgIGJyYW5jaDogWyByZWxlYXNlLyogXQoKICBkb2NrZXI6CiAgICBpbWFnZTogcGx1Z2lucy9kb2NrZXIKICAgIHJlcG86IGdpdGVhL2dpdGVhCiAgICB0YWdzOiBbICdsYXRlc3QnIF0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQogICAgICBicmFuY2g6IFsgbWFzdGVyIF0KCiAgcmVsZWFzZToKICAgIGltYWdlOiBwbHVnaW5zL3MzCiAgICBwYXRoX3N0eWxlOiB0cnVlCiAgICBzdHJpcF9wcmVmaXg6IGRpc3QvcmVsZWFzZS8KICAgIHNvdXJjZTogZGlzdC9yZWxlYXNlLyoKICAgIHRhcmdldDogL2dpdGVhLyR7RFJPTkVfVEFHIyN2fQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgdGFnIF0KICAgICAgYnJhbmNoOiBbIHJlZnMvdGFncy8qIF0KCiAgcmVsZWFzZToKICAgIGltYWdlOiBwbHVnaW5zL3MzCiAgICBwYXRoX3N0eWxlOiB0cnVlCiAgICBzdHJpcF9wcmVmaXg6IGRpc3QvcmVsZWFzZS8KICAgIHNvdXJjZTogZGlzdC9yZWxlYXNlLyoKICAgIHRhcmdldDogL2dpdGVhLyR7RFJPTkVfQlJBTkNIIyNyZWxlYXNlL3Z9CiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIHJlbGVhc2UvKiBdCgogIHJlbGVhc2U6CiAgICBpbWFnZTogcGx1Z2lucy9zMwogICAgcGF0aF9zdHlsZTogdHJ1ZQogICAgc3RyaXBfcHJlZml4OiBkaXN0L3JlbGVhc2UvCiAgICBzb3VyY2U6IGRpc3QvcmVsZWFzZS8qCiAgICB0YXJnZXQ6IC9naXRlYS9tYXN0ZXIKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQogICAgICBicmFuY2g6IFsgbWFzdGVyIF0KCiAgZ2l0aHViOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0aHViLXJlbGVhc2UKICAgIGZpbGVzOgogICAgICAtIGRpc3QvcmVsZWFzZS8qCiAgICB3aGVuOgogICAgICBldmVudDogWyB0YWcgXQogICAgICBicmFuY2g6IFsgcmVmcy90YWdzLyogXQoKICBnaXR0ZXI6CiAgICBpbWFnZTogcGx1Z2lucy9naXR0ZXIKCnNlcnZpY2VzOgogIG15c3FsOgogICAgaW1hZ2U6IG15c3FsOjUuNwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gTVlTUUxfREFUQUJBU0U9dGVzdAogICAgICAtIE1ZU1FMX0FMTE9XX0VNUFRZX1BBU1NXT1JEPXllcwogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICBwZ3NxbDoKICAgIGltYWdlOiBwb3N0Z3Jlczo5LjUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX0RCPXRlc3QKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2gsIHRhZywgcHVsbF9yZXF1ZXN0IF0K.dA2VK6LdoPXvBTYAUywWervhOZmgOjU32uiiPrBbVdQ |
@ -1,91 +0,0 @@ |
|||||||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package integration |
|
||||||
|
|
||||||
import ( |
|
||||||
"fmt" |
|
||||||
"net/http" |
|
||||||
"os" |
|
||||||
"os/user" |
|
||||||
"testing" |
|
||||||
"time" |
|
||||||
|
|
||||||
"code.gitea.io/gitea/integrations/internal/utils" |
|
||||||
) |
|
||||||
|
|
||||||
// The HTTP port listened by the Gitea server.
|
|
||||||
const ServerHTTPPort = "3001" |
|
||||||
|
|
||||||
const _RetryLimit = 10 |
|
||||||
|
|
||||||
func makeSimpleSettings(user, port string) map[string][]string { |
|
||||||
return map[string][]string{ |
|
||||||
"db_type": {"SQLite3"}, |
|
||||||
"db_host": {"localhost"}, |
|
||||||
"db_path": {"data/gitea.db"}, |
|
||||||
"app_name": {"Gitea: Git with a cup of tea"}, |
|
||||||
"repo_root_path": {"repositories"}, |
|
||||||
"run_user": {user}, |
|
||||||
"domain": {"localhost"}, |
|
||||||
"ssh_port": {"22"}, |
|
||||||
"http_port": {port}, |
|
||||||
"app_url": {"http://localhost:" + port}, |
|
||||||
"log_root_path": {"log"}, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func install(t *utils.T) error { |
|
||||||
var r *http.Response |
|
||||||
var err error |
|
||||||
|
|
||||||
for i := 1; i <= _RetryLimit; i++ { |
|
||||||
|
|
||||||
r, err = http.Get("http://:" + ServerHTTPPort + "/") |
|
||||||
if err == nil { |
|
||||||
fmt.Fprintln(os.Stderr) |
|
||||||
break |
|
||||||
} |
|
||||||
|
|
||||||
// Give the server some amount of time to warm up.
|
|
||||||
time.Sleep(100 * time.Millisecond) |
|
||||||
fmt.Fprint(os.Stderr, ".") |
|
||||||
} |
|
||||||
|
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
defer r.Body.Close() |
|
||||||
|
|
||||||
_user, err := user.Current() |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
settings := makeSimpleSettings(_user.Username, ServerHTTPPort) |
|
||||||
r, err = http.PostForm("http://:"+ServerHTTPPort+"/install", settings) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
defer r.Body.Close() |
|
||||||
|
|
||||||
if r.StatusCode != http.StatusOK { |
|
||||||
return fmt.Errorf("'/install': %s", r.Status) |
|
||||||
} |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
func TestInstall(t *testing.T) { |
|
||||||
conf := utils.Config{ |
|
||||||
Program: "../gitea", |
|
||||||
WorkDir: "", |
|
||||||
Args: []string{"web", "--port", ServerHTTPPort}, |
|
||||||
LogFile: os.Stderr, |
|
||||||
} |
|
||||||
|
|
||||||
if err := utils.New(t, &conf).RunTest(install); err != nil { |
|
||||||
t.Fatal(err) |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,92 @@ |
|||||||
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package integrations |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"fmt" |
||||||
|
"io" |
||||||
|
"net/http" |
||||||
|
"os" |
||||||
|
"testing" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/models" |
||||||
|
"code.gitea.io/gitea/modules/setting" |
||||||
|
"code.gitea.io/gitea/routers" |
||||||
|
"code.gitea.io/gitea/routers/routes" |
||||||
|
|
||||||
|
"gopkg.in/macaron.v1" |
||||||
|
"gopkg.in/testfixtures.v2" |
||||||
|
) |
||||||
|
|
||||||
|
var mac *macaron.Macaron |
||||||
|
|
||||||
|
func TestMain(m *testing.M) { |
||||||
|
appIniPath := os.Getenv("GITEA_CONF") |
||||||
|
if appIniPath == "" { |
||||||
|
fmt.Println("Environment variable $GITEA_CONF not set") |
||||||
|
os.Exit(1) |
||||||
|
} |
||||||
|
setting.CustomConf = appIniPath |
||||||
|
routers.GlobalInit() |
||||||
|
mac = routes.NewMacaron() |
||||||
|
routes.RegisterRoutes(mac) |
||||||
|
|
||||||
|
var helper testfixtures.Helper |
||||||
|
if setting.UseMySQL { |
||||||
|
helper = &testfixtures.MySQL{} |
||||||
|
} else if setting.UsePostgreSQL { |
||||||
|
helper = &testfixtures.PostgreSQL{} |
||||||
|
} else if setting.UseSQLite3 { |
||||||
|
helper = &testfixtures.SQLite{} |
||||||
|
} else { |
||||||
|
fmt.Println("Unsupported RDBMS for integration tests") |
||||||
|
os.Exit(1) |
||||||
|
} |
||||||
|
|
||||||
|
err := models.InitFixtures( |
||||||
|
helper, |
||||||
|
"integrations/gitea-integration/fixtures/", |
||||||
|
) |
||||||
|
if err != nil { |
||||||
|
fmt.Printf("Error initializing test database: %v\n", err) |
||||||
|
os.Exit(1) |
||||||
|
} |
||||||
|
os.Exit(m.Run()) |
||||||
|
} |
||||||
|
|
||||||
|
type TestResponseWriter struct { |
||||||
|
HeaderCode int |
||||||
|
Writer io.Writer |
||||||
|
} |
||||||
|
|
||||||
|
func (w *TestResponseWriter) Header() http.Header { |
||||||
|
return make(map[string][]string) |
||||||
|
} |
||||||
|
|
||||||
|
func (w *TestResponseWriter) Write(b []byte) (int, error) { |
||||||
|
return w.Writer.Write(b) |
||||||
|
} |
||||||
|
|
||||||
|
func (w *TestResponseWriter) WriteHeader(n int) { |
||||||
|
w.HeaderCode = n |
||||||
|
} |
||||||
|
|
||||||
|
type TestResponse struct { |
||||||
|
HeaderCode int |
||||||
|
Body []byte |
||||||
|
} |
||||||
|
|
||||||
|
func MakeRequest(req *http.Request) *TestResponse { |
||||||
|
buffer := bytes.NewBuffer(nil) |
||||||
|
respWriter := &TestResponseWriter{ |
||||||
|
Writer: buffer, |
||||||
|
} |
||||||
|
mac.ServeHTTP(respWriter, req) |
||||||
|
return &TestResponse{ |
||||||
|
HeaderCode: respWriter.HeaderCode, |
||||||
|
Body: buffer.Bytes(), |
||||||
|
} |
||||||
|
} |
@ -1,156 +0,0 @@ |
|||||||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package utils |
|
||||||
|
|
||||||
import ( |
|
||||||
"errors" |
|
||||||
"fmt" |
|
||||||
"io" |
|
||||||
"io/ioutil" |
|
||||||
"log" |
|
||||||
"net/http" |
|
||||||
"os" |
|
||||||
"os/exec" |
|
||||||
"path/filepath" |
|
||||||
"syscall" |
|
||||||
"testing" |
|
||||||
) |
|
||||||
|
|
||||||
// T wraps testing.T and the configurations of the testing instance.
|
|
||||||
type T struct { |
|
||||||
*testing.T |
|
||||||
Config *Config |
|
||||||
} |
|
||||||
|
|
||||||
// New create an instance of T
|
|
||||||
func New(t *testing.T, c *Config) *T { |
|
||||||
return &T{T: t, Config: c} |
|
||||||
} |
|
||||||
|
|
||||||
// Config Settings of the testing program
|
|
||||||
type Config struct { |
|
||||||
// The executable path of the tested program.
|
|
||||||
Program string |
|
||||||
// Working directory prepared for the tested program.
|
|
||||||
// If empty, a directory named with random suffixes is picked, and created under the platform-dependent default temporary directory.
|
|
||||||
// The directory will be removed when the test finishes.
|
|
||||||
WorkDir string |
|
||||||
// Command-line arguments passed to the tested program.
|
|
||||||
Args []string |
|
||||||
|
|
||||||
// Where to redirect the stdout/stderr to. For debugging purposes.
|
|
||||||
LogFile *os.File |
|
||||||
} |
|
||||||
|
|
||||||
func redirect(cmd *exec.Cmd, f *os.File) error { |
|
||||||
stdout, err := cmd.StdoutPipe() |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
stderr, err := cmd.StderrPipe() |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
go io.Copy(f, stdout) |
|
||||||
go io.Copy(f, stderr) |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
// RunTest Helper function for setting up a running Gitea server for functional testing and then gracefully terminating it.
|
|
||||||
func (t *T) RunTest(tests ...func(*T) error) (err error) { |
|
||||||
if t.Config.Program == "" { |
|
||||||
return errors.New("Need input file") |
|
||||||
} |
|
||||||
|
|
||||||
path, err := filepath.Abs(t.Config.Program) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
workdir := t.Config.WorkDir |
|
||||||
if workdir == "" { |
|
||||||
workdir, err = ioutil.TempDir(os.TempDir(), "gitea_tests-") |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
defer os.RemoveAll(workdir) |
|
||||||
} |
|
||||||
|
|
||||||
newpath := filepath.Join(workdir, filepath.Base(path)) |
|
||||||
if err := os.Symlink(path, newpath); err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
log.Printf("Starting the server: %s args:%s workdir:%s", newpath, t.Config.Args, workdir) |
|
||||||
|
|
||||||
cmd := exec.Command(newpath, t.Config.Args...) |
|
||||||
cmd.Dir = workdir |
|
||||||
|
|
||||||
if t.Config.LogFile != nil && testing.Verbose() { |
|
||||||
if err := redirect(cmd, t.Config.LogFile); err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
log.Println("Server started.") |
|
||||||
|
|
||||||
defer func() { |
|
||||||
// Do not early return. We have to call Wait anyway.
|
|
||||||
_ = cmd.Process.Signal(syscall.SIGTERM) |
|
||||||
|
|
||||||
if _err := cmd.Wait(); _err != nil { |
|
||||||
if _err.Error() != "signal: terminated" { |
|
||||||
err = _err |
|
||||||
return |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
log.Println("Server exited") |
|
||||||
}() |
|
||||||
|
|
||||||
for _, fn := range tests { |
|
||||||
if err := fn(t); err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Note that the return value 'err' may be updated by the 'defer' statement before despite it's returning nil here.
|
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
// GetAndPost provides a convenient helper function for testing an HTTP endpoint with GET and POST method.
|
|
||||||
// The function sends GET first and then POST with the given form.
|
|
||||||
func GetAndPost(url string, form map[string][]string) error { |
|
||||||
var err error |
|
||||||
var r *http.Response |
|
||||||
|
|
||||||
r, err = http.Get(url) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
defer r.Body.Close() |
|
||||||
|
|
||||||
if r.StatusCode != http.StatusOK { |
|
||||||
return fmt.Errorf("GET '%s': %s", url, r.Status) |
|
||||||
} |
|
||||||
|
|
||||||
r, err = http.PostForm(url, form) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
defer r.Body.Close() |
|
||||||
|
|
||||||
if r.StatusCode != http.StatusOK { |
|
||||||
return fmt.Errorf("POST '%s': %s", url, r.Status) |
|
||||||
} |
|
||||||
|
|
||||||
return nil |
|
||||||
} |
|
@ -0,0 +1,56 @@ |
|||||||
|
APP_NAME = Gitea: Git with a cup of tea |
||||||
|
RUN_MODE = prod |
||||||
|
|
||||||
|
[database] |
||||||
|
DB_TYPE = mysql |
||||||
|
HOST = 127.0.0.1:3306 |
||||||
|
NAME = testgitea |
||||||
|
USER = root |
||||||
|
PASSWD = |
||||||
|
SSL_MODE = disable |
||||||
|
PATH = data/gitea.db |
||||||
|
|
||||||
|
[repository] |
||||||
|
ROOT = integrations/gitea-integration/gitea-repositories |
||||||
|
|
||||||
|
[server] |
||||||
|
SSH_DOMAIN = localhost |
||||||
|
HTTP_PORT = 3000 |
||||||
|
ROOT_URL = http://localhost:3000/ |
||||||
|
DISABLE_SSH = false |
||||||
|
SSH_PORT = 22 |
||||||
|
LFS_START_SERVER = false |
||||||
|
OFFLINE_MODE = false |
||||||
|
|
||||||
|
[mailer] |
||||||
|
ENABLED = false |
||||||
|
|
||||||
|
[service] |
||||||
|
REGISTER_EMAIL_CONFIRM = false |
||||||
|
ENABLE_NOTIFY_MAIL = false |
||||||
|
DISABLE_REGISTRATION = false |
||||||
|
ENABLE_CAPTCHA = false |
||||||
|
REQUIRE_SIGNIN_VIEW = false |
||||||
|
DEFAULT_KEEP_EMAIL_PRIVATE = false |
||||||
|
NO_REPLY_ADDRESS = noreply.example.org |
||||||
|
|
||||||
|
[picture] |
||||||
|
DISABLE_GRAVATAR = false |
||||||
|
ENABLE_FEDERATED_AVATAR = false |
||||||
|
|
||||||
|
[session] |
||||||
|
PROVIDER = file |
||||||
|
|
||||||
|
[log] |
||||||
|
MODE = console,file |
||||||
|
|
||||||
|
[log.console] |
||||||
|
LEVEL = Warn |
||||||
|
|
||||||
|
[log.file] |
||||||
|
LEVEL = Info |
||||||
|
ROOT_PATH = log |
||||||
|
|
||||||
|
[security] |
||||||
|
INSTALL_LOCK = true |
||||||
|
SECRET_KEY = 9pCviYTWSb |
@ -0,0 +1,56 @@ |
|||||||
|
APP_NAME = Gitea: Git with a cup of tea |
||||||
|
RUN_MODE = prod |
||||||
|
|
||||||
|
[database] |
||||||
|
DB_TYPE = postgres |
||||||
|
HOST = 127.0.0.1:5432 |
||||||
|
NAME = testgitea |
||||||
|
USER = postgres |
||||||
|
PASSWD = postgres |
||||||
|
SSL_MODE = disable |
||||||
|
PATH = data/gitea.db |
||||||
|
|
||||||
|
[repository] |
||||||
|
ROOT = integrations/gitea-integration/gitea-repositories |
||||||
|
|
||||||
|
[server] |
||||||
|
SSH_DOMAIN = localhost |
||||||
|
HTTP_PORT = 3000 |
||||||
|
ROOT_URL = http://localhost:3000/ |
||||||
|
DISABLE_SSH = false |
||||||
|
SSH_PORT = 22 |
||||||
|
LFS_START_SERVER = false |
||||||
|
OFFLINE_MODE = false |
||||||
|
|
||||||
|
[mailer] |
||||||
|
ENABLED = false |
||||||
|
|
||||||
|
[service] |
||||||
|
REGISTER_EMAIL_CONFIRM = false |
||||||
|
ENABLE_NOTIFY_MAIL = false |
||||||
|
DISABLE_REGISTRATION = false |
||||||
|
ENABLE_CAPTCHA = false |
||||||
|
REQUIRE_SIGNIN_VIEW = false |
||||||
|
DEFAULT_KEEP_EMAIL_PRIVATE = false |
||||||
|
NO_REPLY_ADDRESS = noreply.example.org |
||||||
|
|
||||||
|
[picture] |
||||||
|
DISABLE_GRAVATAR = false |
||||||
|
ENABLE_FEDERATED_AVATAR = false |
||||||
|
|
||||||
|
[session] |
||||||
|
PROVIDER = file |
||||||
|
|
||||||
|
[log] |
||||||
|
MODE = console,file |
||||||
|
|
||||||
|
[log.console] |
||||||
|
LEVEL = Warn |
||||||
|
|
||||||
|
[log.file] |
||||||
|
LEVEL = Info |
||||||
|
ROOT_PATH = log |
||||||
|
|
||||||
|
[security] |
||||||
|
INSTALL_LOCK = true |
||||||
|
SECRET_KEY = 9pCviYTWSb |
@ -0,0 +1,58 @@ |
|||||||
|
APP_NAME = Gitea: Git with a cup of tea |
||||||
|
RUN_MODE = prod |
||||||
|
|
||||||
|
[database] |
||||||
|
DB_TYPE = sqlite3 |
||||||
|
HOST = 127.0.0.1:3306 |
||||||
|
NAME = testgitea |
||||||
|
USER = gitea |
||||||
|
PASSWD = |
||||||
|
SSL_MODE = disable |
||||||
|
PATH = :memory: |
||||||
|
|
||||||
|
[repository] |
||||||
|
ROOT = integrations/gitea-integration/gitea-repositories |
||||||
|
|
||||||
|
[server] |
||||||
|
SSH_DOMAIN = localhost |
||||||
|
HTTP_PORT = 3000 |
||||||
|
ROOT_URL = http://localhost:3000/ |
||||||
|
DISABLE_SSH = false |
||||||
|
SSH_PORT = 22 |
||||||
|
LFS_START_SERVER = false |
||||||
|
OFFLINE_MODE = false |
||||||
|
|
||||||
|
[mailer] |
||||||
|
ENABLED = false |
||||||
|
|
||||||
|
[service] |
||||||
|
REGISTER_EMAIL_CONFIRM = false |
||||||
|
ENABLE_NOTIFY_MAIL = false |
||||||
|
DISABLE_REGISTRATION = false |
||||||
|
ENABLE_CAPTCHA = false |
||||||
|
REQUIRE_SIGNIN_VIEW = false |
||||||
|
DEFAULT_KEEP_EMAIL_PRIVATE = false |
||||||
|
NO_REPLY_ADDRESS = noreply.example.org |
||||||
|
|
||||||
|
[picture] |
||||||
|
DISABLE_GRAVATAR = false |
||||||
|
ENABLE_FEDERATED_AVATAR = false |
||||||
|
|
||||||
|
[session] |
||||||
|
PROVIDER = file |
||||||
|
|
||||||
|
[log] |
||||||
|
MODE = console,file |
||||||
|
|
||||||
|
[log.console] |
||||||
|
LEVEL = Warn |
||||||
|
|
||||||
|
[log.file] |
||||||
|
LEVEL = Info |
||||||
|
ROOT_PATH = log |
||||||
|
|
||||||
|
[security] |
||||||
|
INSTALL_LOCK = true |
||||||
|
SECRET_KEY = 9pCviYTWSb |
||||||
|
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8 |
||||||
|
|
@ -0,0 +1,32 @@ |
|||||||
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package integrations |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
"testing" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/models" |
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert" |
||||||
|
) |
||||||
|
|
||||||
|
func TestViewRepo(t *testing.T) { |
||||||
|
assert.NoError(t, models.LoadFixtures()) |
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "/user1/repo1", nil) |
||||||
|
assert.NoError(t, err) |
||||||
|
resp := MakeRequest(req) |
||||||
|
assert.EqualValues(t, http.StatusOK, resp.HeaderCode) |
||||||
|
} |
||||||
|
|
||||||
|
func TestViewUser(t *testing.T) { |
||||||
|
assert.NoError(t, models.LoadFixtures()) |
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "/user1", nil) |
||||||
|
assert.NoError(t, err) |
||||||
|
resp := MakeRequest(req) |
||||||
|
assert.EqualValues(t, http.StatusOK, resp.HeaderCode) |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package models |
||||||
|
|
||||||
|
import ( |
||||||
|
"gopkg.in/testfixtures.v2" |
||||||
|
) |
||||||
|
|
||||||
|
var fixtures *testfixtures.Context |
||||||
|
|
||||||
|
// InitFixtures initialize test fixtures for a test database
|
||||||
|
func InitFixtures(helper testfixtures.Helper, dir string) (err error) { |
||||||
|
testfixtures.SkipDatabaseNameCheck(true) |
||||||
|
fixtures, err = testfixtures.NewFolder(x.DB().DB, helper, dir) |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
// LoadFixtures load fixtures for a test database
|
||||||
|
func LoadFixtures() error { |
||||||
|
return fixtures.Load() |
||||||
|
} |
@ -0,0 +1,645 @@ |
|||||||
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package routes |
||||||
|
|
||||||
|
import ( |
||||||
|
"os" |
||||||
|
"path" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/models" |
||||||
|
"code.gitea.io/gitea/modules/auth" |
||||||
|
"code.gitea.io/gitea/modules/context" |
||||||
|
"code.gitea.io/gitea/modules/lfs" |
||||||
|
"code.gitea.io/gitea/modules/log" |
||||||
|
"code.gitea.io/gitea/modules/options" |
||||||
|
"code.gitea.io/gitea/modules/public" |
||||||
|
"code.gitea.io/gitea/modules/setting" |
||||||
|
"code.gitea.io/gitea/modules/templates" |
||||||
|
"code.gitea.io/gitea/modules/validation" |
||||||
|
"code.gitea.io/gitea/routers" |
||||||
|
"code.gitea.io/gitea/routers/admin" |
||||||
|
apiv1 "code.gitea.io/gitea/routers/api/v1" |
||||||
|
"code.gitea.io/gitea/routers/dev" |
||||||
|
"code.gitea.io/gitea/routers/org" |
||||||
|
"code.gitea.io/gitea/routers/private" |
||||||
|
"code.gitea.io/gitea/routers/repo" |
||||||
|
"code.gitea.io/gitea/routers/user" |
||||||
|
|
||||||
|
"github.com/go-macaron/binding" |
||||||
|
"github.com/go-macaron/cache" |
||||||
|
"github.com/go-macaron/captcha" |
||||||
|
"github.com/go-macaron/csrf" |
||||||
|
"github.com/go-macaron/gzip" |
||||||
|
"github.com/go-macaron/i18n" |
||||||
|
"github.com/go-macaron/session" |
||||||
|
"github.com/go-macaron/toolbox" |
||||||
|
"gopkg.in/macaron.v1" |
||||||
|
) |
||||||
|
|
||||||
|
// NewMacaron initializes Macaron instance.
|
||||||
|
func NewMacaron() *macaron.Macaron { |
||||||
|
m := macaron.New() |
||||||
|
if !setting.DisableRouterLog { |
||||||
|
m.Use(macaron.Logger()) |
||||||
|
} |
||||||
|
m.Use(macaron.Recovery()) |
||||||
|
if setting.EnableGzip { |
||||||
|
m.Use(gzip.Gziper()) |
||||||
|
} |
||||||
|
if setting.Protocol == setting.FCGI { |
||||||
|
m.SetURLPrefix(setting.AppSubURL) |
||||||
|
} |
||||||
|
m.Use(public.Custom( |
||||||
|
&public.Options{ |
||||||
|
SkipLogging: setting.DisableRouterLog, |
||||||
|
}, |
||||||
|
)) |
||||||
|
m.Use(public.Static( |
||||||
|
&public.Options{ |
||||||
|
Directory: path.Join(setting.StaticRootPath, "public"), |
||||||
|
SkipLogging: setting.DisableRouterLog, |
||||||
|
}, |
||||||
|
)) |
||||||
|
m.Use(macaron.Static( |
||||||
|
setting.AvatarUploadPath, |
||||||
|
macaron.StaticOptions{ |
||||||
|
Prefix: "avatars", |
||||||
|
SkipLogging: setting.DisableRouterLog, |
||||||
|
ETag: true, |
||||||
|
}, |
||||||
|
)) |
||||||
|
|
||||||
|
m.Use(templates.Renderer()) |
||||||
|
models.InitMailRender(templates.Mailer()) |
||||||
|
|
||||||
|
localeNames, err := options.Dir("locale") |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
log.Fatal(4, "Failed to list locale files: %v", err) |
||||||
|
} |
||||||
|
|
||||||
|
localFiles := make(map[string][]byte) |
||||||
|
|
||||||
|
for _, name := range localeNames { |
||||||
|
localFiles[name], err = options.Locale(name) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
log.Fatal(4, "Failed to load %s locale file. %v", name, err) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
m.Use(i18n.I18n(i18n.Options{ |
||||||
|
SubURL: setting.AppSubURL, |
||||||
|
Files: localFiles, |
||||||
|
Langs: setting.Langs, |
||||||
|
Names: setting.Names, |
||||||
|
DefaultLang: "en-US", |
||||||
|
Redirect: true, |
||||||
|
})) |
||||||
|
m.Use(cache.Cacher(cache.Options{ |
||||||
|
Adapter: setting.CacheAdapter, |
||||||
|
AdapterConfig: setting.CacheConn, |
||||||
|
Interval: setting.CacheInterval, |
||||||
|
})) |
||||||
|
m.Use(captcha.Captchaer(captcha.Options{ |
||||||
|
SubURL: setting.AppSubURL, |
||||||
|
})) |
||||||
|
m.Use(session.Sessioner(setting.SessionConfig)) |
||||||
|
m.Use(csrf.Csrfer(csrf.Options{ |
||||||
|
Secret: setting.SecretKey, |
||||||
|
Cookie: setting.CSRFCookieName, |
||||||
|
SetCookie: true, |
||||||
|
Header: "X-Csrf-Token", |
||||||
|
CookiePath: setting.AppSubURL, |
||||||
|
})) |
||||||
|
m.Use(toolbox.Toolboxer(m, toolbox.Options{ |
||||||
|
HealthCheckFuncs: []*toolbox.HealthCheckFuncDesc{ |
||||||
|
{ |
||||||
|
Desc: "Database connection", |
||||||
|
Func: models.Ping, |
||||||
|
}, |
||||||
|
}, |
||||||
|
})) |
||||||
|
m.Use(context.Contexter()) |
||||||
|
return m |
||||||
|
} |
||||||
|
|
||||||
|
// RegisterRoutes routes routes to Macaron
|
||||||
|
func RegisterRoutes(m *macaron.Macaron) { |
||||||
|
reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true}) |
||||||
|
ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView}) |
||||||
|
ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true}) |
||||||
|
reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true}) |
||||||
|
|
||||||
|
bindIgnErr := binding.BindIgnErr |
||||||
|
validation.AddBindingRules() |
||||||
|
|
||||||
|
m.Use(user.GetNotificationCount) |
||||||
|
|
||||||
|
// FIXME: not all routes need go through same middlewares.
|
||||||
|
// Especially some AJAX requests, we can reduce middleware number to improve performance.
|
||||||
|
// Routers.
|
||||||
|
// for health check
|
||||||
|
m.Head("/", func() string { |
||||||
|
return "" |
||||||
|
}) |
||||||
|
m.Get("/", ignSignIn, routers.Home) |
||||||
|
m.Group("/explore", func() { |
||||||
|
m.Get("", func(ctx *context.Context) { |
||||||
|
ctx.Redirect(setting.AppSubURL + "/explore/repos") |
||||||
|
}) |
||||||
|
m.Get("/repos", routers.ExploreRepos) |
||||||
|
m.Get("/users", routers.ExploreUsers) |
||||||
|
m.Get("/organizations", routers.ExploreOrganizations) |
||||||
|
}, ignSignIn) |
||||||
|
m.Combo("/install", routers.InstallInit).Get(routers.Install). |
||||||
|
Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost) |
||||||
|
m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues) |
||||||
|
|
||||||
|
// ***** START: User *****
|
||||||
|
m.Group("/user", func() { |
||||||
|
m.Get("/login", user.SignIn) |
||||||
|
m.Post("/login", bindIgnErr(auth.SignInForm{}), user.SignInPost) |
||||||
|
if setting.Service.EnableOpenIDSignIn { |
||||||
|
m.Combo("/login/openid"). |
||||||
|
Get(user.SignInOpenID). |
||||||
|
Post(bindIgnErr(auth.SignInOpenIDForm{}), user.SignInOpenIDPost) |
||||||
|
m.Group("/openid", func() { |
||||||
|
m.Combo("/connect"). |
||||||
|
Get(user.ConnectOpenID). |
||||||
|
Post(bindIgnErr(auth.ConnectOpenIDForm{}), user.ConnectOpenIDPost) |
||||||
|
m.Combo("/routes"). |
||||||
|
Get(user.RegisterOpenID). |
||||||
|
Post(bindIgnErr(auth.SignUpOpenIDForm{}), user.RegisterOpenIDPost) |
||||||
|
}) |
||||||
|
} |
||||||
|
m.Get("/sign_up", user.SignUp) |
||||||
|
m.Post("/sign_up", bindIgnErr(auth.RegisterForm{}), user.SignUpPost) |
||||||
|
m.Get("/reset_password", user.ResetPasswd) |
||||||
|
m.Post("/reset_password", user.ResetPasswdPost) |
||||||
|
m.Group("/oauth2", func() { |
||||||
|
m.Get("/:provider", user.SignInOAuth) |
||||||
|
m.Get("/:provider/callback", user.SignInOAuthCallback) |
||||||
|
}) |
||||||
|
m.Get("/link_account", user.LinkAccount) |
||||||
|
m.Post("/link_account_signin", bindIgnErr(auth.SignInForm{}), user.LinkAccountPostSignIn) |
||||||
|
m.Post("/link_account_signup", bindIgnErr(auth.RegisterForm{}), user.LinkAccountPostRegister) |
||||||
|
m.Group("/two_factor", func() { |
||||||
|
m.Get("", user.TwoFactor) |
||||||
|
m.Post("", bindIgnErr(auth.TwoFactorAuthForm{}), user.TwoFactorPost) |
||||||
|
m.Get("/scratch", user.TwoFactorScratch) |
||||||
|
m.Post("/scratch", bindIgnErr(auth.TwoFactorScratchAuthForm{}), user.TwoFactorScratchPost) |
||||||
|
}) |
||||||
|
}, reqSignOut) |
||||||
|
|
||||||
|
m.Group("/user/settings", func() { |
||||||
|
m.Get("", user.Settings) |
||||||
|
m.Post("", bindIgnErr(auth.UpdateProfileForm{}), user.SettingsPost) |
||||||
|
m.Combo("/avatar").Get(user.SettingsAvatar). |
||||||
|
Post(binding.MultipartForm(auth.AvatarForm{}), user.SettingsAvatarPost) |
||||||
|
m.Post("/avatar/delete", user.SettingsDeleteAvatar) |
||||||
|
m.Combo("/email").Get(user.SettingsEmails). |
||||||
|
Post(bindIgnErr(auth.AddEmailForm{}), user.SettingsEmailPost) |
||||||
|
m.Post("/email/delete", user.DeleteEmail) |
||||||
|
m.Get("/password", user.SettingsPassword) |
||||||
|
m.Post("/password", bindIgnErr(auth.ChangePasswordForm{}), user.SettingsPasswordPost) |
||||||
|
if setting.Service.EnableOpenIDSignIn { |
||||||
|
m.Group("/openid", func() { |
||||||
|
m.Combo("").Get(user.SettingsOpenID). |
||||||
|
Post(bindIgnErr(auth.AddOpenIDForm{}), user.SettingsOpenIDPost) |
||||||
|
m.Post("/delete", user.DeleteOpenID) |
||||||
|
m.Post("/toggle_visibility", user.ToggleOpenIDVisibility) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
m.Combo("/ssh").Get(user.SettingsSSHKeys). |
||||||
|
Post(bindIgnErr(auth.AddSSHKeyForm{}), user.SettingsSSHKeysPost) |
||||||
|
m.Post("/ssh/delete", user.DeleteSSHKey) |
||||||
|
m.Combo("/applications").Get(user.SettingsApplications). |
||||||
|
Post(bindIgnErr(auth.NewAccessTokenForm{}), user.SettingsApplicationsPost) |
||||||
|
m.Post("/applications/delete", user.SettingsDeleteApplication) |
||||||
|
m.Route("/delete", "GET,POST", user.SettingsDelete) |
||||||
|
m.Combo("/account_link").Get(user.SettingsAccountLinks).Post(user.SettingsDeleteAccountLink) |
||||||
|
m.Group("/two_factor", func() { |
||||||
|
m.Get("", user.SettingsTwoFactor) |
||||||
|
m.Post("/regenerate_scratch", user.SettingsTwoFactorRegenerateScratch) |
||||||
|
m.Post("/disable", user.SettingsTwoFactorDisable) |
||||||
|
m.Get("/enroll", user.SettingsTwoFactorEnroll) |
||||||
|
m.Post("/enroll", bindIgnErr(auth.TwoFactorAuthForm{}), user.SettingsTwoFactorEnrollPost) |
||||||
|
}) |
||||||
|
}, reqSignIn, func(ctx *context.Context) { |
||||||
|
ctx.Data["PageIsUserSettings"] = true |
||||||
|
}) |
||||||
|
|
||||||
|
m.Group("/user", func() { |
||||||
|
// r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
|
||||||
|
m.Any("/activate", user.Activate) |
||||||
|
m.Any("/activate_email", user.ActivateEmail) |
||||||
|
m.Get("/email2user", user.Email2User) |
||||||
|
m.Get("/forgot_password", user.ForgotPasswd) |
||||||
|
m.Post("/forgot_password", user.ForgotPasswdPost) |
||||||
|
m.Get("/logout", user.SignOut) |
||||||
|
}) |
||||||
|
// ***** END: User *****
|
||||||
|
|
||||||
|
adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true}) |
||||||
|
|
||||||
|
// ***** START: Admin *****
|
||||||
|
m.Group("/admin", func() { |
||||||
|
m.Get("", adminReq, admin.Dashboard) |
||||||
|
m.Get("/config", admin.Config) |
||||||
|
m.Post("/config/test_mail", admin.SendTestMail) |
||||||
|
m.Get("/monitor", admin.Monitor) |
||||||
|
|
||||||
|
m.Group("/users", func() { |
||||||
|
m.Get("", admin.Users) |
||||||
|
m.Combo("/new").Get(admin.NewUser).Post(bindIgnErr(auth.AdminCreateUserForm{}), admin.NewUserPost) |
||||||
|
m.Combo("/:userid").Get(admin.EditUser).Post(bindIgnErr(auth.AdminEditUserForm{}), admin.EditUserPost) |
||||||
|
m.Post("/:userid/delete", admin.DeleteUser) |
||||||
|
}) |
||||||
|
|
||||||
|
m.Group("/orgs", func() { |
||||||
|
m.Get("", admin.Organizations) |
||||||
|
}) |
||||||
|
|
||||||
|
m.Group("/repos", func() { |
||||||
|
m.Get("", admin.Repos) |
||||||
|
m.Post("/delete", admin.DeleteRepo) |
||||||
|
}) |
||||||
|
|
||||||
|
m.Group("/auths", func() { |
||||||
|
m.Get("", admin.Authentications) |
||||||
|
m.Combo("/new").Get(admin.NewAuthSource).Post(bindIgnErr(auth.AuthenticationForm{}), admin.NewAuthSourcePost) |
||||||
|
m.Combo("/:authid").Get(admin.EditAuthSource). |
||||||
|
Post(bindIgnErr(auth.AuthenticationForm{}), admin.EditAuthSourcePost) |
||||||
|
m.Post("/:authid/delete", admin.DeleteAuthSource) |
||||||
|
}) |
||||||
|
|
||||||
|
m.Group("/notices", func() { |
||||||
|
m.Get("", admin.Notices) |
||||||
|
m.Post("/delete", admin.DeleteNotices) |
||||||
|
m.Get("/empty", admin.EmptyNotices) |
||||||
|
}) |
||||||
|
}, adminReq) |
||||||
|
// ***** END: Admin *****
|
||||||
|
|
||||||
|
m.Group("", func() { |
||||||
|
m.Group("/:username", func() { |
||||||
|
m.Get("", user.Profile) |
||||||
|
m.Get("/followers", user.Followers) |
||||||
|
m.Get("/following", user.Following) |
||||||
|
}) |
||||||
|
|
||||||
|
m.Get("/attachments/:uuid", func(ctx *context.Context) { |
||||||
|
attach, err := models.GetAttachmentByUUID(ctx.Params(":uuid")) |
||||||
|
if err != nil { |
||||||
|
if models.IsErrAttachmentNotExist(err) { |
||||||
|
ctx.Error(404) |
||||||
|
} else { |
||||||
|
ctx.Handle(500, "GetAttachmentByUUID", err) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
fr, err := os.Open(attach.LocalPath()) |
||||||
|
if err != nil { |
||||||
|
ctx.Handle(500, "Open", err) |
||||||
|
return |
||||||
|
} |
||||||
|
defer fr.Close() |
||||||
|
|
||||||
|
if err := attach.IncreaseDownloadCount(); err != nil { |
||||||
|
ctx.Handle(500, "Update", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if err = repo.ServeData(ctx, attach.Name, fr); err != nil { |
||||||
|
ctx.Handle(500, "ServeData", err) |
||||||
|
return |
||||||
|
} |
||||||
|
}) |
||||||
|
m.Post("/attachments", repo.UploadAttachment) |
||||||
|
}, ignSignIn) |
||||||
|
|
||||||
|
m.Group("/:username", func() { |
||||||
|
m.Get("/action/:action", user.Action) |
||||||
|
}, reqSignIn) |
||||||
|
|
||||||
|
if macaron.Env == macaron.DEV { |
||||||
|
m.Get("/template/*", dev.TemplatePreview) |
||||||
|
} |
||||||
|
|
||||||
|
reqRepoAdmin := context.RequireRepoAdmin() |
||||||
|
reqRepoWriter := context.RequireRepoWriter() |
||||||
|
|
||||||
|
// ***** START: Organization *****
|
||||||
|
m.Group("/org", func() { |
||||||
|
m.Group("", func() { |
||||||
|
m.Get("/create", org.Create) |
||||||
|
m.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost) |
||||||
|
}, func(ctx *context.Context) { |
||||||
|
if !ctx.User.CanCreateOrganization() { |
||||||
|
ctx.NotFound() |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
m.Group("/:org", func() { |
||||||
|
m.Get("/dashboard", user.Dashboard) |
||||||
|
m.Get("/^:type(issues|pulls)$", user.Issues) |
||||||
|
m.Get("/members", org.Members) |
||||||
|
m.Get("/members/action/:action", org.MembersAction) |
||||||
|
|
||||||
|
m.Get("/teams", org.Teams) |
||||||
|
}, context.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) |
||||||
|
}, context.OrgAssignment(true, false, true)) |
||||||
|
|
||||||
|
m.Group("/:org", func() { |
||||||
|
m.Get("/teams/new", org.NewTeam) |
||||||
|
m.Post("/teams/new", bindIgnErr(auth.CreateTeamForm{}), org.NewTeamPost) |
||||||
|
m.Get("/teams/:team/edit", org.EditTeam) |
||||||
|
m.Post("/teams/:team/edit", bindIgnErr(auth.CreateTeamForm{}), org.EditTeamPost) |
||||||
|
m.Post("/teams/:team/delete", org.DeleteTeam) |
||||||
|
|
||||||
|
m.Group("/settings", func() { |
||||||
|
m.Combo("").Get(org.Settings). |
||||||
|
Post(bindIgnErr(auth.UpdateOrgSettingForm{}), org.SettingsPost) |
||||||
|
m.Post("/avatar", binding.MultipartForm(auth.AvatarForm{}), org.SettingsAvatar) |
||||||
|
m.Post("/avatar/delete", org.SettingsDeleteAvatar) |
||||||
|
|
||||||
|
m.Group("/hooks", func() { |
||||||
|
m.Get("", org.Webhooks) |
||||||
|
m.Post("/delete", org.DeleteWebhook) |
||||||
|
m.Get("/:type/new", repo.WebhooksNew) |
||||||
|
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) |
||||||
|
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) |
||||||
|
m.Get("/:id", repo.WebHooksEdit) |
||||||
|
m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) |
||||||
|
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) |
||||||
|
}) |
||||||
|
|
||||||
|
m.Route("/delete", "GET,POST", org.SettingsDelete) |
||||||
|
}) |
||||||
|
|
||||||
|
m.Route("/invitations/new", "GET,POST", org.Invitation) |
||||||
|
}, context.OrgAssignment(true, true)) |
||||||
|
}, reqSignIn) |
||||||
|
// ***** END: Organization *****
|
||||||
|
|
||||||
|
// ***** START: Repository *****
|
||||||
|
m.Group("/repo", func() { |
||||||
|
m.Get("/create", repo.Create) |
||||||
|
m.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost) |
||||||
|
m.Get("/migrate", repo.Migrate) |
||||||
|
m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost) |
||||||
|
m.Combo("/fork/:repoid").Get(repo.Fork). |
||||||
|
Post(bindIgnErr(auth.CreateRepoForm{}), repo.ForkPost) |
||||||
|
}, reqSignIn) |
||||||
|
|
||||||
|
m.Group("/:username/:reponame", func() { |
||||||
|
m.Group("/settings", func() { |
||||||
|
m.Combo("").Get(repo.Settings). |
||||||
|
Post(bindIgnErr(auth.RepoSettingForm{}), repo.SettingsPost) |
||||||
|
m.Group("/collaboration", func() { |
||||||
|
m.Combo("").Get(repo.Collaboration).Post(repo.CollaborationPost) |
||||||
|
m.Post("/access_mode", repo.ChangeCollaborationAccessMode) |
||||||
|
m.Post("/delete", repo.DeleteCollaboration) |
||||||
|
}) |
||||||
|
m.Group("/branches", func() { |
||||||
|
m.Combo("").Get(repo.ProtectedBranch).Post(repo.ProtectedBranchPost) |
||||||
|
m.Post("/can_push", repo.ChangeProtectedBranch) |
||||||
|
m.Post("/delete", repo.DeleteProtectedBranch) |
||||||
|
}, repo.MustBeNotBare) |
||||||
|
|
||||||
|
m.Group("/hooks", func() { |
||||||
|
m.Get("", repo.Webhooks) |
||||||
|
m.Post("/delete", repo.DeleteWebhook) |
||||||
|
m.Get("/:type/new", repo.WebhooksNew) |
||||||
|
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) |
||||||
|
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) |
||||||
|
m.Get("/:id", repo.WebHooksEdit) |
||||||
|
m.Post("/:id/test", repo.TestWebhook) |
||||||
|
m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) |
||||||
|
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) |
||||||
|
|
||||||
|
m.Group("/git", func() { |
||||||
|
m.Get("", repo.GitHooks) |
||||||
|
m.Combo("/:name").Get(repo.GitHooksEdit). |
||||||
|
Post(repo.GitHooksEditPost) |
||||||
|
}, context.GitHookService()) |
||||||
|
}) |
||||||
|
|
||||||
|
m.Group("/keys", func() { |
||||||
|
m.Combo("").Get(repo.DeployKeys). |
||||||
|
Post(bindIgnErr(auth.AddSSHKeyForm{}), repo.DeployKeysPost) |
||||||
|
m.Post("/delete", repo.DeleteDeployKey) |
||||||
|
}) |
||||||
|
|
||||||
|
}, func(ctx *context.Context) { |
||||||
|
ctx.Data["PageIsSettings"] = true |
||||||
|
}, context.UnitTypes()) |
||||||
|
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef()) |
||||||
|
|
||||||
|
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action) |
||||||
|
m.Group("/:username/:reponame", func() { |
||||||
|
// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
|
||||||
|
// So they can apply their own enable/disable logic on routers.
|
||||||
|
m.Group("/issues", func() { |
||||||
|
m.Combo("/new", repo.MustEnableIssues).Get(context.RepoRef(), repo.NewIssue). |
||||||
|
Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost) |
||||||
|
|
||||||
|
m.Group("/:index", func() { |
||||||
|
m.Post("/title", repo.UpdateIssueTitle) |
||||||
|
m.Post("/content", repo.UpdateIssueContent) |
||||||
|
m.Post("/watch", repo.IssueWatch) |
||||||
|
m.Combo("/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment) |
||||||
|
}) |
||||||
|
|
||||||
|
m.Post("/labels", repo.UpdateIssueLabel, reqRepoWriter) |
||||||
|
m.Post("/milestone", repo.UpdateIssueMilestone, reqRepoWriter) |
||||||
|
m.Post("/assignee", repo.UpdateIssueAssignee, reqRepoWriter) |
||||||
|
m.Post("/status", repo.UpdateIssueStatus, reqRepoWriter) |
||||||
|
}) |
||||||
|
m.Group("/comments/:id", func() { |
||||||
|
m.Post("", repo.UpdateCommentContent) |
||||||
|
m.Post("/delete", repo.DeleteComment) |
||||||
|
}) |
||||||
|
m.Group("/labels", func() { |
||||||
|
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel) |
||||||
|
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel) |
||||||
|
m.Post("/delete", repo.DeleteLabel) |
||||||
|
m.Post("/initialize", bindIgnErr(auth.InitializeLabelsForm{}), repo.InitializeLabels) |
||||||
|
}, reqRepoWriter, context.RepoRef()) |
||||||
|
m.Group("/milestones", func() { |
||||||
|
m.Combo("/new").Get(repo.NewMilestone). |
||||||
|
Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost) |
||||||
|
m.Get("/:id/edit", repo.EditMilestone) |
||||||
|
m.Post("/:id/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost) |
||||||
|
m.Get("/:id/:action", repo.ChangeMilestonStatus) |
||||||
|
m.Post("/delete", repo.DeleteMilestone) |
||||||
|
}, reqRepoWriter, context.RepoRef()) |
||||||
|
m.Group("/releases", func() { |
||||||
|
m.Get("/new", repo.NewRelease) |
||||||
|
m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost) |
||||||
|
m.Post("/delete", repo.DeleteRelease) |
||||||
|
}, repo.MustBeNotBare, reqRepoWriter, context.RepoRef()) |
||||||
|
m.Group("/releases", func() { |
||||||
|
m.Get("/edit/*", repo.EditRelease) |
||||||
|
m.Post("/edit/*", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost) |
||||||
|
}, repo.MustBeNotBare, reqRepoWriter, func(ctx *context.Context) { |
||||||
|
var err error |
||||||
|
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch) |
||||||
|
if err != nil { |
||||||
|
ctx.Handle(500, "GetBranchCommit", err) |
||||||
|
return |
||||||
|
} |
||||||
|
ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount() |
||||||
|
if err != nil { |
||||||
|
ctx.Handle(500, "CommitsCount", err) |
||||||
|
return |
||||||
|
} |
||||||
|
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount |
||||||
|
}) |
||||||
|
|
||||||
|
m.Combo("/compare/*", repo.MustAllowPulls, repo.SetEditorconfigIfExists). |
||||||
|
Get(repo.CompareAndPullRequest). |
||||||
|
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost) |
||||||
|
|
||||||
|
m.Group("", func() { |
||||||
|
m.Combo("/_edit/*").Get(repo.EditFile). |
||||||
|
Post(bindIgnErr(auth.EditRepoFileForm{}), repo.EditFilePost) |
||||||
|
m.Combo("/_new/*").Get(repo.NewFile). |
||||||
|
Post(bindIgnErr(auth.EditRepoFileForm{}), repo.NewFilePost) |
||||||
|
m.Post("/_preview/*", bindIgnErr(auth.EditPreviewDiffForm{}), repo.DiffPreviewPost) |
||||||
|
m.Combo("/_delete/*").Get(repo.DeleteFile). |
||||||
|
Post(bindIgnErr(auth.DeleteRepoFileForm{}), repo.DeleteFilePost) |
||||||
|
|
||||||
|
m.Group("", func() { |
||||||
|
m.Combo("/_upload/*").Get(repo.UploadFile). |
||||||
|
Post(bindIgnErr(auth.UploadRepoFileForm{}), repo.UploadFilePost) |
||||||
|
m.Post("/upload-file", repo.UploadFileToServer) |
||||||
|
m.Post("/upload-remove", bindIgnErr(auth.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer) |
||||||
|
}, func(ctx *context.Context) { |
||||||
|
if !setting.Repository.Upload.Enabled { |
||||||
|
ctx.Handle(404, "", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
}) |
||||||
|
}, repo.MustBeNotBare, reqRepoWriter, context.RepoRef(), func(ctx *context.Context) { |
||||||
|
if !ctx.Repo.Repository.CanEnableEditor() || ctx.Repo.IsViewCommit { |
||||||
|
ctx.Handle(404, "", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
}) |
||||||
|
}, reqSignIn, context.RepoAssignment(), context.UnitTypes()) |
||||||
|
|
||||||
|
m.Group("/:username/:reponame", func() { |
||||||
|
m.Group("", func() { |
||||||
|
m.Get("/releases", repo.MustBeNotBare, repo.Releases) |
||||||
|
m.Get("/^:type(issues|pulls)$", repo.RetrieveLabels, repo.Issues) |
||||||
|
m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue) |
||||||
|
m.Get("/labels/", repo.RetrieveLabels, repo.Labels) |
||||||
|
m.Get("/milestones", repo.Milestones) |
||||||
|
}, context.RepoRef()) |
||||||
|
|
||||||
|
// m.Get("/branches", repo.Branches)
|
||||||
|
m.Post("/branches/:name/delete", reqSignIn, reqRepoWriter, repo.MustBeNotBare, repo.DeleteBranchPost) |
||||||
|
|
||||||
|
m.Group("/wiki", func() { |
||||||
|
m.Get("/?:page", repo.Wiki) |
||||||
|
m.Get("/_pages", repo.WikiPages) |
||||||
|
|
||||||
|
m.Group("", func() { |
||||||
|
m.Combo("/_new").Get(repo.NewWiki). |
||||||
|
Post(bindIgnErr(auth.NewWikiForm{}), repo.NewWikiPost) |
||||||
|
m.Combo("/:page/_edit").Get(repo.EditWiki). |
||||||
|
Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost) |
||||||
|
m.Post("/:page/delete", repo.DeleteWikiPagePost) |
||||||
|
}, reqSignIn, reqRepoWriter) |
||||||
|
}, repo.MustEnableWiki, context.RepoRef()) |
||||||
|
|
||||||
|
m.Group("/wiki", func() { |
||||||
|
m.Get("/raw/*", repo.WikiRaw) |
||||||
|
m.Get("/*", repo.WikiRaw) |
||||||
|
}, repo.MustEnableWiki) |
||||||
|
|
||||||
|
m.Get("/archive/*", repo.MustBeNotBare, repo.Download) |
||||||
|
|
||||||
|
m.Group("/pulls/:index", func() { |
||||||
|
m.Get("/commits", context.RepoRef(), repo.ViewPullCommits) |
||||||
|
m.Get("/files", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ViewPullFiles) |
||||||
|
m.Post("/merge", reqRepoWriter, repo.MergePullRequest) |
||||||
|
}, repo.MustAllowPulls) |
||||||
|
|
||||||
|
m.Group("", func() { |
||||||
|
m.Get("/src/*", repo.SetEditorconfigIfExists, repo.Home) |
||||||
|
m.Get("/raw/*", repo.SingleDownload) |
||||||
|
m.Get("/commits/*", repo.RefCommits) |
||||||
|
m.Get("/graph", repo.Graph) |
||||||
|
m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.Diff) |
||||||
|
m.Get("/forks", repo.Forks) |
||||||
|
}, context.RepoRef()) |
||||||
|
m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.MustBeNotBare, repo.RawDiff) |
||||||
|
|
||||||
|
m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.MustBeNotBare, repo.CompareDiff) |
||||||
|
}, ignSignIn, context.RepoAssignment(), context.UnitTypes()) |
||||||
|
m.Group("/:username/:reponame", func() { |
||||||
|
m.Get("/stars", repo.Stars) |
||||||
|
m.Get("/watchers", repo.Watchers) |
||||||
|
}, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes()) |
||||||
|
|
||||||
|
m.Group("/:username", func() { |
||||||
|
m.Group("/:reponame", func() { |
||||||
|
m.Get("", repo.SetEditorconfigIfExists, repo.Home) |
||||||
|
m.Get("\\.git$", repo.SetEditorconfigIfExists, repo.Home) |
||||||
|
}, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes()) |
||||||
|
|
||||||
|
m.Group("/:reponame", func() { |
||||||
|
m.Group("/info/lfs", func() { |
||||||
|
m.Post("/objects/batch", lfs.BatchHandler) |
||||||
|
m.Get("/objects/:oid/:filename", lfs.ObjectOidHandler) |
||||||
|
m.Any("/objects/:oid", lfs.ObjectOidHandler) |
||||||
|
m.Post("/objects", lfs.PostHandler) |
||||||
|
m.Any("/*", func(ctx *context.Context) { |
||||||
|
ctx.Handle(404, "", nil) |
||||||
|
}) |
||||||
|
}, ignSignInAndCsrf) |
||||||
|
m.Any("/*", ignSignInAndCsrf, repo.HTTP) |
||||||
|
m.Head("/tasks/trigger", repo.TriggerTask) |
||||||
|
}) |
||||||
|
}) |
||||||
|
// ***** END: Repository *****
|
||||||
|
|
||||||
|
m.Group("/notifications", func() { |
||||||
|
m.Get("", user.Notifications) |
||||||
|
m.Post("/status", user.NotificationStatusPost) |
||||||
|
}, reqSignIn) |
||||||
|
|
||||||
|
m.Group("/api", func() { |
||||||
|
apiv1.RegisterRoutes(m) |
||||||
|
}, ignSignIn) |
||||||
|
|
||||||
|
m.Group("/api/internal", func() { |
||||||
|
// package name internal is ideal but Golang is not allowed, so we use private as package name.
|
||||||
|
private.RegisterRoutes(m) |
||||||
|
}) |
||||||
|
|
||||||
|
// robots.txt
|
||||||
|
m.Get("/robots.txt", func(ctx *context.Context) { |
||||||
|
if setting.HasRobotsTxt { |
||||||
|
ctx.ServeFileContent(path.Join(setting.CustomPath, "robots.txt")) |
||||||
|
} else { |
||||||
|
ctx.Error(404) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
// Not found handler.
|
||||||
|
m.NotFound(routers.NotFound) |
||||||
|
} |
Loading…
Reference in new issue