mirror of
https://github.com/harness/drone.git
synced 2025-05-20 19:09:59 +08:00
detect force push (#856)
This commit is contained in:
parent
90d8ac7193
commit
1899e70e56
@ -25,6 +25,7 @@ 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"
|
||||
)
|
||||
@ -57,6 +58,7 @@ type Controller struct {
|
||||
principalStore store.PrincipalStore
|
||||
repoStore store.RepoStore
|
||||
gitReporter *eventsgit.Reporter
|
||||
git git.Interface
|
||||
pullreqStore store.PullReqStore
|
||||
urlProvider url.Provider
|
||||
protectionManager *protection.Manager
|
||||
@ -67,6 +69,7 @@ func NewController(
|
||||
principalStore store.PrincipalStore,
|
||||
repoStore store.RepoStore,
|
||||
gitReporter *eventsgit.Reporter,
|
||||
git git.Interface,
|
||||
pullreqStore store.PullReqStore,
|
||||
urlProvider url.Provider,
|
||||
protectionManager *protection.Manager,
|
||||
@ -76,6 +79,7 @@ func NewController(
|
||||
principalStore: principalStore,
|
||||
repoStore: repoStore,
|
||||
gitReporter: gitReporter,
|
||||
git: git,
|
||||
pullreqStore: pullreqStore,
|
||||
urlProvider: urlProvider,
|
||||
protectionManager: protectionManager,
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
events "github.com/harness/gitness/app/events/git"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/githook"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
@ -53,7 +54,7 @@ func (c *Controller) PostReceive(
|
||||
}
|
||||
|
||||
// report ref events (best effort)
|
||||
c.reportReferenceEvents(ctx, repoID, principalID, in)
|
||||
c.reportReferenceEvents(ctx, repo, principalID, in)
|
||||
|
||||
// create output object and have following messages fill its messages
|
||||
out := &githook.Output{}
|
||||
@ -69,16 +70,16 @@ 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,
|
||||
repoID int64,
|
||||
repo *types.Repository,
|
||||
principalID int64,
|
||||
in githook.PostReceiveInput,
|
||||
) {
|
||||
for _, refUpdate := range in.RefUpdates {
|
||||
switch {
|
||||
case strings.HasPrefix(refUpdate.Ref, gitReferenceNamePrefixBranch):
|
||||
c.reportBranchEvent(ctx, repoID, principalID, refUpdate)
|
||||
c.reportBranchEvent(ctx, repo, principalID, refUpdate)
|
||||
case strings.HasPrefix(refUpdate.Ref, gitReferenceNamePrefixTag):
|
||||
c.reportTagEvent(ctx, repoID, principalID, refUpdate)
|
||||
c.reportTagEvent(ctx, repo, principalID, refUpdate)
|
||||
default:
|
||||
// Ignore any other references in post-receive
|
||||
}
|
||||
@ -87,61 +88,75 @@ func (c *Controller) reportReferenceEvents(
|
||||
|
||||
func (c *Controller) reportBranchEvent(
|
||||
ctx context.Context,
|
||||
repoID int64,
|
||||
repo *types.Repository,
|
||||
principalID int64,
|
||||
branchUpdate githook.ReferenceUpdate,
|
||||
) {
|
||||
switch {
|
||||
case branchUpdate.Old == types.NilSHA:
|
||||
c.gitReporter.BranchCreated(ctx, &events.BranchCreatedPayload{
|
||||
RepoID: repoID,
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: branchUpdate.Ref,
|
||||
SHA: branchUpdate.New,
|
||||
})
|
||||
case branchUpdate.New == types.NilSHA:
|
||||
c.gitReporter.BranchDeleted(ctx, &events.BranchDeletedPayload{
|
||||
RepoID: repoID,
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: branchUpdate.Ref,
|
||||
SHA: branchUpdate.Old,
|
||||
})
|
||||
default:
|
||||
result, err := c.git.IsAncestor(ctx, git.IsAncestorParams{
|
||||
ReadParams: git.ReadParams{RepoUID: repo.GitUID},
|
||||
AncestorCommitSHA: branchUpdate.Old,
|
||||
DescendantCommitSHA: branchUpdate.New,
|
||||
})
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Err(err).
|
||||
Str("ref", branchUpdate.Ref).
|
||||
Msg("failed to check ancestor")
|
||||
}
|
||||
// In case of an error consider this a forced update. In post-update the branch has already been updated,
|
||||
// so there's less harm in declaring the update as forced. A force update event might trigger some additional
|
||||
// operations that aren't required for ordinary updates (force pushes alter the commit history of a branch).
|
||||
forced := err != nil || !result.Ancestor
|
||||
c.gitReporter.BranchUpdated(ctx, &events.BranchUpdatedPayload{
|
||||
RepoID: repoID,
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: branchUpdate.Ref,
|
||||
OldSHA: branchUpdate.Old,
|
||||
NewSHA: branchUpdate.New,
|
||||
Forced: false, // TODO: data not available yet
|
||||
Forced: forced,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) reportTagEvent(
|
||||
ctx context.Context,
|
||||
repoID int64,
|
||||
repo *types.Repository,
|
||||
principalID int64,
|
||||
tagUpdate githook.ReferenceUpdate,
|
||||
) {
|
||||
switch {
|
||||
case tagUpdate.Old == types.NilSHA:
|
||||
c.gitReporter.TagCreated(ctx, &events.TagCreatedPayload{
|
||||
RepoID: repoID,
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: tagUpdate.Ref,
|
||||
SHA: tagUpdate.New,
|
||||
})
|
||||
case tagUpdate.New == types.NilSHA:
|
||||
c.gitReporter.TagDeleted(ctx, &events.TagDeletedPayload{
|
||||
RepoID: repoID,
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: tagUpdate.Ref,
|
||||
SHA: tagUpdate.Old,
|
||||
})
|
||||
default:
|
||||
c.gitReporter.TagUpdated(ctx, &events.TagUpdatedPayload{
|
||||
RepoID: repoID,
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: tagUpdate.Ref,
|
||||
OldSHA: tagUpdate.Old,
|
||||
|
@ -20,6 +20,7 @@ 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/google/wire"
|
||||
)
|
||||
@ -34,6 +35,7 @@ func ProvideController(
|
||||
principalStore store.PrincipalStore,
|
||||
repoStore store.RepoStore,
|
||||
gitReporter *eventsgit.Reporter,
|
||||
git git.Interface,
|
||||
pullreqStore store.PullReqStore,
|
||||
urlProvider url.Provider,
|
||||
protectionManager *protection.Manager,
|
||||
@ -43,6 +45,7 @@ func ProvideController(
|
||||
principalStore,
|
||||
repoStore,
|
||||
gitReporter,
|
||||
git,
|
||||
pullreqStore,
|
||||
urlProvider,
|
||||
protectionManager)
|
||||
|
@ -245,7 +245,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
githookController := githook.ProvideController(authorizer, principalStore, repoStore, reporter2, pullReqStore, provider, protectionManager)
|
||||
githookController := githook.ProvideController(authorizer, principalStore, repoStore, reporter2, gitInterface, pullReqStore, provider, protectionManager)
|
||||
serviceaccountController := serviceaccount.NewController(principalUID, authorizer, principalStore, spaceStore, repoStore, tokenStore)
|
||||
principalController := principal.ProvideController(principalStore)
|
||||
checkController := check2.ProvideController(transactor, authorizer, repoStore, checkStore, gitInterface)
|
||||
|
@ -74,6 +74,7 @@ type Adapter interface {
|
||||
Merge(ctx context.Context, pr *types.PullRequest, mergeMethod enum.MergeMethod, baseBranch, trackingBranch string,
|
||||
tmpBasePath string, mergeMsg string, identity *types.Identity, env ...string) (types.MergeResult, error)
|
||||
GetMergeBase(ctx context.Context, repoPath, remote, base, head string) (string, string, error)
|
||||
IsAncestor(ctx context.Context, repoPath, ancestorCommitSHA, descendantCommitSHA string) (bool, error)
|
||||
Blame(ctx context.Context, repoPath, rev, file string, lineFrom, lineTo int) types.BlameReader
|
||||
Sync(ctx context.Context, repoPath string, source string, refSpecs []string) error
|
||||
|
||||
|
@ -585,6 +585,28 @@ func (a Adapter) GetMergeBase(
|
||||
return strings.TrimSpace(stdout), base, nil
|
||||
}
|
||||
|
||||
// IsAncestor returns if the provided commit SHA is ancestor of the other commit SHA.
|
||||
func (a Adapter) IsAncestor(
|
||||
ctx context.Context,
|
||||
repoPath string,
|
||||
ancestorCommitSHA, descendantCommitSHA string,
|
||||
) (bool, error) {
|
||||
if repoPath == "" {
|
||||
return false, ErrRepositoryPathEmpty
|
||||
}
|
||||
|
||||
_, stderr, runErr := git.NewCommand(ctx, "merge-base", "--is-ancestor", ancestorCommitSHA, descendantCommitSHA).
|
||||
RunStdString(&git.RunOpts{Dir: repoPath})
|
||||
if runErr != nil {
|
||||
if runErr.IsExitCode(1) && stderr == "" {
|
||||
return false, nil
|
||||
}
|
||||
return false, processGiteaErrorf(runErr, "failed to check commit ancestry: %v", stderr)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// giteaRunStdError is an implementation of the RunStdError interface in the gitea codebase.
|
||||
// It allows us to process gitea errors even when using cmd.Run() instead of cmd.RunStdString() or run.StdBytes().
|
||||
type giteaRunStdError struct {
|
||||
|
@ -53,6 +53,7 @@ type Interface interface {
|
||||
GetCommitDivergences(ctx context.Context, params *GetCommitDivergencesParams) (*GetCommitDivergencesOutput, error)
|
||||
CommitFiles(ctx context.Context, params *CommitFilesParams) (CommitFilesResponse, error)
|
||||
MergeBase(ctx context.Context, params MergeBaseParams) (MergeBaseOutput, error)
|
||||
IsAncestor(ctx context.Context, params IsAncestorParams) (IsAncestorOutput, error)
|
||||
|
||||
/*
|
||||
* Git Cli Service
|
||||
|
26
git/merge.go
26
git/merge.go
@ -411,3 +411,29 @@ func (s *Service) MergeBase(
|
||||
MergeBaseSHA: result,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type IsAncestorParams struct {
|
||||
ReadParams
|
||||
AncestorCommitSHA string
|
||||
DescendantCommitSHA string
|
||||
}
|
||||
|
||||
type IsAncestorOutput struct {
|
||||
Ancestor bool
|
||||
}
|
||||
|
||||
func (s *Service) IsAncestor(
|
||||
ctx context.Context,
|
||||
params IsAncestorParams,
|
||||
) (IsAncestorOutput, error) {
|
||||
repoPath := getFullPathForRepo(s.reposRoot, params.RepoUID)
|
||||
|
||||
result, err := s.adapter.IsAncestor(ctx, repoPath, params.AncestorCommitSHA, params.DescendantCommitSHA)
|
||||
if err != nil {
|
||||
return IsAncestorOutput{}, err
|
||||
}
|
||||
|
||||
return IsAncestorOutput{
|
||||
Ancestor: result,
|
||||
}, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user