diff --git a/integrations/goget_test.go b/integrations/goget_test.go new file mode 100644 index 0000000000..1003d71023 --- /dev/null +++ b/integrations/goget_test.go @@ -0,0 +1,35 @@ +// Copyright 2021 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 ( + "fmt" + "net/http" + "testing" + + "code.gitea.io/gitea/modules/setting" + "github.com/stretchr/testify/assert" +) + +func TestGoGet(t *testing.T) { + defer prepareTestEnv(t)() + + req := NewRequest(t, "GET", "/blah/glah/plah?go-get=1") + resp := MakeRequest(t, req, http.StatusOK) + + expected := fmt.Sprintf(` + +
+ + + + + go get --insecure %[1]s:%[2]s/blah/glah + + +`, setting.Domain, setting.HTTPPort, setting.AppURL) + + assert.Equal(t, expected, resp.Body.String()) +} diff --git a/routers/routes/goget.go b/routers/routes/goget.go new file mode 100644 index 0000000000..518f5e3073 --- /dev/null +++ b/routers/routes/goget.go @@ -0,0 +1,86 @@ +// Copyright 2021 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 ( + "net/http" + "net/url" + "path" + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" + "github.com/unknwon/com" +) + +func goGet(ctx *context.Context) { + if ctx.Req.Method != "GET" || ctx.Query("go-get") != "1" || len(ctx.Req.URL.Query()) > 1 { + return + } + + parts := strings.SplitN(ctx.Req.URL.EscapedPath(), "/", 4) + + if len(parts) < 3 { + return + } + + ownerName := parts[1] + repoName := parts[2] + + // Quick responses appropriate go-get meta with status 200 + // regardless of if user have access to the repository, + // or the repository does not exist at all. + // This is particular a workaround for "go get" command which does not respect + // .netrc file. + + trimmedRepoName := strings.TrimSuffix(repoName, ".git") + + if ownerName == "" || trimmedRepoName == "" { + _, _ = ctx.Write([]byte(` + + + invalid import path + + +`)) + ctx.Status(400) + return + } + branchName := setting.Repository.DefaultBranch + + repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) + if err == nil && len(repo.DefaultBranch) > 0 { + branchName = repo.DefaultBranch + } + prefix := setting.AppURL + path.Join(url.PathEscape(ownerName), url.PathEscape(repoName), "src", "branch", util.PathEscapeSegments(branchName)) + + appURL, _ := url.Parse(setting.AppURL) + + insecure := "" + if appURL.Scheme == string(setting.HTTP) { + insecure = "--insecure " + } + ctx.Header().Set("Content-Type", "text/html") + ctx.Status(http.StatusOK) + _, _ = ctx.Write([]byte(com.Expand(` + + + + + + + go get {Insecure}{GoGetImport} + + +`, map[string]string{ + "GoGetImport": context.ComposeGoGetImport(ownerName, trimmedRepoName), + "CloneLink": models.ComposeHTTPSCloneURL(ownerName, repoName), + "GoDocDirectory": prefix + "{/dir}", + "GoDocFile": prefix + "{/dir}/{file}#L{line}", + "Insecure": insecure, + }))) +} diff --git a/routers/routes/web.go b/routers/routes/web.go index 77ceb83214..008c745d6e 100644 --- a/routers/routes/web.go +++ b/routers/routes/web.go @@ -8,7 +8,6 @@ import ( "encoding/gob" "fmt" "net/http" - "net/url" "os" "path" "strings" @@ -22,7 +21,6 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers" @@ -51,7 +49,6 @@ import ( "github.com/go-chi/cors" "github.com/prometheus/client_golang/prometheus" "github.com/tstranex/u2f" - "github.com/unknwon/com" ) const ( @@ -228,6 +225,7 @@ func WebRoutes() *web.Route { // TODO: These really seem like things that could be folded into Contexter or as helper functions common = append(common, user.GetNotificationCount) common = append(common, repo.GetActiveStopwatch) + common = append(common, goGet) others := web.NewRoute() for _, middle := range common { @@ -239,67 +237,6 @@ func WebRoutes() *web.Route { return routes } -func goGet(ctx *context.Context) { - if ctx.Query("go-get") != "1" { - return - } - - // Quick responses appropriate go-get meta with status 200 - // regardless of if user have access to the repository, - // or the repository does not exist at all. - // This is particular a workaround for "go get" command which does not respect - // .netrc file. - - ownerName := ctx.Params(":username") - repoName := ctx.Params(":reponame") - trimmedRepoName := strings.TrimSuffix(repoName, ".git") - - if ownerName == "" || trimmedRepoName == "" { - _, _ = ctx.Write([]byte(` - - - invalid import path - - -`)) - ctx.Status(400) - return - } - branchName := setting.Repository.DefaultBranch - - repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) - if err == nil && len(repo.DefaultBranch) > 0 { - branchName = repo.DefaultBranch - } - prefix := setting.AppURL + path.Join(url.PathEscape(ownerName), url.PathEscape(repoName), "src", "branch", util.PathEscapeSegments(branchName)) - - appURL, _ := url.Parse(setting.AppURL) - - insecure := "" - if appURL.Scheme == string(setting.HTTP) { - insecure = "--insecure " - } - ctx.Header().Set("Content-Type", "text/html") - ctx.Status(http.StatusOK) - _, _ = ctx.Write([]byte(com.Expand(` - - - - - - - go get {Insecure}{GoGetImport} - - -`, map[string]string{ - "GoGetImport": context.ComposeGoGetImport(ownerName, trimmedRepoName), - "CloneLink": models.ComposeHTTPSCloneURL(ownerName, repoName), - "GoDocDirectory": prefix + "{/dir}", - "GoDocFile": prefix + "{/dir}/{file}#L{line}", - "Insecure": insecure, - }))) -} - // RegisterRoutes register routes func RegisterRoutes(m *web.Route) { reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true}) @@ -1104,7 +1041,7 @@ func RegisterRoutes(m *web.Route) { m.Group("/{username}", func() { m.Group("/{reponame}", func() { m.Get("", repo.SetEditorconfigIfExists, repo.Home) - }, goGet, ignSignIn, context.RepoAssignment, context.RepoRef(), context.UnitTypes()) + }, ignSignIn, context.RepoAssignment, context.RepoRef(), context.UnitTypes()) m.Group("/{reponame}", func() { m.Group("/info/lfs", func() {