feat: [CODE-2146]: add new router paradigm

* lint
* address comment
* fix
* ssh ctx
* add ctx for new places
* generate wiregen
* Merge remote-tracking branch 'harness0/main' into abhinav/new-router-paradigm
* Merge branch 'main' into abhinav/new-router-paradigm
* add new discussion changes
* address comment
* address comment
* address comment
* address comment
* address comment
* feat: abstract routers logic
* feat: abstract routers logic
* feat: abstract routers logic
* feat: abstract routers logic
* feat: abstract routers logic
* feat: abstract routers logic
* feat: abstract routers logic
* style
* remove nil context
* add ctx to missing
* style
* remvoe ctx
* remvoe ctx
* feat: provider should have ctx
This commit is contained in:
Abhinav Singh 2024-07-23 21:39:39 +00:00 committed by Harness
parent fb88cb34ab
commit d0562a573c
37 changed files with 366 additions and 238 deletions

View File

@ -245,7 +245,7 @@ func (c *Controller) suggestPullRequest(
msgs[0] = fmt.Sprintf("Branch %q has open PRs:", branchName) msgs[0] = fmt.Sprintf("Branch %q has open PRs:", branchName)
for i, pr := range prs { for i, pr := range prs {
msgs[2*i+1] = fmt.Sprintf(" (#%d) %s", pr.Number, pr.Title) msgs[2*i+1] = fmt.Sprintf(" (#%d) %s", pr.Number, pr.Title)
msgs[2*i+2] = " " + c.urlProvider.GenerateUIPRURL(repo.Path, pr.Number) msgs[2*i+2] = " " + c.urlProvider.GenerateUIPRURL(ctx, repo.Path, pr.Number)
} }
out.Messages = append(out.Messages, msgs...) out.Messages = append(out.Messages, msgs...)
return return
@ -254,7 +254,7 @@ func (c *Controller) suggestPullRequest(
// this is a new PR! // this is a new PR!
out.Messages = append(out.Messages, out.Messages = append(out.Messages,
fmt.Sprintf("Create a pull request for %q by visiting:", branchName), fmt.Sprintf("Create a pull request for %q by visiting:", branchName),
" "+c.urlProvider.GenerateUICompareURL(repo.Path, repo.DefaultBranch, branchName), " "+c.urlProvider.GenerateUICompareURL(ctx, repo.Path, repo.DefaultBranch, branchName),
) )
} }

View File

@ -146,8 +146,8 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
} }
// backfil GitURL // backfil GitURL
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path) repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path) repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path)
repoOutput := GetRepoOutputWithAccess(ctx, in.IsPublic, repo) repoOutput := GetRepoOutputWithAccess(ctx, in.IsPublic, repo)
@ -266,7 +266,7 @@ func (c *Controller) createGitRepository(ctx context.Context, session *auth.Sess
// generate envars (add everything githook CLI needs for execution) // generate envars (add everything githook CLI needs for execution)
envVars, err := githook.GenerateEnvironmentVariables( envVars, err := githook.GenerateEnvironmentVariables(
ctx, ctx,
c.urlProvider.GetInternalAPIURL(), c.urlProvider.GetInternalAPIURL(ctx),
0, 0,
session.Principal.ID, session.Principal.ID,
true, true,

View File

@ -35,8 +35,8 @@ func (c *Controller) Find(ctx context.Context, session *auth.Session, repoRef st
} }
// backfill clone url // backfill clone url
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path) repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path) repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path)
return GetRepoOutput(ctx, c.publicAccess, repo) return GetRepoOutput(ctx, c.publicAccess, repo)
} }

View File

@ -97,8 +97,8 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo
return nil, err return nil, err
} }
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path) repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path) repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path)
err = c.auditService.Log(ctx, err = c.auditService.Log(ctx,
session.Principal, session.Principal,

View File

@ -130,8 +130,8 @@ func (c *Controller) Move(ctx context.Context,
return nil, fmt.Errorf("failed to set repo public access for new path (cleanup successful): %w", err) return nil, fmt.Errorf("failed to set repo public access for new path (cleanup successful): %w", err)
} }
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path) repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path) repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path)
return GetRepoOutput(ctx, c.publicAccess, repo) return GetRepoOutput(ctx, c.publicAccess, repo)
} }

View File

@ -97,7 +97,7 @@ func (c *Controller) DeleteGitRepository(
// create custom write params for delete as repo might or might not exist in db (similar to create). // create custom write params for delete as repo might or might not exist in db (similar to create).
envVars, err := githook.GenerateEnvironmentVariables( envVars, err := githook.GenerateEnvironmentVariables(
ctx, ctx,
c.urlProvider.GetInternalAPIURL(), c.urlProvider.GetInternalAPIURL(ctx),
0, // no repoID 0, // no repoID
session.Principal.ID, session.Principal.ID,
true, true,

View File

@ -84,8 +84,8 @@ func (c *Controller) Update(ctx context.Context,
} }
// backfill repo url // backfill repo url
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path) repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path) repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path)
return GetRepoOutput(ctx, c.publicAccess, repo) return GetRepoOutput(ctx, c.publicAccess, repo)
} }

View File

@ -71,8 +71,8 @@ func (c *Controller) UpdatePublicAccess(ctx context.Context,
} }
// backfill GitURL // backfill GitURL
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path) repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path) repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path)
err = c.auditService.Log(ctx, err = c.auditService.Log(ctx,
session.Principal, session.Principal,

View File

@ -81,8 +81,8 @@ func (c *Controller) ListRepositoriesNoAuth(
var reposOut []*repoCtrl.RepositoryOutput var reposOut []*repoCtrl.RepositoryOutput
for _, repo := range repos { for _, repo := range repos {
// backfill URLs // backfill URLs
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path) repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path) repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path)
repoOut, err := repoCtrl.GetRepoOutput(ctx, c.publicAccess, repo) repoOut, err := repoCtrl.GetRepoOutput(ctx, c.publicAccess, repo)
if err != nil { if err != nil {

View File

@ -37,7 +37,7 @@ func createRPCWriteParams(
// generate envars (add everything githook CLI needs for execution) // generate envars (add everything githook CLI needs for execution)
envVars, err := githook.GenerateEnvironmentVariables( envVars, err := githook.GenerateEnvironmentVariables(
ctx, ctx,
urlProvider.GetInternalAPIURL(), urlProvider.GetInternalAPIURL(ctx),
repo.ID, repo.ID,
session.Principal.ID, session.Principal.ID,
false, false,

View File

@ -43,7 +43,7 @@ func HandleGitRedirect(urlProvider url.Provider) http.HandlerFunc {
// NOTE: // NOTE:
// Technically, we could find the repo first and use repo.Path. // Technically, we could find the repo first and use repo.Path.
// However, the auth cookie isn't available in case of custom git domains, and thus the auth would fail. // However, the auth cookie isn't available in case of custom git domains, and thus the auth would fail.
repoURL := urlProvider.GenerateUIRepoURL(repoRef) repoURL := urlProvider.GenerateUIRepoURL(ctx, repoRef)
http.Redirect( http.Redirect(
w, w,

View File

@ -15,6 +15,7 @@
package repo package repo
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
@ -53,7 +54,7 @@ func HandleGitInfoRefs(repoCtrl *repo.Controller, urlProvider url.Provider) http
err = repoCtrl.GitInfoRefs(ctx, session, repoRef, service, gitProtocol, w) err = repoCtrl.GitInfoRefs(ctx, session, repoRef, service, gitProtocol, w)
if errors.Is(err, apiauth.ErrNotAuthorized) && auth.IsAnonymousSession(session) { if errors.Is(err, apiauth.ErrNotAuthorized) && auth.IsAnonymousSession(session) {
renderBasicAuth(w, urlProvider) renderBasicAuth(ctx, w, urlProvider)
return return
} }
if err != nil { if err != nil {
@ -65,8 +66,8 @@ func HandleGitInfoRefs(repoCtrl *repo.Controller, urlProvider url.Provider) http
// renderBasicAuth renders a response that indicates that the client (GIT) requires basic authentication. // renderBasicAuth renders a response that indicates that the client (GIT) requires basic authentication.
// This is required in order to tell git CLI to query user credentials. // This is required in order to tell git CLI to query user credentials.
func renderBasicAuth(w http.ResponseWriter, urlProvider url.Provider) { func renderBasicAuth(ctx context.Context, w http.ResponseWriter, urlProvider url.Provider) {
// Git doesn't seem to handle "realm" - so it doesn't seem to matter for basic user CLI interactions. // Git doesn't seem to handle "realm" - so it doesn't seem to matter for basic user CLI interactions.
w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, urlProvider.GetAPIHostname())) w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, urlProvider.GetAPIHostname(ctx)))
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
} }

View File

@ -80,7 +80,7 @@ func HandleGitServicePack(
Protocol: gitProtocol, Protocol: gitProtocol,
}) })
if errors.Is(err, apiauth.ErrNotAuthorized) && auth.IsAnonymousSession(session) { if errors.Is(err, apiauth.ErrNotAuthorized) && auth.IsAnonymousSession(session) {
renderBasicAuth(w, urlProvider) renderBasicAuth(ctx, w, urlProvider)
return return
} }
if err != nil { if err != nil {

View File

@ -109,8 +109,8 @@ func (e *embedded) Detail(ctx context.Context, stage *drone.Stage) (*client.Cont
Config: ConvertToDroneFile(details.Config), Config: ConvertToDroneFile(details.Config),
Netrc: ConvertToDroneNetrc(details.Netrc), Netrc: ConvertToDroneNetrc(details.Netrc),
System: &drone.System{ System: &drone.System{
Proto: e.urlProvider.GetAPIProto(), Proto: e.urlProvider.GetAPIProto(ctx),
Host: e.urlProvider.GetAPIHostname(), Host: e.urlProvider.GetAPIHostname(ctx),
}, },
}, nil }, nil
} }

View File

@ -280,7 +280,7 @@ func (m *Manager) UploadLogs(ctx context.Context, step int64, r io.Reader) error
} }
// Details provides details about the stage. // Details provides details about the stage.
func (m *Manager) Details(_ context.Context, stageID int64) (*ExecutionContext, error) { func (m *Manager) Details(ctx context.Context, stageID int64) (*ExecutionContext, error) {
log := log.With(). log := log.With().
Int64("stage-id", stageID). Int64("stage-id", stageID).
Logger() Logger()
@ -308,7 +308,7 @@ func (m *Manager) Details(_ context.Context, stageID int64) (*ExecutionContext,
} }
// Backfill clone URL // Backfill clone URL
repo.GitURL = m.urlProvider.GenerateContainerGITCloneURL(repo.Path) repo.GitURL = m.urlProvider.GenerateContainerGITCloneURL(ctx, repo.Path)
stages, err := m.Stages.List(noContext, stage.ExecutionID) stages, err := m.Stages.List(noContext, stage.ExecutionID)
if err != nil { if err != nil {

View File

@ -15,6 +15,8 @@
package triggerer package triggerer
import ( import (
"context"
"github.com/harness/gitness/app/url" "github.com/harness/gitness/app/url"
"github.com/harness/gitness/types" "github.com/harness/gitness/types"
@ -32,11 +34,12 @@ func combine(env ...map[string]string) map[string]string {
} }
func Envs( func Envs(
ctx context.Context,
repo *types.Repository, repo *types.Repository,
pipeline *types.Pipeline, pipeline *types.Pipeline,
urlProvider url.Provider, urlProvider url.Provider,
) map[string]string { ) map[string]string {
return map[string]string{ return map[string]string{
"DRONE_BUILD_LINK": urlProvider.GenerateUIBuildURL(repo.Path, pipeline.Identifier, pipeline.Seq), "DRONE_BUILD_LINK": urlProvider.GenerateUIBuildURL(ctx, repo.Path, pipeline.Identifier, pipeline.Seq),
} }
} }

View File

@ -356,7 +356,7 @@ func (t *triggerer) Trigger(
// TODO: this can be made better. We are setting this later since otherwise any parsing failure // TODO: this can be made better. We are setting this later since otherwise any parsing failure
// would lead to an incremented pipeline sequence number. // would lead to an incremented pipeline sequence number.
execution.Number = pipeline.Seq execution.Number = pipeline.Seq
execution.Params = combine(execution.Params, Envs(repo, pipeline, t.urlProvider)) execution.Params = combine(execution.Params, Envs(ctx, repo, pipeline, t.urlProvider))
err = t.createExecutionWithStages(ctx, execution, stages) err = t.createExecutionWithStages(ctx, execution, stages)
if err != nil { if err != nil {

View File

@ -89,11 +89,6 @@ import (
"github.com/rs/zerolog/hlog" "github.com/rs/zerolog/hlog"
) )
// APIHandler is an abstraction of a http handler that handles API calls.
type APIHandler interface {
http.Handler
}
var ( var (
// terminatedPathPrefixesAPI is the list of prefixes that will require resolving terminated paths. // terminatedPathPrefixesAPI is the list of prefixes that will require resolving terminated paths.
terminatedPathPrefixesAPI = []string{"/v1/spaces/", "/v1/repos/", terminatedPathPrefixesAPI = []string{"/v1/spaces/", "/v1/repos/",
@ -130,7 +125,7 @@ func NewAPIHandler(
infraProviderCtrl *infraprovider.Controller, infraProviderCtrl *infraprovider.Controller,
migrateCtrl *migrate.Controller, migrateCtrl *migrate.Controller,
gitspaceCtrl *gitspace.Controller, gitspaceCtrl *gitspace.Controller,
) APIHandler { ) http.Handler {
// Use go-chi router for inner routing. // Use go-chi router for inner routing.
r := chi.NewRouter() r := chi.NewRouter()

58
app/router/api_router.go Normal file
View File

@ -0,0 +1,58 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package router
import (
"net/http"
"strings"
"github.com/harness/gitness/app/api/render"
"github.com/harness/gitness/logging"
"github.com/rs/zerolog/log"
)
const APIMount = "/api"
type APIRouter struct {
handler http.Handler
}
func NewAPIRouter(handler http.Handler) *APIRouter {
return &APIRouter{handler: handler}
}
func (r *APIRouter) Handle(w http.ResponseWriter, req *http.Request) {
req = req.WithContext(logging.NewContext(req.Context(), WithLoggingRouter("api")))
// remove matched prefix to simplify API handlers
if err := StripPrefix(APIMount, req); err != nil {
log.Ctx(req.Context()).Err(err).Msgf("Failed striping of prefix for api request.")
render.InternalError(req.Context(), w)
return
}
r.handler.ServeHTTP(w, req)
}
func (r *APIRouter) IsEligibleTraffic(req *http.Request) bool {
// All Rest API calls start with "/api/", and thus can be uniquely identified.
p := req.URL.Path
return strings.HasPrefix(p, APIMount)
}
func (r *APIRouter) Name() string {
return "api"
}

View File

@ -34,17 +34,12 @@ import (
"github.com/rs/zerolog/hlog" "github.com/rs/zerolog/hlog"
) )
// GitHandler is an abstraction of an http handler that handles git calls.
type GitHandler interface {
http.Handler
}
// NewGitHandler returns a new GitHandler. // NewGitHandler returns a new GitHandler.
func NewGitHandler( func NewGitHandler(
urlProvider url.Provider, urlProvider url.Provider,
authenticator authn.Authenticator, authenticator authn.Authenticator,
repoCtrl *repo.Controller, repoCtrl *repo.Controller,
) GitHandler { ) http.Handler {
// Use go-chi router for inner routing. // Use go-chi router for inner routing.
r := chi.NewRouter() r := chi.NewRouter()

76
app/router/git_router.go Normal file
View File

@ -0,0 +1,76 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package router
import (
"net/http"
"strings"
"github.com/harness/gitness/app/api/render"
"github.com/rs/zerolog/log"
)
const GitMount = "/git"
type GitRouter struct {
handler http.Handler
// gitHost describes the optional host via which git traffic is identified.
// Note: always stored as lowercase.
gitHost string
}
func NewGitRouter(handler http.Handler, gitHost string) *GitRouter {
return &GitRouter{handler: handler, gitHost: gitHost}
}
func (r *GitRouter) Handle(w http.ResponseWriter, req *http.Request) {
// remove matched prefix to simplify API handlers (only if it's there)
if err := StripPrefix(GitMount, req); err != nil {
log.Ctx(req.Context()).Err(err).Msgf("Failed striping of prefix for git request.")
render.InternalError(req.Context(), w)
return
}
r.handler.ServeHTTP(w, req)
}
func (r *GitRouter) IsEligibleTraffic(req *http.Request) bool {
// All Git originating traffic starts with "/space1/space2/repo.git".
// git traffic is always reachable via the git mounting path.
p := req.URL.Path
if strings.HasPrefix(p, GitMount) {
return true
}
// otherwise check if the request came in via the configured git host (if enabled)
if len(r.gitHost) > 0 {
// cut (optional) port off the host
h, _, _ := strings.Cut(req.Host, ":")
if strings.EqualFold(r.gitHost, h) {
return true
}
}
// otherwise we don't treat it as git traffic
return false
}
func (r *GitRouter) Name() string {
return "git"
}

25
app/router/interface.go Normal file
View File

@ -0,0 +1,25 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package router
import (
"net/http"
)
type Interface interface {
Handle(w http.ResponseWriter, req *http.Request)
IsEligibleTraffic(req *http.Request) bool
Name() string
}

28
app/router/logging.go Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package router
import (
"github.com/harness/gitness/logging"
"github.com/rs/zerolog"
)
// WithLoggingRouter can be used to annotate logs with the handler info.
func WithLoggingRouter(handler string) logging.Option {
return func(c zerolog.Context) zerolog.Context {
return c.Str("http.router", handler)
}
}

View File

@ -20,6 +20,7 @@ import (
"github.com/harness/gitness/app/api/render" "github.com/harness/gitness/app/api/render"
"github.com/harness/gitness/app/request" "github.com/harness/gitness/app/request"
"github.com/harness/gitness/logging"
"github.com/go-logr/logr" "github.com/go-logr/logr"
"github.com/go-logr/zerologr" "github.com/go-logr/zerologr"
@ -27,40 +28,21 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
const (
APIMount = "/api"
GitMount = "/git"
)
type Router struct { type Router struct {
api APIHandler routers []Interface
git GitHandler
web WebHandler
// gitHost describes the optional host via which git traffic is identified.
// Note: always stored as lowercase.
gitHost string
} }
// NewRouter returns a new http.Handler that routes traffic // NewRouter returns a new http.Handler that routes traffic
// to the appropriate handlers. // to the appropriate handlers.
func NewRouter( func NewRouter(
api APIHandler, routers []Interface,
git GitHandler,
web WebHandler,
gitHost string,
) *Router { ) *Router {
return &Router{ return &Router{
api: api, routers: routers,
git: git,
web: web,
gitHost: strings.ToLower(gitHost),
} }
} }
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var err error
// setup logger for request // setup logger for request
log := log.Logger.With().Logger() log := log.Logger.With().Logger()
ctx := log.WithContext(req.Context()) ctx := log.WithContext(req.Context())
@ -72,91 +54,20 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
Str("http.original_url", req.URL.String()) Str("http.original_url", req.URL.String())
}) })
/* for _, router := range r.routers {
* 1. GIT if ok := router.IsEligibleTraffic(req); ok {
* req = req.WithContext(logging.NewContext(req.Context(), WithLoggingRouter(router.Name())))
* All Git originating traffic starts with "/space1/space2/repo.git". router.Handle(w, req)
*/
if r.isGitTraffic(req) {
log.UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Str("http.handler", "git")
})
// remove matched prefix to simplify API handlers (only if it's there)
if err = stripPrefix(GitMount, req); err != nil {
log.Err(err).Msgf("Failed striping of prefix for git request.")
render.InternalError(ctx, w)
return return
} }
r.git.ServeHTTP(w, req)
return
} }
render.BadRequestf(ctx, w, "No eligible router found")
/*
* 2. REST API
*
* All Rest API calls start with "/api/", and thus can be uniquely identified.
*/
if r.isAPITraffic(req) {
log.UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Str("http.handler", "api")
})
// remove matched prefix to simplify API handlers
if err = stripPrefix(APIMount, req); err != nil {
log.Err(err).Msgf("Failed striping of prefix for api request.")
render.InternalError(ctx, w)
return
}
r.api.ServeHTTP(w, req)
return
}
/*
* 3. WEB
*
* Everything else will be routed to web (or return 404)
*/
log.UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Str("http.handler", "web")
})
r.web.ServeHTTP(w, req)
} }
// stripPrefix removes the prefix from the request path (or noop if it's not there). // StripPrefix removes the prefix from the request path (or noop if it's not there).
func stripPrefix(prefix string, req *http.Request) error { func StripPrefix(prefix string, req *http.Request) error {
if !strings.HasPrefix(req.URL.Path, prefix) { if !strings.HasPrefix(req.URL.Path, prefix) {
return nil return nil
} }
return request.ReplacePrefix(req, prefix, "") return request.ReplacePrefix(req, prefix, "")
} }
// isGitTraffic returns true iff the request is identified as part of the git http protocol.
func (r *Router) isGitTraffic(req *http.Request) bool {
// git traffic is always reachable via the git mounting path.
if strings.HasPrefix(req.URL.Path, GitMount+"/") {
return true
}
// otherwise check if the request came in via the configured git host (if enabled)
if len(r.gitHost) > 0 {
// cut (optional) port off the host
h, _, _ := strings.Cut(req.Host, ":")
// check if request host matches the configured git host (case insensitive)
if r.gitHost == strings.ToLower(h) {
return true
}
}
// otherwise we don't treat it as git traffic
return false
}
// isAPITraffic returns true iff the request is identified as part of our rest API.
func (r *Router) isAPITraffic(req *http.Request) bool {
return strings.HasPrefix(req.URL.Path, APIMount+"/")
}

View File

@ -29,15 +29,10 @@ import (
"github.com/unrolled/secure" "github.com/unrolled/secure"
) )
// WebHandler is an abstraction of an http handler that handles web calls.
type WebHandler interface {
http.Handler
}
// NewWebHandler returns a new WebHandler. // NewWebHandler returns a new WebHandler.
func NewWebHandler(config *types.Config, func NewWebHandler(config *types.Config,
openapi openapi.Service, openapi openapi.Service,
) WebHandler { ) http.Handler {
// Use go-chi router for inner routing // Use go-chi router for inner routing
r := chi.NewRouter() r := chi.NewRouter()
// create middleware to enforce security best practices for // create middleware to enforce security best practices for

43
app/router/web_router.go Normal file
View File

@ -0,0 +1,43 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package router
import (
"net/http"
"github.com/harness/gitness/logging"
)
type WebRouter struct {
handler http.Handler
}
func NewWebRouter(handler http.Handler) *WebRouter {
return &WebRouter{handler: handler}
}
func (r *WebRouter) Handle(w http.ResponseWriter, req *http.Request) {
req = req.WithContext(logging.NewContext(req.Context(), WithLoggingRouter("web")))
r.handler.ServeHTTP(w, req)
}
func (r *WebRouter) IsEligibleTraffic(*http.Request) bool {
// Everything else will be routed to web (or return 404)
return true
}
func (r *WebRouter) Name() string {
return "web"
}

View File

@ -54,20 +54,12 @@ import (
// WireSet provides a wire set for this package. // WireSet provides a wire set for this package.
var WireSet = wire.NewSet( var WireSet = wire.NewSet(
ProvideRouter, ProvideRouter,
ProvideGitHandler,
ProvideAPIHandler,
ProvideWebHandler,
) )
func ProvideRouter( func GetGitRoutingHost(ctx context.Context, urlProvider url.Provider) string {
api APIHandler,
git GitHandler,
web WebHandler,
urlProvider url.Provider,
) *Router {
// use url provider as it has the latest data. // use url provider as it has the latest data.
gitHostname := urlProvider.GetGITHostname() gitHostname := urlProvider.GetGITHostname(ctx)
apiHostname := urlProvider.GetAPIHostname() apiHostname := urlProvider.GetAPIHostname(ctx)
// only use host name to identify git traffic if it differs from api hostname. // only use host name to identify git traffic if it differs from api hostname.
// TODO: Can we make this even more flexible - aka use the full base urls to route traffic? // TODO: Can we make this even more flexible - aka use the full base urls to route traffic?
@ -75,23 +67,11 @@ func ProvideRouter(
if !strings.EqualFold(gitHostname, apiHostname) { if !strings.EqualFold(gitHostname, apiHostname) {
gitRoutingHost = gitHostname gitRoutingHost = gitHostname
} }
return gitRoutingHost
return NewRouter(api, git, web, gitRoutingHost)
} }
func ProvideGitHandler( // ProvideRouter provides ordered list of routers.
urlProvider url.Provider, func ProvideRouter(
authenticator authn.Authenticator,
repoCtrl *repo.Controller,
) GitHandler {
return NewGitHandler(
urlProvider,
authenticator,
repoCtrl,
)
}
func ProvideAPIHandler(
appCtx context.Context, appCtx context.Context,
config *types.Config, config *types.Config,
authenticator authn.Authenticator, authenticator authn.Authenticator,
@ -120,14 +100,28 @@ func ProvideAPIHandler(
infraProviderCtrl *infraprovider.Controller, infraProviderCtrl *infraprovider.Controller,
gitspaceCtrl *gitspace.Controller, gitspaceCtrl *gitspace.Controller,
migrateCtrl *migrate.Controller, migrateCtrl *migrate.Controller,
) APIHandler { urlProvider url.Provider,
return NewAPIHandler(appCtx, config, openapi openapi.Service,
) *Router {
routers := make([]Interface, 3)
gitRoutingHost := GetGitRoutingHost(appCtx, urlProvider)
gitHandler := NewGitHandler(
urlProvider,
authenticator,
repoCtrl,
)
routers[0] = NewGitRouter(gitHandler, gitRoutingHost)
apiHandler := NewAPIHandler(appCtx, config,
authenticator, repoCtrl, repoSettingsCtrl, executionCtrl, logCtrl, spaceCtrl, pipelineCtrl, authenticator, repoCtrl, repoSettingsCtrl, executionCtrl, logCtrl, spaceCtrl, pipelineCtrl,
secretCtrl, triggerCtrl, connectorCtrl, templateCtrl, pluginCtrl, pullreqCtrl, webhookCtrl, secretCtrl, triggerCtrl, connectorCtrl, templateCtrl, pluginCtrl, pullreqCtrl, webhookCtrl,
githookCtrl, git, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl, blobCtrl, searchCtrl, githookCtrl, git, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl, blobCtrl, searchCtrl,
infraProviderCtrl, migrateCtrl, gitspaceCtrl) infraProviderCtrl, migrateCtrl, gitspaceCtrl)
} routers[1] = NewAPIRouter(apiHandler)
func ProvideWebHandler(config *types.Config, openapi openapi.Service) WebHandler { webHandler := NewWebHandler(config, openapi)
return NewWebHandler(config, openapi) routers[2] = NewWebRouter(webHandler)
return NewRouter(routers)
} }

View File

@ -548,7 +548,7 @@ func (r *Repository) createEnvVars(ctx context.Context,
) (map[string]string, error) { ) (map[string]string, error) {
envVars, err := githook.GenerateEnvironmentVariables( envVars, err := githook.GenerateEnvironmentVariables(
ctx, ctx,
r.urlProvider.GetInternalAPIURL(), r.urlProvider.GetInternalAPIURL(ctx),
repoID, repoID,
principal.ID, principal.ID,
false, false,

View File

@ -180,6 +180,6 @@ func (s *Service) getBasePayload(
Repo: repo, Repo: repo,
PullReq: pullReq, PullReq: pullReq,
Author: author, Author: author,
PullReqURL: s.urlProvider.GenerateUIPRURL(repo.Path, pullReq.Number), PullReqURL: s.urlProvider.GenerateUIPRURL(ctx, repo.Path, pullReq.Number),
}, nil }, nil
} }

View File

@ -259,7 +259,7 @@ func createSystemRPCWriteParams(
// generate envars (add everything githook CLI needs for execution) // generate envars (add everything githook CLI needs for execution)
envVars, err := githook.GenerateEnvironmentVariables( envVars, err := githook.GenerateEnvironmentVariables(
ctx, ctx,
urlProvider.GetInternalAPIURL(), urlProvider.GetInternalAPIURL(ctx),
repoID, repoID,
principal.ID, principal.ID,
false, false,

View File

@ -62,7 +62,7 @@ func (s *Service) handleUpdateDefaultBranch(
systemPrincipal := bootstrap.NewSystemServiceSession().Principal systemPrincipal := bootstrap.NewSystemServiceSession().Principal
envVars, err := githook.GenerateEnvironmentVariables( envVars, err := githook.GenerateEnvironmentVariables(
ctx, ctx,
s.urlProvider.GetInternalAPIURL(), s.urlProvider.GetInternalAPIURL(ctx),
repo.ID, repo.ID,
systemPrincipal.ID, systemPrincipal.ID,
true, true,

View File

@ -48,7 +48,7 @@ func (s *Service) handleEventBranchCreated(ctx context.Context,
if err != nil { if err != nil {
return nil, err return nil, err
} }
repoInfo := repositoryInfoFrom(repo, s.urlProvider) repoInfo := repositoryInfoFrom(ctx, repo, s.urlProvider)
return &ReferencePayload{ return &ReferencePayload{
BaseSegment: BaseSegment{ BaseSegment: BaseSegment{
@ -89,7 +89,7 @@ func (s *Service) handleEventBranchUpdated(ctx context.Context,
} }
commitInfo := commitsInfo[0] commitInfo := commitsInfo[0]
repoInfo := repositoryInfoFrom(repo, s.urlProvider) repoInfo := repositoryInfoFrom(ctx, repo, s.urlProvider)
return &ReferencePayload{ return &ReferencePayload{
BaseSegment: BaseSegment{ BaseSegment: BaseSegment{
@ -125,7 +125,7 @@ func (s *Service) handleEventBranchDeleted(ctx context.Context,
return s.triggerForEventWithRepo(ctx, enum.WebhookTriggerBranchDeleted, return s.triggerForEventWithRepo(ctx, enum.WebhookTriggerBranchDeleted,
event.ID, event.Payload.PrincipalID, event.Payload.RepoID, event.ID, event.Payload.PrincipalID, event.Payload.RepoID,
func(principal *types.Principal, repo *types.Repository) (any, error) { func(principal *types.Principal, repo *types.Repository) (any, error) {
repoInfo := repositoryInfoFrom(repo, s.urlProvider) repoInfo := repositoryInfoFrom(ctx, repo, s.urlProvider)
return &ReferencePayload{ return &ReferencePayload{
BaseSegment: BaseSegment{ BaseSegment: BaseSegment{

View File

@ -50,8 +50,8 @@ func (s *Service) handleEventPullReqCreated(ctx context.Context,
if err != nil { if err != nil {
return nil, err return nil, err
} }
targetRepoInfo := repositoryInfoFrom(targetRepo, s.urlProvider) targetRepoInfo := repositoryInfoFrom(ctx, targetRepo, s.urlProvider)
sourceRepoInfo := repositoryInfoFrom(sourceRepo, s.urlProvider) sourceRepoInfo := repositoryInfoFrom(ctx, sourceRepo, s.urlProvider)
return &PullReqCreatedPayload{ return &PullReqCreatedPayload{
BaseSegment: BaseSegment{ BaseSegment: BaseSegment{
@ -60,7 +60,7 @@ func (s *Service) handleEventPullReqCreated(ctx context.Context,
Principal: principalInfoFrom(principal.ToPrincipalInfo()), Principal: principalInfoFrom(principal.ToPrincipalInfo()),
}, },
PullReqSegment: PullReqSegment{ PullReqSegment: PullReqSegment{
PullReq: pullReqInfoFrom(pr, targetRepo, s.urlProvider), PullReq: pullReqInfoFrom(ctx, pr, targetRepo, s.urlProvider),
}, },
PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{ PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{
TargetRef: ReferenceInfo{ TargetRef: ReferenceInfo{
@ -98,8 +98,8 @@ func (s *Service) handleEventPullReqReopened(ctx context.Context,
if err != nil { if err != nil {
return nil, err return nil, err
} }
targetRepoInfo := repositoryInfoFrom(targetRepo, s.urlProvider) targetRepoInfo := repositoryInfoFrom(ctx, targetRepo, s.urlProvider)
sourceRepoInfo := repositoryInfoFrom(sourceRepo, s.urlProvider) sourceRepoInfo := repositoryInfoFrom(ctx, sourceRepo, s.urlProvider)
return &PullReqReopenedPayload{ return &PullReqReopenedPayload{
BaseSegment: BaseSegment{ BaseSegment: BaseSegment{
@ -108,7 +108,7 @@ func (s *Service) handleEventPullReqReopened(ctx context.Context,
Principal: principalInfoFrom(principal.ToPrincipalInfo()), Principal: principalInfoFrom(principal.ToPrincipalInfo()),
}, },
PullReqSegment: PullReqSegment{ PullReqSegment: PullReqSegment{
PullReq: pullReqInfoFrom(pr, targetRepo, s.urlProvider), PullReq: pullReqInfoFrom(ctx, pr, targetRepo, s.urlProvider),
}, },
PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{ PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{
TargetRef: ReferenceInfo{ TargetRef: ReferenceInfo{
@ -156,8 +156,8 @@ func (s *Service) handleEventPullReqBranchUpdated(ctx context.Context,
} }
commitInfo := commitsInfo[0] commitInfo := commitsInfo[0]
targetRepoInfo := repositoryInfoFrom(targetRepo, s.urlProvider) targetRepoInfo := repositoryInfoFrom(ctx, targetRepo, s.urlProvider)
sourceRepoInfo := repositoryInfoFrom(sourceRepo, s.urlProvider) sourceRepoInfo := repositoryInfoFrom(ctx, sourceRepo, s.urlProvider)
return &PullReqBranchUpdatedPayload{ return &PullReqBranchUpdatedPayload{
BaseSegment: BaseSegment{ BaseSegment: BaseSegment{
@ -166,7 +166,7 @@ func (s *Service) handleEventPullReqBranchUpdated(ctx context.Context,
Principal: principalInfoFrom(principal.ToPrincipalInfo()), Principal: principalInfoFrom(principal.ToPrincipalInfo()),
}, },
PullReqSegment: PullReqSegment{ PullReqSegment: PullReqSegment{
PullReq: pullReqInfoFrom(pr, targetRepo, s.urlProvider), PullReq: pullReqInfoFrom(ctx, pr, targetRepo, s.urlProvider),
}, },
PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{ PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{
TargetRef: ReferenceInfo{ TargetRef: ReferenceInfo{
@ -213,8 +213,8 @@ func (s *Service) handleEventPullReqClosed(ctx context.Context,
if err != nil { if err != nil {
return nil, err return nil, err
} }
targetRepoInfo := repositoryInfoFrom(targetRepo, s.urlProvider) targetRepoInfo := repositoryInfoFrom(ctx, targetRepo, s.urlProvider)
sourceRepoInfo := repositoryInfoFrom(sourceRepo, s.urlProvider) sourceRepoInfo := repositoryInfoFrom(ctx, sourceRepo, s.urlProvider)
return &PullReqClosedPayload{ return &PullReqClosedPayload{
BaseSegment: BaseSegment{ BaseSegment: BaseSegment{
@ -223,7 +223,7 @@ func (s *Service) handleEventPullReqClosed(ctx context.Context,
Principal: principalInfoFrom(principal.ToPrincipalInfo()), Principal: principalInfoFrom(principal.ToPrincipalInfo()),
}, },
PullReqSegment: PullReqSegment{ PullReqSegment: PullReqSegment{
PullReq: pullReqInfoFrom(pr, targetRepo, s.urlProvider), PullReq: pullReqInfoFrom(ctx, pr, targetRepo, s.urlProvider),
}, },
PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{ PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{
TargetRef: ReferenceInfo{ TargetRef: ReferenceInfo{
@ -264,8 +264,8 @@ func (s *Service) handleEventPullReqMerged(ctx context.Context,
if err != nil { if err != nil {
return nil, err return nil, err
} }
targetRepoInfo := repositoryInfoFrom(targetRepo, s.urlProvider) targetRepoInfo := repositoryInfoFrom(ctx, targetRepo, s.urlProvider)
sourceRepoInfo := repositoryInfoFrom(sourceRepo, s.urlProvider) sourceRepoInfo := repositoryInfoFrom(ctx, sourceRepo, s.urlProvider)
return &PullReqClosedPayload{ return &PullReqClosedPayload{
BaseSegment: BaseSegment{ BaseSegment: BaseSegment{
@ -274,7 +274,7 @@ func (s *Service) handleEventPullReqMerged(ctx context.Context,
Principal: principalInfoFrom(principal.ToPrincipalInfo()), Principal: principalInfoFrom(principal.ToPrincipalInfo()),
}, },
PullReqSegment: PullReqSegment{ PullReqSegment: PullReqSegment{
PullReq: pullReqInfoFrom(pr, targetRepo, s.urlProvider), PullReq: pullReqInfoFrom(ctx, pr, targetRepo, s.urlProvider),
}, },
PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{ PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{
TargetRef: ReferenceInfo{ TargetRef: ReferenceInfo{
@ -314,8 +314,8 @@ func (s *Service) handleEventPullReqComment(
return s.triggerForEventWithPullReq(ctx, enum.WebhookTriggerPullReqCommentCreated, return s.triggerForEventWithPullReq(ctx, enum.WebhookTriggerPullReqCommentCreated,
event.ID, event.Payload.PrincipalID, event.Payload.PullReqID, event.ID, event.Payload.PrincipalID, event.Payload.PullReqID,
func(principal *types.Principal, pr *types.PullReq, targetRepo, sourceRepo *types.Repository) (any, error) { func(principal *types.Principal, pr *types.PullReq, targetRepo, sourceRepo *types.Repository) (any, error) {
targetRepoInfo := repositoryInfoFrom(targetRepo, s.urlProvider) targetRepoInfo := repositoryInfoFrom(ctx, targetRepo, s.urlProvider)
sourceRepoInfo := repositoryInfoFrom(sourceRepo, s.urlProvider) sourceRepoInfo := repositoryInfoFrom(ctx, sourceRepo, s.urlProvider)
activity, err := s.activityStore.Find(ctx, event.Payload.ActivityID) activity, err := s.activityStore.Find(ctx, event.Payload.ActivityID)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get activity by id for acitivity id %d: %w", event.Payload.ActivityID, err) return nil, fmt.Errorf("failed to get activity by id for acitivity id %d: %w", event.Payload.ActivityID, err)
@ -331,7 +331,7 @@ func (s *Service) handleEventPullReqComment(
Principal: principalInfoFrom(principal.ToPrincipalInfo()), Principal: principalInfoFrom(principal.ToPrincipalInfo()),
}, },
PullReqSegment: PullReqSegment{ PullReqSegment: PullReqSegment{
PullReq: pullReqInfoFrom(pr, targetRepo, s.urlProvider), PullReq: pullReqInfoFrom(ctx, pr, targetRepo, s.urlProvider),
}, },
PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{ PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{
TargetRef: ReferenceInfo{ TargetRef: ReferenceInfo{

View File

@ -34,7 +34,7 @@ func (s *Service) handleEventTagCreated(ctx context.Context,
if err != nil { if err != nil {
return nil, err return nil, err
} }
repoInfo := repositoryInfoFrom(repo, s.urlProvider) repoInfo := repositoryInfoFrom(ctx, repo, s.urlProvider)
return &ReferencePayload{ return &ReferencePayload{
BaseSegment: BaseSegment{ BaseSegment: BaseSegment{
@ -78,7 +78,7 @@ func (s *Service) handleEventTagUpdated(ctx context.Context,
if len(commitsInfo) > 0 { if len(commitsInfo) > 0 {
commitInfo = commitsInfo[0] commitInfo = commitsInfo[0]
} }
repoInfo := repositoryInfoFrom(repo, s.urlProvider) repoInfo := repositoryInfoFrom(ctx, repo, s.urlProvider)
return &ReferencePayload{ return &ReferencePayload{
BaseSegment: BaseSegment{ BaseSegment: BaseSegment{
@ -114,7 +114,7 @@ func (s *Service) handleEventTagDeleted(ctx context.Context,
return s.triggerForEventWithRepo(ctx, enum.WebhookTriggerTagDeleted, return s.triggerForEventWithRepo(ctx, enum.WebhookTriggerTagDeleted,
event.ID, event.Payload.PrincipalID, event.Payload.RepoID, event.ID, event.Payload.PrincipalID, event.Payload.RepoID,
func(principal *types.Principal, repo *types.Repository) (any, error) { func(principal *types.Principal, repo *types.Repository) (any, error) {
repoInfo := repositoryInfoFrom(repo, s.urlProvider) repoInfo := repositoryInfoFrom(ctx, repo, s.urlProvider)
return &ReferencePayload{ return &ReferencePayload{
BaseSegment: BaseSegment{ BaseSegment: BaseSegment{

View File

@ -15,6 +15,7 @@
package webhook package webhook
import ( import (
"context"
"encoding/json" "encoding/json"
"time" "time"
@ -104,14 +105,14 @@ func (r RepositoryInfo) MarshalJSON() ([]byte, error) {
} }
// repositoryInfoFrom gets the RespositoryInfo from a types.Repository. // repositoryInfoFrom gets the RespositoryInfo from a types.Repository.
func repositoryInfoFrom(repo *types.Repository, urlProvider url.Provider) RepositoryInfo { func repositoryInfoFrom(ctx context.Context, repo *types.Repository, urlProvider url.Provider) RepositoryInfo {
return RepositoryInfo{ return RepositoryInfo{
ID: repo.ID, ID: repo.ID,
Path: repo.Path, Path: repo.Path,
Identifier: repo.Identifier, Identifier: repo.Identifier,
DefaultBranch: repo.DefaultBranch, DefaultBranch: repo.DefaultBranch,
GitURL: urlProvider.GenerateGITCloneURL(repo.Path), GitURL: urlProvider.GenerateGITCloneURL(ctx, repo.Path),
GitSSHURL: urlProvider.GenerateGITCloneSSHURL(repo.Path), GitSSHURL: urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path),
} }
} }
@ -133,7 +134,12 @@ type PullReqInfo struct {
} }
// pullReqInfoFrom gets the PullReqInfo from a types.PullReq. // pullReqInfoFrom gets the PullReqInfo from a types.PullReq.
func pullReqInfoFrom(pr *types.PullReq, repo *types.Repository, urlProvider url.Provider) PullReqInfo { func pullReqInfoFrom(
ctx context.Context,
pr *types.PullReq,
repo *types.Repository,
urlProvider url.Provider,
) PullReqInfo {
return PullReqInfo{ return PullReqInfo{
Number: pr.Number, Number: pr.Number,
State: pr.State, State: pr.State,
@ -146,7 +152,7 @@ func pullReqInfoFrom(pr *types.PullReq, repo *types.Repository, urlProvider url.
TargetBranch: pr.TargetBranch, TargetBranch: pr.TargetBranch,
MergeStrategy: pr.MergeMethod, MergeStrategy: pr.MergeMethod,
Author: principalInfoFrom(&pr.Author), Author: principalInfoFrom(&pr.Author),
PrURL: urlProvider.GenerateUIPRURL(repo.Path, pr.Number), PrURL: urlProvider.GenerateUIPRURL(ctx, repo.Path, pr.Number),
} }
} }

View File

@ -15,6 +15,7 @@
package url package url
import ( import (
"context"
"fmt" "fmt"
"net/url" "net/url"
"path" "path"
@ -38,40 +39,40 @@ const (
type Provider interface { type Provider interface {
// GetInternalAPIURL returns the internally reachable base url of the server. // GetInternalAPIURL returns the internally reachable base url of the server.
// NOTE: url is guaranteed to not have any trailing '/'. // NOTE: url is guaranteed to not have any trailing '/'.
GetInternalAPIURL() string GetInternalAPIURL(ctx context.Context) string
// GenerateContainerGITCloneURL generates a URL that can be used by CI container builds to // GenerateContainerGITCloneURL generates a URL that can be used by CI container builds to
// interact with gitness and clone a repo. // interact with gitness and clone a repo.
GenerateContainerGITCloneURL(repoPath string) string GenerateContainerGITCloneURL(ctx context.Context, repoPath string) string
// GenerateGITCloneURL generates the public git clone URL for the provided repo path. // GenerateGITCloneURL generates the public git clone URL for the provided repo path.
// NOTE: url is guaranteed to not have any trailing '/'. // NOTE: url is guaranteed to not have any trailing '/'.
GenerateGITCloneURL(repoPath string) string GenerateGITCloneURL(ctx context.Context, repoPath string) string
// GenerateGITCloneSSHURL generates the public git clone URL for the provided repo path. // GenerateGITCloneSSHURL generates the public git clone URL for the provided repo path.
// NOTE: url is guaranteed to not have any trailing '/'. // NOTE: url is guaranteed to not have any trailing '/'.
GenerateGITCloneSSHURL(repoPath string) string GenerateGITCloneSSHURL(ctx context.Context, repoPath string) string
// GenerateUIRepoURL returns the url for the UI screen of a repository. // GenerateUIRepoURL returns the url for the UI screen of a repository.
GenerateUIRepoURL(repoPath string) string GenerateUIRepoURL(ctx context.Context, repoPath string) string
// GenerateUIPRURL returns the url for the UI screen of an existing pr. // GenerateUIPRURL returns the url for the UI screen of an existing pr.
GenerateUIPRURL(repoPath string, prID int64) string GenerateUIPRURL(ctx context.Context, repoPath string, prID int64) string
// GenerateUICompareURL returns the url for the UI screen comparing two references. // GenerateUICompareURL returns the url for the UI screen comparing two references.
GenerateUICompareURL(repoPath string, ref1 string, ref2 string) string GenerateUICompareURL(ctx context.Context, repoPath string, ref1 string, ref2 string) string
// GetAPIHostname returns the host for the api endpoint. // GetAPIHostname returns the host for the api endpoint.
GetAPIHostname() string GetAPIHostname(ctx context.Context) string
// GenerateUIBuildURL returns the endpoint to use for viewing build executions. // GenerateUIBuildURL returns the endpoint to use for viewing build executions.
GenerateUIBuildURL(repoPath, pipelineIdentifier string, seqNumber int64) string GenerateUIBuildURL(ctx context.Context, repoPath, pipelineIdentifier string, seqNumber int64) string
// GetGITHostname returns the host for the git endpoint. // GetGITHostname returns the host for the git endpoint.
GetGITHostname() string GetGITHostname(ctx context.Context) string
// GetAPIProto returns the proto for the API hostname // GetAPIProto returns the proto for the API hostname
GetAPIProto() string GetAPIProto(ctx context.Context) string
} }
// Provider provides the URLs of the gitness system. // Provider provides the URLs of the gitness system.
@ -159,11 +160,11 @@ func NewProvider(
}, nil }, nil
} }
func (p *provider) GetInternalAPIURL() string { func (p *provider) GetInternalAPIURL(context.Context) string {
return p.internalURL.JoinPath(APIMount).String() return p.internalURL.JoinPath(APIMount).String()
} }
func (p *provider) GenerateContainerGITCloneURL(repoPath string) string { func (p *provider) GenerateContainerGITCloneURL(_ context.Context, repoPath string) string {
repoPath = path.Clean(repoPath) repoPath = path.Clean(repoPath)
if !strings.HasSuffix(repoPath, GITSuffix) { if !strings.HasSuffix(repoPath, GITSuffix) {
repoPath += GITSuffix repoPath += GITSuffix
@ -172,7 +173,7 @@ func (p *provider) GenerateContainerGITCloneURL(repoPath string) string {
return p.containerURL.JoinPath(GITMount, repoPath).String() return p.containerURL.JoinPath(GITMount, repoPath).String()
} }
func (p *provider) GenerateGITCloneURL(repoPath string) string { func (p *provider) GenerateGITCloneURL(_ context.Context, repoPath string) string {
repoPath = path.Clean(repoPath) repoPath = path.Clean(repoPath)
if !strings.HasSuffix(repoPath, GITSuffix) { if !strings.HasSuffix(repoPath, GITSuffix) {
repoPath += GITSuffix repoPath += GITSuffix
@ -181,7 +182,7 @@ func (p *provider) GenerateGITCloneURL(repoPath string) string {
return p.gitURL.JoinPath(repoPath).String() return p.gitURL.JoinPath(repoPath).String()
} }
func (p *provider) GenerateGITCloneSSHURL(repoPath string) string { func (p *provider) GenerateGITCloneSSHURL(_ context.Context, repoPath string) string {
if !p.SSHEnabled { if !p.SSHEnabled {
return "" return ""
} }
@ -193,31 +194,31 @@ func (p *provider) GenerateGITCloneSSHURL(repoPath string) string {
return fmt.Sprintf("%s@%s:%s", p.SSHDefaultUser, p.gitSSHURL.String(), repoPath) return fmt.Sprintf("%s@%s:%s", p.SSHDefaultUser, p.gitSSHURL.String(), repoPath)
} }
func (p *provider) GenerateUIBuildURL(repoPath, pipelineIdentifier string, seqNumber int64) string { func (p *provider) GenerateUIBuildURL(_ context.Context, repoPath, pipelineIdentifier string, seqNumber int64) string {
return p.uiURL.JoinPath(repoPath, "pipelines", return p.uiURL.JoinPath(repoPath, "pipelines",
pipelineIdentifier, "execution", strconv.Itoa(int(seqNumber))).String() pipelineIdentifier, "execution", strconv.Itoa(int(seqNumber))).String()
} }
func (p *provider) GenerateUIRepoURL(repoPath string) string { func (p *provider) GenerateUIRepoURL(_ context.Context, repoPath string) string {
return p.uiURL.JoinPath(repoPath).String() return p.uiURL.JoinPath(repoPath).String()
} }
func (p *provider) GenerateUIPRURL(repoPath string, prID int64) string { func (p *provider) GenerateUIPRURL(_ context.Context, repoPath string, prID int64) string {
return p.uiURL.JoinPath(repoPath, "pulls", fmt.Sprint(prID)).String() return p.uiURL.JoinPath(repoPath, "pulls", fmt.Sprint(prID)).String()
} }
func (p *provider) GenerateUICompareURL(repoPath string, ref1 string, ref2 string) string { func (p *provider) GenerateUICompareURL(_ context.Context, repoPath string, ref1 string, ref2 string) string {
return p.uiURL.JoinPath(repoPath, "pulls/compare", ref1+"..."+ref2).String() return p.uiURL.JoinPath(repoPath, "pulls/compare", ref1+"..."+ref2).String()
} }
func (p *provider) GetAPIHostname() string { func (p *provider) GetAPIHostname(context.Context) string {
return p.apiURL.Hostname() return p.apiURL.Hostname()
} }
func (p *provider) GetGITHostname() string { func (p *provider) GetGITHostname(context.Context) string {
return p.gitURL.Hostname() return p.gitURL.Hostname()
} }
func (p *provider) GetAPIProto() string { func (p *provider) GetAPIProto(context.Context) string {
return p.apiURL.Scheme return p.apiURL.Scheme
} }

View File

@ -349,11 +349,8 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
gitspaceEventStore := database.ProvideGitspaceEventStore(db) gitspaceEventStore := database.ProvideGitspaceEventStore(db)
gitspaceController := gitspace2.ProvideController(transactor, authorizer, infraproviderService, gitspaceConfigStore, gitspaceInstanceStore, spaceStore, reporter3, orchestratorOrchestrator, gitspaceEventStore, statefulLogger, scmSCM) gitspaceController := gitspace2.ProvideController(transactor, authorizer, infraproviderService, gitspaceConfigStore, gitspaceInstanceStore, spaceStore, reporter3, orchestratorOrchestrator, gitspaceEventStore, statefulLogger, scmSCM)
migrateController := migrate.ProvideController(authorizer, principalStore) migrateController := migrate.ProvideController(authorizer, principalStore)
apiHandler := router.ProvideAPIHandler(ctx, config, authenticator, repoController, reposettingsController, executionController, logsController, spaceController, pipelineController, secretController, triggerController, connectorController, templateController, pluginController, pullreqController, webhookController, githookController, gitInterface, serviceaccountController, controller, principalController, checkController, systemController, uploadController, keywordsearchController, infraproviderController, gitspaceController, migrateController)
gitHandler := router.ProvideGitHandler(provider, authenticator, repoController)
openapiService := openapi.ProvideOpenAPIService() openapiService := openapi.ProvideOpenAPIService()
webHandler := router.ProvideWebHandler(config, openapiService) routerRouter := router.ProvideRouter(ctx, config, authenticator, repoController, reposettingsController, executionController, logsController, spaceController, pipelineController, secretController, triggerController, connectorController, templateController, pluginController, pullreqController, webhookController, githookController, gitInterface, serviceaccountController, controller, principalController, checkController, systemController, uploadController, keywordsearchController, infraproviderController, gitspaceController, migrateController, provider, openapiService)
routerRouter := router.ProvideRouter(apiHandler, gitHandler, webHandler, provider)
serverServer := server2.ProvideServer(config, routerRouter) serverServer := server2.ProvideServer(config, routerRouter)
publickeyService := publickey.ProvidePublicKey(publicKeyStore, principalInfoCache) publickeyService := publickey.ProvidePublicKey(publicKeyStore, principalInfoCache)
sshServer := ssh.ProvideServer(config, publickeyService, repoController) sshServer := ssh.ProvideServer(config, publickeyService, repoController)