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. 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. ref, 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: ref.Hash()}) 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) } }