2023-06-30 15:54:50 +00:00
|
|
|
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/object"
|
|
|
|
gha "github.com/sethvargo/go-githubactions"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
// Prepare regexp templates.
|
2023-06-30 16:07:45 +00:00
|
|
|
rxHeader := regexp.MustCompile(`^(\[\#[0-9Xx]+\]\s|Release)`)
|
2023-06-30 15:54:50 +00:00
|
|
|
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.
|
2023-07-13 08:51:00 +00:00
|
|
|
head, err := r.Head()
|
2023-06-30 15:54:50 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Failed to retrieve HEAD reference: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create iterator over commits.
|
2023-07-13 08:51:00 +00:00
|
|
|
commits, err := r.Log(&git.LogOptions{From: head.Hash()})
|
2023-06-30 15:54:50 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Failed to retrieve commit history: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Limit number of iterations.
|
|
|
|
from := gha.GetInput("from")
|
|
|
|
|
|
|
|
// Processing result.
|
|
|
|
var fail bool
|
|
|
|
|
|
|
|
_ = commits.ForEach(func(c *object.Commit) error {
|
|
|
|
// Stop iterator when limit is reached.
|
|
|
|
if len(from) != 0 && strings.HasPrefix(c.ID().String(), from) {
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|