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
pull/3545/head
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)
for i, pr := range prs {
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...)
return
@ -254,7 +254,7 @@ func (c *Controller) suggestPullRequest(
// this is a new PR!
out.Messages = append(out.Messages,
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
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path)
repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path)
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)
envVars, err := githook.GenerateEnvironmentVariables(
ctx,
c.urlProvider.GetInternalAPIURL(),
c.urlProvider.GetInternalAPIURL(ctx),
0,
session.Principal.ID,
true,

View File

@ -35,8 +35,8 @@ func (c *Controller) Find(ctx context.Context, session *auth.Session, repoRef st
}
// backfill clone url
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path)
repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path)
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
}
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path)
repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path)
err = c.auditService.Log(ctx,
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)
}
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(repo.Path)
repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path)
repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path)
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).
envVars, err := githook.GenerateEnvironmentVariables(
ctx,
c.urlProvider.GetInternalAPIURL(),
c.urlProvider.GetInternalAPIURL(ctx),
0, // no repoID
session.Principal.ID,
true,

View File

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

View File

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

View File

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

View File

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

View File

@ -43,7 +43,7 @@ func HandleGitRedirect(urlProvider url.Provider) http.HandlerFunc {
// NOTE:
// 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.
repoURL := urlProvider.GenerateUIRepoURL(repoRef)
repoURL := urlProvider.GenerateUIRepoURL(ctx, repoRef)
http.Redirect(
w,

View File

@ -15,6 +15,7 @@
package repo
import (
"context"
"errors"
"fmt"
"net/http"
@ -53,7 +54,7 @@ func HandleGitInfoRefs(repoCtrl *repo.Controller, urlProvider url.Provider) http
err = repoCtrl.GitInfoRefs(ctx, session, repoRef, service, gitProtocol, w)
if errors.Is(err, apiauth.ErrNotAuthorized) && auth.IsAnonymousSession(session) {
renderBasicAuth(w, urlProvider)
renderBasicAuth(ctx, w, urlProvider)
return
}
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.
// 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.
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)
}

View File

@ -80,7 +80,7 @@ func HandleGitServicePack(
Protocol: gitProtocol,
})
if errors.Is(err, apiauth.ErrNotAuthorized) && auth.IsAnonymousSession(session) {
renderBasicAuth(w, urlProvider)
renderBasicAuth(ctx, w, urlProvider)
return
}
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),
Netrc: ConvertToDroneNetrc(details.Netrc),
System: &drone.System{
Proto: e.urlProvider.GetAPIProto(),
Host: e.urlProvider.GetAPIHostname(),
Proto: e.urlProvider.GetAPIProto(ctx),
Host: e.urlProvider.GetAPIHostname(ctx),
},
}, 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.
func (m *Manager) Details(_ context.Context, stageID int64) (*ExecutionContext, error) {
func (m *Manager) Details(ctx context.Context, stageID int64) (*ExecutionContext, error) {
log := log.With().
Int64("stage-id", stageID).
Logger()
@ -308,7 +308,7 @@ func (m *Manager) Details(_ context.Context, stageID int64) (*ExecutionContext,
}
// 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)
if err != nil {

View File

@ -15,6 +15,8 @@
package triggerer
import (
"context"
"github.com/harness/gitness/app/url"
"github.com/harness/gitness/types"
@ -32,11 +34,12 @@ func combine(env ...map[string]string) map[string]string {
}
func Envs(
ctx context.Context,
repo *types.Repository,
pipeline *types.Pipeline,
urlProvider url.Provider,
) 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
// would lead to an incremented pipeline sequence number.
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)
if err != nil {

View File

@ -89,11 +89,6 @@ import (
"github.com/rs/zerolog/hlog"
)
// APIHandler is an abstraction of a http handler that handles API calls.
type APIHandler interface {
http.Handler
}
var (
// terminatedPathPrefixesAPI is the list of prefixes that will require resolving terminated paths.
terminatedPathPrefixesAPI = []string{"/v1/spaces/", "/v1/repos/",
@ -130,7 +125,7 @@ func NewAPIHandler(
infraProviderCtrl *infraprovider.Controller,
migrateCtrl *migrate.Controller,
gitspaceCtrl *gitspace.Controller,
) APIHandler {
) http.Handler {
// Use go-chi router for inner routing.
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"
)
// GitHandler is an abstraction of an http handler that handles git calls.
type GitHandler interface {
http.Handler
}
// NewGitHandler returns a new GitHandler.
func NewGitHandler(
urlProvider url.Provider,
authenticator authn.Authenticator,
repoCtrl *repo.Controller,
) GitHandler {
) http.Handler {
// Use go-chi router for inner routing.
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/request"
"github.com/harness/gitness/logging"
"github.com/go-logr/logr"
"github.com/go-logr/zerologr"
@ -27,40 +28,21 @@ import (
"github.com/rs/zerolog/log"
)
const (
APIMount = "/api"
GitMount = "/git"
)
type Router struct {
api APIHandler
git GitHandler
web WebHandler
// gitHost describes the optional host via which git traffic is identified.
// Note: always stored as lowercase.
gitHost string
routers []Interface
}
// NewRouter returns a new http.Handler that routes traffic
// to the appropriate handlers.
func NewRouter(
api APIHandler,
git GitHandler,
web WebHandler,
gitHost string,
routers []Interface,
) *Router {
return &Router{
api: api,
git: git,
web: web,
gitHost: strings.ToLower(gitHost),
routers: routers,
}
}
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var err error
// setup logger for request
log := log.Logger.With().Logger()
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())
})
/*
* 1. GIT
*
* All Git originating traffic starts with "/space1/space2/repo.git".
*/
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)
for _, router := range r.routers {
if ok := router.IsEligibleTraffic(req); ok {
req = req.WithContext(logging.NewContext(req.Context(), WithLoggingRouter(router.Name())))
router.Handle(w, req)
return
}
r.git.ServeHTTP(w, req)
return
}
/*
* 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)
render.BadRequestf(ctx, w, "No eligible router found")
}
// stripPrefix removes the prefix from the request path (or noop if it's not there).
func stripPrefix(prefix string, req *http.Request) error {
// StripPrefix removes the prefix from the request path (or noop if it's not there).
func StripPrefix(prefix string, req *http.Request) error {
if !strings.HasPrefix(req.URL.Path, prefix) {
return nil
}
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"
)
// WebHandler is an abstraction of an http handler that handles web calls.
type WebHandler interface {
http.Handler
}
// NewWebHandler returns a new WebHandler.
func NewWebHandler(config *types.Config,
openapi openapi.Service,
) WebHandler {
) http.Handler {
// Use go-chi router for inner routing
r := chi.NewRouter()
// 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.
var WireSet = wire.NewSet(
ProvideRouter,
ProvideGitHandler,
ProvideAPIHandler,
ProvideWebHandler,
)
func ProvideRouter(
api APIHandler,
git GitHandler,
web WebHandler,
urlProvider url.Provider,
) *Router {
func GetGitRoutingHost(ctx context.Context, urlProvider url.Provider) string {
// use url provider as it has the latest data.
gitHostname := urlProvider.GetGITHostname()
apiHostname := urlProvider.GetAPIHostname()
gitHostname := urlProvider.GetGITHostname(ctx)
apiHostname := urlProvider.GetAPIHostname(ctx)
// 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?
@ -75,23 +67,11 @@ func ProvideRouter(
if !strings.EqualFold(gitHostname, apiHostname) {
gitRoutingHost = gitHostname
}
return NewRouter(api, git, web, gitRoutingHost)
return gitRoutingHost
}
func ProvideGitHandler(
urlProvider url.Provider,
authenticator authn.Authenticator,
repoCtrl *repo.Controller,
) GitHandler {
return NewGitHandler(
urlProvider,
authenticator,
repoCtrl,
)
}
func ProvideAPIHandler(
// ProvideRouter provides ordered list of routers.
func ProvideRouter(
appCtx context.Context,
config *types.Config,
authenticator authn.Authenticator,
@ -120,14 +100,28 @@ func ProvideAPIHandler(
infraProviderCtrl *infraprovider.Controller,
gitspaceCtrl *gitspace.Controller,
migrateCtrl *migrate.Controller,
) APIHandler {
return NewAPIHandler(appCtx, config,
urlProvider url.Provider,
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,
secretCtrl, triggerCtrl, connectorCtrl, templateCtrl, pluginCtrl, pullreqCtrl, webhookCtrl,
githookCtrl, git, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl, blobCtrl, searchCtrl,
infraProviderCtrl, migrateCtrl, gitspaceCtrl)
}
routers[1] = NewAPIRouter(apiHandler)
func ProvideWebHandler(config *types.Config, openapi openapi.Service) WebHandler {
return NewWebHandler(config, openapi)
webHandler := 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) {
envVars, err := githook.GenerateEnvironmentVariables(
ctx,
r.urlProvider.GetInternalAPIURL(),
r.urlProvider.GetInternalAPIURL(ctx),
repoID,
principal.ID,
false,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,6 +15,7 @@
package webhook
import (
"context"
"encoding/json"
"time"
@ -104,14 +105,14 @@ func (r RepositoryInfo) MarshalJSON() ([]byte, error) {
}
// 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{
ID: repo.ID,
Path: repo.Path,
Identifier: repo.Identifier,
DefaultBranch: repo.DefaultBranch,
GitURL: urlProvider.GenerateGITCloneURL(repo.Path),
GitSSHURL: urlProvider.GenerateGITCloneSSHURL(repo.Path),
GitURL: urlProvider.GenerateGITCloneURL(ctx, repo.Path),
GitSSHURL: urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path),
}
}
@ -133,7 +134,12 @@ type PullReqInfo struct {
}
// 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{
Number: pr.Number,
State: pr.State,
@ -146,7 +152,7 @@ func pullReqInfoFrom(pr *types.PullReq, repo *types.Repository, urlProvider url.
TargetBranch: pr.TargetBranch,
MergeStrategy: pr.MergeMethod,
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
import (
"context"
"fmt"
"net/url"
"path"
@ -38,40 +39,40 @@ const (
type Provider interface {
// GetInternalAPIURL returns the internally reachable base url of the server.
// 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
// 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.
// 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.
// 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(repoPath string) string
GenerateUIRepoURL(ctx context.Context, repoPath string) string
// 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(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() string
GetAPIHostname(ctx context.Context) string
// 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() string
GetGITHostname(ctx context.Context) string
// GetAPIProto returns the proto for the API hostname
GetAPIProto() string
GetAPIProto(ctx context.Context) string
}
// Provider provides the URLs of the gitness system.
@ -159,11 +160,11 @@ func NewProvider(
}, nil
}
func (p *provider) GetInternalAPIURL() string {
func (p *provider) GetInternalAPIURL(context.Context) 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)
if !strings.HasSuffix(repoPath, GITSuffix) {
repoPath += GITSuffix
@ -172,7 +173,7 @@ func (p *provider) GenerateContainerGITCloneURL(repoPath string) 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)
if !strings.HasSuffix(repoPath, GITSuffix) {
repoPath += GITSuffix
@ -181,7 +182,7 @@ func (p *provider) GenerateGITCloneURL(repoPath string) 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 {
return ""
}
@ -193,31 +194,31 @@ func (p *provider) GenerateGITCloneSSHURL(repoPath string) string {
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",
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()
}
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()
}
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()
}
func (p *provider) GetAPIHostname() string {
func (p *provider) GetAPIHostname(context.Context) string {
return p.apiURL.Hostname()
}
func (p *provider) GetGITHostname() string {
func (p *provider) GetGITHostname(context.Context) string {
return p.gitURL.Hostname()
}
func (p *provider) GetAPIProto() string {
func (p *provider) GetAPIProto(context.Context) string {
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)
gitspaceController := gitspace2.ProvideController(transactor, authorizer, infraproviderService, gitspaceConfigStore, gitspaceInstanceStore, spaceStore, reporter3, orchestratorOrchestrator, gitspaceEventStore, statefulLogger, scmSCM)
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()
webHandler := router.ProvideWebHandler(config, openapiService)
routerRouter := router.ProvideRouter(apiHandler, gitHandler, webHandler, provider)
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)
serverServer := server2.ProvideServer(config, routerRouter)
publickeyService := publickey.ProvidePublicKey(publicKeyStore, principalInfoCache)
sshServer := ssh.ProvideServer(config, publickeyService, repoController)