dco-go/main.go

112 lines
2.4 KiB
Go
Raw Normal View History

package main
import (
"fmt"
"log"
"os"
"regexp"
"strings"
git "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/plumbing/storer"
gha "github.com/sethvargo/go-githubactions"
)
func main() {
// Prepare regexp templates.
rxHeader := regexp.MustCompile(`^(\[\#[0-9Xx]+\]\s|Release)`)
rxSignOff := regexp.MustCompile(`^Signed-off-by:`)
// Open current git dir.
r, err := git.PlainOpen("./")
if err != nil {
log.Fatalf("Failed to open repository: %v", err)
}
// Retrieve the commit history.
head, err := r.Head()
if err != nil {
log.Fatalf("Failed to retrieve HEAD reference: %v", err)
}
// Create iterator over commits.
commits, err := r.Log(&git.LogOptions{From: head.Hash()})
if err != nil {
log.Fatalf("Failed to retrieve commit history: %v", err)
}
// Limit number of iterations.
var lca *object.Commit
if from := gha.GetInput("from"); from != "" {
lca = getMergeBase(r, head, from)
}
// Processing result.
var fail bool
_ = commits.ForEach(func(c *object.Commit) error {
// Stop iterator when limit is reached.
if lca != nil && c.Hash == lca.Hash {
return storer.ErrStop
}
// Parse commit data.
id := c.ID().String()[:7]
lines := strings.Split(strings.Trim(c.Message, "\n"), "\n")
// Do not process empty commit.
if len(lines) == 0 {
fail = true
fmt.Printf("Error: empty commit [%s]\n", id)
return nil
}
// Check commit header.
header := lines[0]
if !rxHeader.MatchString(header) {
fail = true
fmt.Printf("Error: invalid header %s [%s]\n", header, id)
return nil
}
// Check commit sign-off.
if !rxSignOff.MatchString(lines[len(lines)-1]) {
fail = true
fmt.Printf("Error: missing sign-off %s [%s]\n", header, id)
}
return nil
})
// Return non-zero code if DCO check failed.
if fail {
os.Exit(1)
}
}
func getMergeBase(r *git.Repository, head *plumbing.Reference, from string) *object.Commit {
h, err := r.ResolveRevision(plumbing.Revision(from))
if err != nil {
log.Fatalf("Failed to resolve a reference: %v", err)
}
to, err := r.CommitObject(*h)
if err != nil {
log.Fatalf("Failed to get commit object: %v", err)
}
other, err := r.CommitObject(head.Hash())
if err != nil {
log.Fatalf("Failed to get HEAD commit object: %v", err)
}
cc, err := to.MergeBase(other)
if err != nil {
log.Fatalf("Failed to determine merge-base: %v", err)
}
return cc[0]
}