@@ -15,37 +15,125 @@ const (
1515 BODY_REQUIRED = false
1616)
1717
18+ type MsgState int
19+
20+ const (
21+ // normal state
22+ Validated MsgState = iota
23+ Merge
24+ // non format error
25+ ArgumentMissing
26+ FileMissing
27+ ReadError
28+ // format error
29+ EmptyMessage
30+ EmptyHeader
31+ BadHeaderFormat
32+ WrongType
33+ BodyMissing
34+ NoBlankLineBeforeBody
35+ LineOverLong
36+ UndefindedError
37+ )
38+
1839var (
40+ msgStates = [... ]string {
41+ "Validated" ,
42+ "Merge" ,
43+ "ArgumentMissing" ,
44+ "FileMissing" ,
45+ "ReadError" ,
46+ "EmptyMessage" ,
47+ "EmptyHeader" ,
48+ "BadHeaderFormat" ,
49+ "WrongType" ,
50+ "BodyMissing" ,
51+ "NoBlankLineBeforeBody" ,
52+ "LineOverLong" ,
53+ "UndefindedError" ,
54+ }
55+ stateHint = [... ]string {
56+ "%s: commit message meet the rule.\n " ,
57+ "%s: merge commit detected,skip check.\n " ,
58+ "Error %s: commit message file argument missing.\n " ,
59+ "Error %s: file %s not exists.\n " ,
60+ "Error %s: read file %s error.\n " ,
61+ "Error %s: commit message has no content except whitespaces.\n " ,
62+ "Error %s: header (first line) has no content except whitespaces.\n " ,
63+ `Error %s: header (first line) not following the rule:
64+ %s
65+ if you can not find any error after check, maybe you use Chinese colon, or lack of whitespace after the colon.` ,
66+ "Error %s: %s, should be one of the keywords:\n %s\n " ,
67+ "Error %s: body has no content except whitespaces.\n " ,
68+ "Error %s: no empty line between header and body.\n " ,
69+ "Error %s: the length of line is %d, exceed %d:\n %s\n " ,
70+ "Error %s: unexpected error occurs, please raise an issue." ,
71+ }
1972 typeList = [... ]string {
20- "feat" , // 新功能( feature)
21- "fix" , // 修补bug
22- "docs" , // 文档( documentation)
23- "style" , // 格式(不影响代码运行的变动)
73+ "feat" , // new feature 新功能
74+ "fix" , // fix bug 修复
75+ "docs" , // documentation 文档
76+ "style" , // changes not affect logic 格式(不影响代码运行的变动)
2477 "refactor" , // 重构(既不是新增功能,也不是修改bug的代码变动)
25- "perf" , // 提升性能( performance)
78+ "perf" , // performance 提升性能
2679 "test" , // 增加测试
2780 "chore" , // 构建过程或辅助工具的变动'
2881 "revert" , // 撤销以前的 commit
29- "Revert" } // 有些版本的工具生成的revert message首字母大写
82+ "Revert" , // 有些工具生成的 revert 首字母大写
83+ }
84+ ruleHint = `Commit message rule as follow:
85+ <type>(<scope>): <subject>
86+ // empty line
87+ <body>
88+ // empty line
89+ <footer>
90+
91+ (<scope>), <body> and <footer> are optional
92+ <type> must be one of %s
93+ more specific instructions, please refer to https://github.com/JayceChant/commit-msg.go`
3094)
3195
96+ func (state MsgState ) Name () string {
97+ return msgStates [state ]
98+ }
99+
100+ func (state MsgState ) Hint () string {
101+ return stateHint [state ]
102+ }
103+
104+ func logAndExit (state MsgState , v ... interface {}) {
105+ a := append ([]interface {}{state .Name ()}, v ... )
106+ if state <= Merge {
107+ log .Printf (state .Hint (), a ... )
108+ os .Exit (0 )
109+ } else if state <= FileMissing {
110+ log .Fatalf (state .Hint (), a ... )
111+ } else {
112+ log .Printf (state .Hint (), a ... )
113+ log .Fatalf (ruleHint , strings .Join (typeList [:], ", " ))
114+ }
115+ }
116+
32117func getMsg (path string ) string {
33118 if path == "" {
34- log . Fatalln ( "Arg missing." )
119+ logAndExit ( ArgumentMissing )
35120 }
36121
37122 f , err := os .Stat (path )
38123 if err != nil {
39- log .Fatalln (err )
124+ log .Println (err )
125+ logAndExit (FileMissing , path )
40126 }
41127
42128 if f .IsDir () {
43- log .Fatalln (path , "is not a file." )
129+ log .Println (path , "is not a file." )
130+ logAndExit (FileMissing , path )
44131 }
45132
46133 buf , err := ioutil .ReadFile (path )
47134 if err != nil {
48- log .Fatalln (err )
135+ log .Println (err )
136+ logAndExit (ReadError , path )
49137 }
50138
51139 return string (buf )
@@ -61,64 +149,69 @@ func checkType(type_ string) {
61149 return
62150 }
63151 }
64- log . Fatalln ( "Wrong type." )
152+ logAndExit ( WrongType , type_ , strings . Join ( typeList [:], ", " ) )
65153}
66154
67155func checkHeader (header string ) {
68156 if checkEmpty (header ) {
69- log . Fatalln ( "Empty header." )
157+ logAndExit ( EmptyHeader )
70158 }
71159
72160 re := regexp .MustCompile (HEADER_PATTERN )
73161 groups := re .FindStringSubmatch (header )
74162
75- isFixupOrSquash := (groups [2 ] != "" )
163+ if groups == nil || checkEmpty (groups [5 ]) {
164+ logAndExit (BadHeaderFormat , header )
165+ }
76166
77167 type_ := groups [3 ]
78- // scope = groups[4] // TODO: 根据配置对scope检查
79- // subject = (groups[5] != "") // TODO: 根据规则对subject检查
80168 checkType (type_ )
81169
170+ isFixupOrSquash := (groups [2 ] != "" )
171+ // scope := groups[4] // TODO: 根据配置对scope检查
172+ // subject := groups[5] // TODO: 根据规则对subject检查
173+
82174 length := len (header )
83- if length > LINE_LIMIT && ! (isFixupOrSquash || type_ == "revert" ) {
84- log .Fatalln ("Line overlong." )
175+ if length > LINE_LIMIT &&
176+ ! (isFixupOrSquash || type_ == "revert" || type_ == "Revert" ) {
177+ logAndExit (LineOverLong , length , LINE_LIMIT , header )
85178 }
86179}
87180
88181func checkBody (body string ) {
89182 if checkEmpty (body ) {
90183 if BODY_REQUIRED {
91- log . Fatalln ( "Empty body." )
184+ logAndExit ( BodyMissing )
92185 } else {
93- return
186+ logAndExit ( Validated )
94187 }
95188 }
96189
97190 if ! checkEmpty (strings .SplitN (body , "\n " , 2 )[0 ]) {
98- log . Fatalln ( "Blank line lacking between header and body." )
191+ logAndExit ( NoBlankLineBeforeBody )
99192 }
100193
101194 for _ , line := range strings .Split (body , "\n " ) {
102- if len (line ) > LINE_LIMIT {
103- log .Fatalln ("Line overlong." )
195+ length := len (line )
196+ if length > LINE_LIMIT {
197+ logAndExit (LineOverLong , length , LINE_LIMIT , line )
104198 }
105199 }
106200}
107201
108202func validateMsg (msg string ) {
109- msg = strings .TrimSpace (msg )
110- if msg == "" {
111- log .Fatalln ("Empty Message." )
203+ if checkEmpty (msg ) {
204+ logAndExit (EmptyMessage )
112205 }
113206
114207 isMerge , err := regexp .MatchString (MERGE_PATTERN , msg )
115208 if err != nil {
116- log .Fatalln (err )
209+ log .Println (err )
210+ logAndExit (UndefindedError )
117211 }
118212
119213 if isMerge {
120- log .Println ("Merge message, skip check." )
121- os .Exit (0 )
214+ logAndExit (Merge )
122215 }
123216
124217 sections := strings .SplitN (msg , "\n " , 2 )
@@ -127,8 +220,10 @@ func validateMsg(msg string) {
127220 if len (sections ) == 2 {
128221 checkBody (sections [1 ])
129222 } else if BODY_REQUIRED {
130- log . Fatalln ( "Body missing. Maybe a new line is lacking." )
223+ logAndExit ( BodyMissing )
131224 }
225+
226+ logAndExit (Validated )
132227}
133228
134229func main () {
0 commit comments