Evgenii Stratonikov
2f1de6fc41
Set it to target branch and check only the commits we are interested in. If the commit is already in the branch, we just get an old behaviour. Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
111 lines
2.4 KiB
Go
111 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"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"
|
|
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 errors.New("stop")
|
|
}
|
|
|
|
// 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]
|
|
}
|