mirror of https://github.com/harness/drone.git
Add alternate_object_dirs support to githook handlers (#1141)
parent
96f35b6e01
commit
e96ab4159b
|
@ -26,40 +26,15 @@ import (
|
|||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// ServerHookOutput represents the output of server hook api calls.
|
||||
// TODO: support non-error messages (once we need it).
|
||||
type ServerHookOutput struct {
|
||||
// Error contains the user facing error (like "branch is protected", ...).
|
||||
Error *string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ReferenceUpdate represents an update of a git reference.
|
||||
type ReferenceUpdate struct {
|
||||
// Ref is the full name of the reference that got updated.
|
||||
Ref string `json:"ref"`
|
||||
// Old is the old commmit hash (before the update).
|
||||
Old string `json:"old"`
|
||||
// New is the new commit hash (after the update).
|
||||
New string `json:"new"`
|
||||
}
|
||||
|
||||
// BaseInput contains the base input for any githook api call.
|
||||
type BaseInput struct {
|
||||
RepoID int64 `json:"repo_id"`
|
||||
PrincipalID int64 `json:"principal_id"`
|
||||
}
|
||||
|
||||
type Controller struct {
|
||||
authorizer authz.Authorizer
|
||||
principalStore store.PrincipalStore
|
||||
repoStore store.RepoStore
|
||||
gitReporter *eventsgit.Reporter
|
||||
git git.Interface
|
||||
pullreqStore store.PullReqStore
|
||||
urlProvider url.Provider
|
||||
protectionManager *protection.Manager
|
||||
|
@ -74,7 +49,6 @@ func NewController(
|
|||
principalStore store.PrincipalStore,
|
||||
repoStore store.RepoStore,
|
||||
gitReporter *eventsgit.Reporter,
|
||||
git git.Interface,
|
||||
pullreqStore store.PullReqStore,
|
||||
urlProvider url.Provider,
|
||||
protectionManager *protection.Manager,
|
||||
|
@ -89,7 +63,6 @@ func NewController(
|
|||
principalStore: principalStore,
|
||||
repoStore: repoStore,
|
||||
gitReporter: gitReporter,
|
||||
git: git,
|
||||
pullreqStore: pullreqStore,
|
||||
urlProvider: urlProvider,
|
||||
protectionManager: protectionManager,
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
type PreReceiveExtender interface {
|
||||
Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.Repository,
|
||||
types.GithookPreReceiveInput,
|
||||
|
@ -35,6 +36,7 @@ type PreReceiveExtender interface {
|
|||
type UpdateExtender interface {
|
||||
Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.Repository,
|
||||
types.GithookUpdateInput,
|
||||
|
@ -45,6 +47,7 @@ type UpdateExtender interface {
|
|||
type PostReceiveExtender interface {
|
||||
Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.Repository,
|
||||
types.GithookPostReceiveInput,
|
||||
|
@ -61,6 +64,7 @@ func NewPreReceiveExtender() PreReceiveExtender {
|
|||
|
||||
func (NoOpPreReceiveExtender) Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.Repository,
|
||||
types.GithookPreReceiveInput,
|
||||
|
@ -78,6 +82,7 @@ func NewUpdateExtender() UpdateExtender {
|
|||
|
||||
func (NoOpUpdateExtender) Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.Repository,
|
||||
types.GithookUpdateInput,
|
||||
|
@ -95,6 +100,7 @@ func NewPostReceiveExtender() PostReceiveExtender {
|
|||
|
||||
func (NoOpPostReceiveExtender) Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.Repository,
|
||||
types.GithookPostReceiveInput,
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// 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 githook
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/git"
|
||||
)
|
||||
|
||||
// RestrictedGIT is a git client that is restricted to a subset of operations of git.Interface
|
||||
// which can be executed on quarantine data that is part of git-hooks (e.g. pre-receive, update, ..)
|
||||
// and don't alter the repo (so only read operations).
|
||||
// NOTE: While it doesn't apply to all git-hooks (e.g. post-receive), we still use the interface across the board
|
||||
// to "soft enforce" no write operations being executed as part of githooks.
|
||||
type RestrictedGIT interface {
|
||||
IsAncestor(ctx context.Context, params git.IsAncestorParams) (git.IsAncestorOutput, error)
|
||||
}
|
|
@ -43,6 +43,7 @@ const (
|
|||
// PostReceive executes the post-receive hook for a git repository.
|
||||
func (c *Controller) PostReceive(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
session *auth.Session,
|
||||
in types.GithookPostReceiveInput,
|
||||
) (hook.Output, error) {
|
||||
|
@ -52,7 +53,7 @@ func (c *Controller) PostReceive(
|
|||
}
|
||||
|
||||
// report ref events (best effort)
|
||||
c.reportReferenceEvents(ctx, repo, in.PrincipalID, in.PostReceiveInput)
|
||||
c.reportReferenceEvents(ctx, rgit, repo, in.PrincipalID, in.PostReceiveInput)
|
||||
|
||||
// create output object and have following messages fill its messages
|
||||
out := hook.Output{}
|
||||
|
@ -60,7 +61,7 @@ func (c *Controller) PostReceive(
|
|||
// handle branch updates related to PRs - best effort
|
||||
c.handlePRMessaging(ctx, repo, in.PostReceiveInput, &out)
|
||||
|
||||
err = c.postReceiveExtender.Extend(ctx, session, repo, in, &out)
|
||||
err = c.postReceiveExtender.Extend(ctx, rgit, session, repo, in, &out)
|
||||
if out.Error != nil {
|
||||
return out, nil
|
||||
}
|
||||
|
@ -76,6 +77,7 @@ func (c *Controller) PostReceive(
|
|||
// TODO: in the future we might want to think about propagating errors so user is aware of events not being triggered.
|
||||
func (c *Controller) reportReferenceEvents(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
repo *types.Repository,
|
||||
principalID int64,
|
||||
in hook.PostReceiveInput,
|
||||
|
@ -83,7 +85,7 @@ func (c *Controller) reportReferenceEvents(
|
|||
for _, refUpdate := range in.RefUpdates {
|
||||
switch {
|
||||
case strings.HasPrefix(refUpdate.Ref, gitReferenceNamePrefixBranch):
|
||||
c.reportBranchEvent(ctx, repo, principalID, refUpdate)
|
||||
c.reportBranchEvent(ctx, rgit, repo, principalID, in.Environment, refUpdate)
|
||||
case strings.HasPrefix(refUpdate.Ref, gitReferenceNamePrefixTag):
|
||||
c.reportTagEvent(ctx, repo, principalID, refUpdate)
|
||||
default:
|
||||
|
@ -94,8 +96,10 @@ func (c *Controller) reportReferenceEvents(
|
|||
|
||||
func (c *Controller) reportBranchEvent(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
repo *types.Repository,
|
||||
principalID int64,
|
||||
env hook.Environment,
|
||||
branchUpdate hook.ReferenceUpdate,
|
||||
) {
|
||||
switch {
|
||||
|
@ -114,8 +118,11 @@ func (c *Controller) reportBranchEvent(
|
|||
SHA: branchUpdate.Old.String(),
|
||||
})
|
||||
default:
|
||||
result, err := c.git.IsAncestor(ctx, git.IsAncestorParams{
|
||||
ReadParams: git.ReadParams{RepoUID: repo.GitUID},
|
||||
result, err := rgit.IsAncestor(ctx, git.IsAncestorParams{
|
||||
ReadParams: git.ReadParams{
|
||||
RepoUID: repo.GitUID,
|
||||
AlternateObjectDirs: env.AlternateObjectDirs,
|
||||
},
|
||||
AncestorCommitSHA: branchUpdate.Old,
|
||||
DescendantCommitSHA: branchUpdate.New,
|
||||
})
|
||||
|
|
|
@ -33,10 +33,9 @@ import (
|
|||
)
|
||||
|
||||
// PreReceive executes the pre-receive hook for a git repository.
|
||||
//
|
||||
//nolint:revive // not yet fully implemented
|
||||
func (c *Controller) PreReceive(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
session *auth.Session,
|
||||
in types.GithookPreReceiveInput,
|
||||
) (hook.Output, error) {
|
||||
|
@ -87,7 +86,7 @@ func (c *Controller) PreReceive(
|
|||
return hook.Output{}, fmt.Errorf("failed to check protection rules: %w", err)
|
||||
}
|
||||
|
||||
err = c.preReceiveExtender.Extend(ctx, session, repo, in, &output)
|
||||
err = c.preReceiveExtender.Extend(ctx, rgit, session, repo, in, &output)
|
||||
if output.Error != nil {
|
||||
return output, nil
|
||||
}
|
||||
|
|
|
@ -25,10 +25,9 @@ import (
|
|||
)
|
||||
|
||||
// Update executes the update hook for a git repository.
|
||||
//
|
||||
//nolint:revive // not yet implemented
|
||||
func (c *Controller) Update(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
session *auth.Session,
|
||||
in types.GithookUpdateInput,
|
||||
) (hook.Output, error) {
|
||||
|
@ -39,7 +38,7 @@ func (c *Controller) Update(
|
|||
|
||||
output := hook.Output{}
|
||||
|
||||
err = c.updateExtender.Extend(ctx, session, repo, in, &output)
|
||||
err = c.updateExtender.Extend(ctx, rgit, session, repo, in, &output)
|
||||
if output.Error != nil {
|
||||
return output, nil
|
||||
}
|
||||
|
|
|
@ -21,11 +21,15 @@ import (
|
|||
controllergithook "github.com/harness/gitness/app/api/controller/githook"
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
// HandlePostReceive returns a handler function that handles post-receive git hooks.
|
||||
func HandlePostReceive(githookCtrl *controllergithook.Controller) http.HandlerFunc {
|
||||
func HandlePostReceive(
|
||||
githookCtrl *controllergithook.Controller,
|
||||
git git.Interface,
|
||||
) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
|
@ -37,7 +41,8 @@ func HandlePostReceive(githookCtrl *controllergithook.Controller) http.HandlerFu
|
|||
return
|
||||
}
|
||||
|
||||
out, err := githookCtrl.PostReceive(ctx, session, in)
|
||||
// gitness doesn't require any custom git connector.
|
||||
out, err := githookCtrl.PostReceive(ctx, git, session, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
|
|
|
@ -21,11 +21,15 @@ import (
|
|||
controllergithook "github.com/harness/gitness/app/api/controller/githook"
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
// HandlePreReceive returns a handler function that handles pre-receive git hooks.
|
||||
func HandlePreReceive(githookCtrl *controllergithook.Controller) http.HandlerFunc {
|
||||
func HandlePreReceive(
|
||||
githookCtrl *controllergithook.Controller,
|
||||
git git.Interface,
|
||||
) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
|
@ -37,7 +41,8 @@ func HandlePreReceive(githookCtrl *controllergithook.Controller) http.HandlerFun
|
|||
return
|
||||
}
|
||||
|
||||
out, err := githookCtrl.PreReceive(ctx, session, in)
|
||||
// gitness doesn't require any custom git connector.
|
||||
out, err := githookCtrl.PreReceive(ctx, git, session, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
|
|
|
@ -18,14 +18,18 @@ import (
|
|||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
githookcontroller "github.com/harness/gitness/app/api/controller/githook"
|
||||
controllergithook "github.com/harness/gitness/app/api/controller/githook"
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
// HandleUpdate returns a handler function that handles update git hooks.
|
||||
func HandleUpdate(githookCtrl *githookcontroller.Controller) http.HandlerFunc {
|
||||
func HandleUpdate(
|
||||
githookCtrl *controllergithook.Controller,
|
||||
git git.Interface,
|
||||
) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
|
@ -37,7 +41,8 @@ func HandleUpdate(githookCtrl *githookcontroller.Controller) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
out, err := githookCtrl.Update(ctx, session, in)
|
||||
// gitness doesn't require any custom git connector.
|
||||
out, err := githookCtrl.Update(ctx, git, session, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/githook"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/git/hook"
|
||||
"github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/types"
|
||||
|
@ -27,9 +28,13 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var _ hook.ClientFactory = (*ControllerClientFactory)(nil)
|
||||
var _ hook.Client = (*ControllerClient)(nil)
|
||||
|
||||
// ControllerClientFactory creates clients that directly call the controller to execute githooks.
|
||||
type ControllerClientFactory struct {
|
||||
githookCtrl *githook.Controller
|
||||
git git.Interface
|
||||
}
|
||||
|
||||
func (f *ControllerClientFactory) NewClient(_ context.Context, envVars map[string]string) (hook.Client, error) {
|
||||
|
@ -48,8 +53,9 @@ func (f *ControllerClientFactory) NewClient(_ context.Context, envVars map[strin
|
|||
}
|
||||
|
||||
return &ControllerClient{
|
||||
baseInput: getInputBaseFromPayload(payload),
|
||||
baseInput: GetInputBaseFromPayload(payload),
|
||||
githookCtrl: f.githookCtrl,
|
||||
git: f.git,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -57,6 +63,7 @@ func (f *ControllerClientFactory) NewClient(_ context.Context, envVars map[strin
|
|||
type ControllerClient struct {
|
||||
baseInput types.GithookInputBase
|
||||
githookCtrl *githook.Controller
|
||||
git githook.RestrictedGIT
|
||||
}
|
||||
|
||||
func (c *ControllerClient) PreReceive(
|
||||
|
@ -67,7 +74,8 @@ func (c *ControllerClient) PreReceive(
|
|||
|
||||
out, err := c.githookCtrl.PreReceive(
|
||||
ctx,
|
||||
nil, // TODO: update once githooks are auth protected
|
||||
c.git, // gitness doesn't require any custom git connector.
|
||||
nil, // TODO: update once githooks are auth protected
|
||||
types.GithookPreReceiveInput{
|
||||
GithookInputBase: c.baseInput,
|
||||
PreReceiveInput: in,
|
||||
|
@ -88,7 +96,8 @@ func (c *ControllerClient) Update(
|
|||
|
||||
out, err := c.githookCtrl.Update(
|
||||
ctx,
|
||||
nil, // TODO: update once githooks are auth protected
|
||||
c.git, // gitness doesn't require any custom git connector.
|
||||
nil, // TODO: update once githooks are auth protected
|
||||
types.GithookUpdateInput{
|
||||
GithookInputBase: c.baseInput,
|
||||
UpdateInput: in,
|
||||
|
@ -109,7 +118,8 @@ func (c *ControllerClient) PostReceive(
|
|||
|
||||
out, err := c.githookCtrl.PostReceive(
|
||||
ctx,
|
||||
nil, // TODO: update once githooks are auth protected
|
||||
c.git, // gitness doesn't require any custom git connector.
|
||||
nil, // TODO: update once githooks are auth protected
|
||||
types.GithookPostReceiveInput{
|
||||
GithookInputBase: c.baseInput,
|
||||
PostReceiveInput: in,
|
||||
|
|
|
@ -77,7 +77,7 @@ func NewRestClient(
|
|||
httpClient: http.DefaultClient,
|
||||
baseURL: strings.TrimRight(payload.BaseURL, "/"),
|
||||
requestID: payload.RequestID,
|
||||
baseInput: getInputBaseFromPayload(payload),
|
||||
baseInput: GetInputBaseFromPayload(payload),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ func (p Payload) Validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getInputBaseFromPayload(p Payload) types.GithookInputBase {
|
||||
func GetInputBaseFromPayload(p Payload) types.GithookInputBase {
|
||||
return types.GithookInputBase{
|
||||
RepoID: p.RepoID,
|
||||
PrincipalID: p.PrincipalID,
|
||||
|
|
|
@ -61,7 +61,6 @@ func ProvideController(
|
|||
principalStore,
|
||||
repoStore,
|
||||
gitReporter,
|
||||
git,
|
||||
pullreqStore,
|
||||
urlProvider,
|
||||
protectionManager,
|
||||
|
@ -74,6 +73,7 @@ func ProvideController(
|
|||
// TODO: improve wiring if possible
|
||||
if fct, ok := githookFactory.(*ControllerClientFactory); ok {
|
||||
fct.githookCtrl = ctrl
|
||||
fct.git = git
|
||||
}
|
||||
|
||||
return ctrl
|
||||
|
|
|
@ -70,6 +70,7 @@ import (
|
|||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/app/auth/authn"
|
||||
"github.com/harness/gitness/app/githook"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
|
@ -108,6 +109,7 @@ func NewAPIHandler(
|
|||
pullreqCtrl *pullreq.Controller,
|
||||
webhookCtrl *webhook.Controller,
|
||||
githookCtrl *controllergithook.Controller,
|
||||
git git.Interface,
|
||||
saCtrl *serviceaccount.Controller,
|
||||
userCtrl *user.Controller,
|
||||
principalCtrl principal.Controller,
|
||||
|
@ -139,7 +141,7 @@ func NewAPIHandler(
|
|||
r.Route("/v1", func(r chi.Router) {
|
||||
setupRoutesV1(r, appCtx, config, repoCtrl, executionCtrl, triggerCtrl, logCtrl, pipelineCtrl,
|
||||
connectorCtrl, templateCtrl, pluginCtrl, secretCtrl, spaceCtrl, pullreqCtrl,
|
||||
webhookCtrl, githookCtrl, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl, uploadCtrl,
|
||||
webhookCtrl, githookCtrl, git, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl, uploadCtrl,
|
||||
searchCtrl)
|
||||
})
|
||||
|
||||
|
@ -177,6 +179,7 @@ func setupRoutesV1(r chi.Router,
|
|||
pullreqCtrl *pullreq.Controller,
|
||||
webhookCtrl *webhook.Controller,
|
||||
githookCtrl *controllergithook.Controller,
|
||||
git git.Interface,
|
||||
saCtrl *serviceaccount.Controller,
|
||||
userCtrl *user.Controller,
|
||||
principalCtrl principal.Controller,
|
||||
|
@ -194,7 +197,7 @@ func setupRoutesV1(r chi.Router,
|
|||
setupUser(r, userCtrl)
|
||||
setupServiceAccounts(r, saCtrl)
|
||||
setupPrincipals(r, principalCtrl)
|
||||
setupInternal(r, githookCtrl)
|
||||
setupInternal(r, githookCtrl, git)
|
||||
setupAdmin(r, userCtrl)
|
||||
setupAccount(r, userCtrl, sysCtrl, config)
|
||||
setupSystem(r, config, sysCtrl)
|
||||
|
@ -470,17 +473,17 @@ func setupTriggers(
|
|||
})
|
||||
}
|
||||
|
||||
func setupInternal(r chi.Router, githookCtrl *controllergithook.Controller) {
|
||||
func setupInternal(r chi.Router, githookCtrl *controllergithook.Controller, git git.Interface) {
|
||||
r.Route("/internal", func(r chi.Router) {
|
||||
SetupGitHooks(r, githookCtrl)
|
||||
SetupGitHooks(r, githookCtrl, git)
|
||||
})
|
||||
}
|
||||
|
||||
func SetupGitHooks(r chi.Router, githookCtrl *controllergithook.Controller) {
|
||||
func SetupGitHooks(r chi.Router, githookCtrl *controllergithook.Controller, git git.Interface) {
|
||||
r.Route("/git-hooks", func(r chi.Router) {
|
||||
r.Post("/"+githook.HTTPRequestPathPreReceive, handlergithook.HandlePreReceive(githookCtrl))
|
||||
r.Post("/"+githook.HTTPRequestPathUpdate, handlergithook.HandleUpdate(githookCtrl))
|
||||
r.Post("/"+githook.HTTPRequestPathPostReceive, handlergithook.HandlePostReceive(githookCtrl))
|
||||
r.Post("/"+githook.HTTPRequestPathPreReceive, handlergithook.HandlePreReceive(githookCtrl, git))
|
||||
r.Post("/"+githook.HTTPRequestPathUpdate, handlergithook.HandleUpdate(githookCtrl, git))
|
||||
r.Post("/"+githook.HTTPRequestPathPostReceive, handlergithook.HandlePostReceive(githookCtrl, git))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ import (
|
|||
"github.com/harness/gitness/app/api/openapi"
|
||||
"github.com/harness/gitness/app/auth/authn"
|
||||
"github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/google/wire"
|
||||
|
@ -103,6 +104,7 @@ func ProvideAPIHandler(
|
|||
pullreqCtrl *pullreq.Controller,
|
||||
webhookCtrl *webhook.Controller,
|
||||
githookCtrl *githook.Controller,
|
||||
git git.Interface,
|
||||
saCtrl *serviceaccount.Controller,
|
||||
userCtrl *user.Controller,
|
||||
principalCtrl principal.Controller,
|
||||
|
@ -114,7 +116,7 @@ func ProvideAPIHandler(
|
|||
return NewAPIHandler(appCtx, config,
|
||||
authenticator, repoCtrl, executionCtrl, logCtrl, spaceCtrl, pipelineCtrl,
|
||||
secretCtrl, triggerCtrl, connectorCtrl, templateCtrl, pluginCtrl, pullreqCtrl, webhookCtrl,
|
||||
githookCtrl, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl, blobCtrl, searchCtrl)
|
||||
githookCtrl, git, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl, blobCtrl, searchCtrl)
|
||||
}
|
||||
|
||||
func ProvideWebHandler(config *types.Config, openapi openapi.Service) WebHandler {
|
||||
|
|
|
@ -291,7 +291,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
|||
uploadController := upload.ProvideController(authorizer, repoStore, blobStore)
|
||||
searcher := keywordsearch.ProvideSearcher(localIndexSearcher)
|
||||
keywordsearchController := keywordsearch2.ProvideController(authorizer, searcher, repoController, spaceController)
|
||||
apiHandler := router.ProvideAPIHandler(ctx, config, authenticator, repoController, executionController, logsController, spaceController, pipelineController, secretController, triggerController, connectorController, templateController, pluginController, pullreqController, webhookController, githookController, serviceaccountController, controller, principalController, checkController, systemController, uploadController, keywordsearchController)
|
||||
apiHandler := router.ProvideAPIHandler(ctx, config, authenticator, repoController, executionController, logsController, spaceController, pipelineController, secretController, triggerController, connectorController, templateController, pluginController, pullreqController, webhookController, githookController, gitInterface, serviceaccountController, controller, principalController, checkController, systemController, uploadController, keywordsearchController)
|
||||
gitHandler := router.ProvideGitHandler(provider, authenticator, repoController)
|
||||
openapiService := openapi.ProvideOpenAPIService()
|
||||
webHandler := router.ProvideWebHandler(config, openapiService)
|
||||
|
|
|
@ -183,15 +183,12 @@ func (g *Git) RawDiff(
|
|||
cmd := command.New("diff",
|
||||
command.WithFlag("-M"),
|
||||
command.WithFlag("--full-index"),
|
||||
command.WithAlternateObjectDirs(alternates...),
|
||||
)
|
||||
if mergeBase {
|
||||
cmd.Add(command.WithFlag("--merge-base"))
|
||||
}
|
||||
|
||||
if len(alternates) > 0 {
|
||||
cmd.Add(command.WithAlternateObjectDirs(alternates...))
|
||||
}
|
||||
|
||||
perFileDiffRequired := false
|
||||
paths := make([]string, 0, len(files))
|
||||
if len(files) > 0 {
|
||||
|
|
|
@ -79,7 +79,9 @@ func (g *Git) GetMergeBase(
|
|||
func (g *Git) IsAncestor(
|
||||
ctx context.Context,
|
||||
repoPath string,
|
||||
ancestorCommitSHA, descendantCommitSHA sha.SHA,
|
||||
alternates []string,
|
||||
ancestorCommitSHA,
|
||||
descendantCommitSHA sha.SHA,
|
||||
) (bool, error) {
|
||||
if repoPath == "" {
|
||||
return false, ErrRepositoryPathEmpty
|
||||
|
@ -88,6 +90,7 @@ func (g *Git) IsAncestor(
|
|||
cmd := command.New("merge-base",
|
||||
command.WithFlag("--is-ancestor"),
|
||||
command.WithArg(ancestorCommitSHA.String(), descendantCommitSHA.String()),
|
||||
command.WithAlternateObjectDirs(alternates...),
|
||||
)
|
||||
|
||||
err := cmd.Run(ctx, command.WithDir(repoPath))
|
||||
|
|
|
@ -342,6 +342,9 @@ func (g *Git) updateRefWithHooks(
|
|||
New: newValue,
|
||||
},
|
||||
},
|
||||
Environment: hook.Environment{
|
||||
// TODO: Update once we properly copy quarantine objects only after pre-receive.
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("pre-receive call failed with: %w", err)
|
||||
|
@ -378,6 +381,7 @@ func (g *Git) updateRefWithHooks(
|
|||
New: newValue,
|
||||
},
|
||||
},
|
||||
Environment: hook.Environment{},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("post-receive call failed with: %w", err)
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/git/command"
|
||||
"github.com/harness/gitness/git/sha"
|
||||
)
|
||||
|
||||
|
@ -49,8 +50,16 @@ func (c *CLICore) PreReceive(ctx context.Context) error {
|
|||
return fmt.Errorf("failed to read updated references from std in: %w", err)
|
||||
}
|
||||
|
||||
alternateObjDirs, err := getAlternateObjectDirsFromEnv()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read alternate object dirs from env: %w", err)
|
||||
}
|
||||
|
||||
in := PreReceiveInput{
|
||||
RefUpdates: refUpdates,
|
||||
Environment: Environment{
|
||||
AlternateObjectDirs: alternateObjDirs,
|
||||
},
|
||||
}
|
||||
|
||||
out, err := c.client.PreReceive(ctx, in)
|
||||
|
@ -60,12 +69,20 @@ func (c *CLICore) PreReceive(ctx context.Context) error {
|
|||
|
||||
// Update executes the update git hook.
|
||||
func (c *CLICore) Update(ctx context.Context, ref string, oldSHA string, newSHA string) error {
|
||||
alternateObjDirs, err := getAlternateObjectDirsFromEnv()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read alternate object dirs from env: %w", err)
|
||||
}
|
||||
|
||||
in := UpdateInput{
|
||||
RefUpdate: ReferenceUpdate{
|
||||
Ref: ref,
|
||||
Old: sha.Must(oldSHA),
|
||||
New: sha.Must(newSHA),
|
||||
},
|
||||
Environment: Environment{
|
||||
AlternateObjectDirs: alternateObjDirs,
|
||||
},
|
||||
}
|
||||
|
||||
out, err := c.client.Update(ctx, in)
|
||||
|
@ -82,6 +99,9 @@ func (c *CLICore) PostReceive(ctx context.Context) error {
|
|||
|
||||
in := PostReceiveInput{
|
||||
RefUpdates: refUpdates,
|
||||
Environment: Environment{
|
||||
AlternateObjectDirs: nil, // all objects are in main objects folder at this point
|
||||
},
|
||||
}
|
||||
|
||||
out, err := c.client.PostReceive(ctx, in)
|
||||
|
@ -149,3 +169,16 @@ func getUpdatedReferencesFromStdIn() ([]ReferenceUpdate, error) {
|
|||
|
||||
return updatedRefs, nil
|
||||
}
|
||||
|
||||
// getAlternateObjectDirsFromEnv returns the alternate object directories that have to be used
|
||||
// to be able to preemptively access the quarantined objects created by a write operation.
|
||||
// NOTE: The temp dir of a write operation is it's main object dir,
|
||||
// which is the one that read operations have to use as alternate object dir.
|
||||
func getAlternateObjectDirsFromEnv() ([]string, error) {
|
||||
tmpDir, err := getRequiredEnvironmentVariable(command.GitObjectDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []string{tmpDir}, nil
|
||||
}
|
|
@ -18,7 +18,6 @@ import (
|
|||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
@ -28,11 +27,6 @@ const (
|
|||
envNamePayload = "GIT_HOOK_PAYLOAD"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrEnvVarNotFound is an error that is returned in case the environment variable isn't found.
|
||||
ErrEnvVarNotFound = errors.New("environment variable not found")
|
||||
)
|
||||
|
||||
// GenerateEnvironmentVariables generates the environment variables that should be used when calling git
|
||||
// to ensure the payload will be available to the githook cli.
|
||||
func GenerateEnvironmentVariables(payload any) (map[string]string, error) {
|
||||
|
@ -60,7 +54,7 @@ func LoadPayloadFromMap[T any](envVars map[string]string) (T, error) {
|
|||
// retrieve payload from environment variables
|
||||
payloadBase64, ok := envVars[envNamePayload]
|
||||
if !ok {
|
||||
return payload, ErrEnvVarNotFound
|
||||
return payload, fmt.Errorf("environment variable %q not found", envNamePayload)
|
||||
}
|
||||
|
||||
return decodePayload[T](payloadBase64)
|
||||
|
@ -71,7 +65,7 @@ func LoadPayloadFromEnvironment[T any]() (T, error) {
|
|||
var payload T
|
||||
|
||||
// retrieve payload from environment variables
|
||||
payloadBase64, err := getEnvironmentVariable(envNamePayload)
|
||||
payloadBase64, err := getRequiredEnvironmentVariable(envNamePayload)
|
||||
if err != nil {
|
||||
return payload, fmt.Errorf("failed to load payload from environment variables: %w", err)
|
||||
}
|
||||
|
@ -97,14 +91,14 @@ func decodePayload[T any](encodedPayload string) (T, error) {
|
|||
return payload, nil
|
||||
}
|
||||
|
||||
func getEnvironmentVariable(name string) (string, error) {
|
||||
func getRequiredEnvironmentVariable(name string) (string, error) {
|
||||
val, ok := os.LookupEnv(name)
|
||||
if !ok {
|
||||
return "", ErrEnvVarNotFound
|
||||
return "", fmt.Errorf("environment variable %q not found", name)
|
||||
}
|
||||
|
||||
if val == "" {
|
||||
return "", fmt.Errorf("'%s' found in env but it's empty", name)
|
||||
return "", fmt.Errorf("environment variable %q found but it's empty", name)
|
||||
}
|
||||
|
||||
return val, nil
|
||||
|
|
|
@ -35,20 +35,35 @@ type ReferenceUpdate struct {
|
|||
New sha.SHA `json:"new"`
|
||||
}
|
||||
|
||||
// PostReceiveInput represents the input of the post-receive git hook.
|
||||
type PostReceiveInput struct {
|
||||
// RefUpdates contains all references that got updated as part of the git operation.
|
||||
RefUpdates []ReferenceUpdate `json:"ref_updates"`
|
||||
// Environment contains the information required to access a specific git environment.
|
||||
type Environment struct {
|
||||
// AlternateObjectDirs contains any alternate object dirs required to access all objects of an operation.
|
||||
AlternateObjectDirs []string `json:"alternate_object_dirs,omitempty"`
|
||||
}
|
||||
|
||||
// PreReceiveInput represents the input of the pre-receive git hook.
|
||||
type PreReceiveInput struct {
|
||||
// Environment contains the information required to access the git environment.
|
||||
Environment Environment `json:"environment"`
|
||||
|
||||
// RefUpdates contains all references that are being updated as part of the git operation.
|
||||
RefUpdates []ReferenceUpdate `json:"ref_updates"`
|
||||
}
|
||||
|
||||
// UpdateInput represents the input of the update git hook.
|
||||
type UpdateInput struct {
|
||||
// Environment contains the information required to access the git environment.
|
||||
Environment Environment `json:"environment"`
|
||||
|
||||
// RefUpdate contains information about the reference that is being updated.
|
||||
RefUpdate ReferenceUpdate `json:"ref_update"`
|
||||
}
|
||||
|
||||
// PostReceiveInput represents the input of the post-receive git hook.
|
||||
type PostReceiveInput struct {
|
||||
// Environment contains the information required to access the git environment.
|
||||
Environment Environment `json:"environment"`
|
||||
|
||||
// RefUpdates contains all references that got updated as part of the git operation.
|
||||
RefUpdates []ReferenceUpdate `json:"ref_updates"`
|
||||
}
|
||||
|
|
|
@ -391,7 +391,13 @@ func (s *Service) IsAncestor(
|
|||
) (IsAncestorOutput, error) {
|
||||
repoPath := getFullPathForRepo(s.reposRoot, params.RepoUID)
|
||||
|
||||
result, err := s.git.IsAncestor(ctx, repoPath, params.AncestorCommitSHA, params.DescendantCommitSHA)
|
||||
result, err := s.git.IsAncestor(
|
||||
ctx,
|
||||
repoPath,
|
||||
params.AlternateObjectDirs,
|
||||
params.AncestorCommitSHA,
|
||||
params.DescendantCommitSHA,
|
||||
)
|
||||
if err != nil {
|
||||
return IsAncestorOutput{}, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue