package main import ( "errors" "fmt" "io" "log" "os" "regexp" "strings" ) var ( errCommitMsgSyntax = errors.New("commit msg syntax is wrong") errCommitMsgInvalideType = errors.New("commit msg type is invalide") ) var allowedTypes []string func init() { allowedTypes = append(allowedTypes, "fix", "feat", "build", "chore", "ci", "docs", "style", "refactor", "perf", "test") } func main() { commitMsg, err := getCommitMessageFromFile(os.Args[1]) if err != nil { log.Fatal("Error parsing commitMsg: ", err) } firstLine, err := getFirstLine(commitMsg) if err != nil { log.Fatal("Error getting first line of commitMsg: ", err) } err = checkCommitMsg(firstLine) if err != nil { fmt.Println("### COMMIT MESSAGES dont match conventions") fmt.Println(err) fmt.Println("") fmt.Println("A valid example is:") fmt.Println("feat(lang): add Polish language") fmt.Println("valide types are: ", strings.Join(allowedTypes, ", ")) fmt.Println("see more at: https://www.conventionalcommits.org/en/v1.0.0/") os.Exit(1) } fmt.Println("Commit Message ok") } func checkCommitMsg(firstLine string) error { r, _ := regexp.Compile("^([a-z]*)(\\([^\\)]*\\))?!?:") results := r.FindStringSubmatch(firstLine) if len(results) < 3 { return errCommitMsgSyntax } if !CheckTyp(results[1]) { return errCommitMsgInvalideType } return nil } func CheckTyp(ty string) bool { for _, t := range allowedTypes { if t == ty { return true } } return false } func getFirstLine(commitMsg string) (string, error) { lines := strings.Split(commitMsg, "\n") return lines[0], nil } func getCommitMessageFromFile(path string) (string, error) { f, err := os.Open(path) if err != nil { return "", fmt.Errorf("cant open commit msg file: %w", err) } defer f.Close() buf := make([]byte, 1024) commitmsg := "" for { n, err := f.Read(buf) if err == io.EOF { break } if err != nil { return "", fmt.Errorf("cant read from commit-msg file: %w", err) } if n > 0 { commitmsg += string(buf[:n]) } } return commitmsg, nil }