A read-only clone of the dehub project, for until dehub.dev can be brought back online.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
dehub/cmd/dehub/cmd_hook.go

103 lines
2.8 KiB

package main
import (
"bufio"
"context"
"dehub/cmd/dehub/dcmd"
"errors"
"fmt"
"io"
"os"
"strings"
"gopkg.in/src-d/go-git.v4/plumbing"
)
func cmdHook(ctx context.Context, cmd *dcmd.Cmd) {
flag := cmd.FlagSet()
preRcv := flag.Bool("pre-receive", false, "Use dehub as a server-side pre-receive hook")
cmd.Run(func() (context.Context, error) {
if !*preRcv {
return nil, errors.New("must set the hook type")
}
repo := ctxRepo(ctx)
br := bufio.NewReader(os.Stdin)
for {
line, err := br.ReadString('\n')
if errors.Is(err, io.EOF) {
return nil, nil
} else if err != nil {
return nil, fmt.Errorf("error reading next line from stdin: %w", err)
}
fmt.Printf("Processing line %q\n", strings.TrimSpace(line))
lineParts := strings.Fields(line)
if len(lineParts) < 3 {
return nil, fmt.Errorf("malformed pre-receive hook stdin line %q", line)
}
branchName := plumbing.ReferenceName(lineParts[2])
// the zeroRevision gets sent on the very first push
const zeroRevision plumbing.Revision = "0000000000000000000000000000000000000000"
fromRev := plumbing.Revision(lineParts[0])
var fromHash *plumbing.Hash
if fromRev != zeroRevision {
fromHash, err = repo.GitRepo.ResolveRevision(fromRev)
if err != nil {
return nil, fmt.Errorf("unable to resolve revision %q: %w", fromRev, err)
}
}
toRev := plumbing.Revision(lineParts[1])
toHash, err := repo.GitRepo.ResolveRevision(toRev)
if err != nil {
return nil, fmt.Errorf("unable to resolve revision %q: %w", toRev, err)
}
toCommit, err := repo.GitRepo.CommitObject(*toHash)
if err != nil {
return nil, fmt.Errorf("unable to find commit %q: %w", *toHash, err)
}
var hashesToCheck []plumbing.Hash
var found bool
for currCommit := toCommit; ; {
hashesToCheck = append(hashesToCheck, currCommit.Hash)
if currCommit.NumParents() == 0 {
break
} else if currCommit.NumParents() > 1 {
return nil, fmt.Errorf("commit %q has more than one parent: %+v",
currCommit.Hash, currCommit.ParentHashes)
}
parentCommit, err := currCommit.Parent(0)
if err != nil {
return nil, fmt.Errorf("unable to get parent of commit %q: %w", currCommit.Hash, err)
} else if fromHash != nil && parentCommit.Hash == *fromHash {
found = true
break
}
currCommit = parentCommit
}
if !found && fromHash != nil {
return nil, fmt.Errorf("unable to find commit %q as an ancestor of %q", *fromHash, *toHash)
}
for i := len(hashesToCheck) - 1; i >= 0; i-- {
hash := hashesToCheck[i]
fmt.Printf("Verifying change commit %q\n", hash)
if err := repo.VerifyCommit(branchName, hash); err != nil {
return nil, fmt.Errorf("could not verify change commit %q: %w", hash, err)
}
}
fmt.Println("All pushed commits have been verified, well done.")
return nil, nil
}
})
}