-
Notifications
You must be signed in to change notification settings - Fork 0
/
commit-msg
executable file
·143 lines (119 loc) · 5.42 KB
/
commit-msg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/bin/bash
# Ensure commit message matches conventional commit ...conventions
# Unset this and this script will straight up flip a table if it thinks your commit message sucks
permissive_mode=1
# Variable munging
commit_content=$(grep -v '\#' $1)
commit_linecount=$(echo "$commit_content" | wc -l)
commit_firstline=$(echo "$commit_content" | awk 'NR==1')
commit_firstline_len=$(echo "$commit_firstline" | wc -m)
commit_firstline_end=$(echo "$commit_firstline" | awk '{print substr($0,length($0),1)}')
commit_firstline_case=$(grep [[:upper:]] $commit_firstline &>/dev/null) # || 'foo')
if [[ $commit_linecount -gt 1 ]]; then
multiline=1
commit_secondline=$(echo "$commit_content" | awk 'NR==2')
commit_second_lastline=$(echo "$commit_content" | tail -n 2 | head -n 1)
commit_lastline=$(echo "$commit_content" | tail -n 1)
fi
conventional_commit_regex='^(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert)(!)?(\(.+\))?:\s'
# Strings
help_firstline=$(cat << EOF
The first line of your commit should match the following pattern:
<type>(<scope>): <short summary>
│ │ │
│ │ └─> Summary in present tense. Not capitalized. No period at the end.
│ │
│ └─> Commit Scope (optional): core|cdn|docs|tasks|etc
│
└─> Commit Type: build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert
build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
ci: Changes to CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
docs: Documentation only changes
feat: A new feature
fix: A bug fix
perf: A code change that improves performance
refactor: A code change that neither fixes a bug nor adds a feature
style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
test: Adding missing tests or correcting existing tests\n
Examples:
# Commit message with no body
docs: correct spelling of CHANGELOG
# Commit message with scope
feat(lang): add Polish language
# Commit message with description and breaking change footer
feat: allow provided config object to extend other configs
BREAKING CHANGE: extends key in config file is now used for extending other config files
# Commit message with ! to draw attention to breaking change
feat!: send an email to the customer when a product is shipped
# Commit message with scope and ! to draw attention to breaking change
feat(api)!: send an email to the customer when a product is shipped
# Commit message with both ! and BREAKING CHANGE footer
chore!: drop support for Node 6
# Commit message with both ! and BREAKING CHANGE footer
BREAKING CHANGE: use JavaScript features not available in Node 6.
EOF
)
help_commitperiod='- Commit message should not end with a period.'
help_commitcase='- Commit message should be lowercase.'
help_longcommit='- Commit message should not be longer than 72 characters.'
help_longbody='- Commit message body/footer should not be longer than 80 characters.'
# Multiple footers are not supported at this time :/
help_secondline=$(cat << EOF
- The second line of a multi lined commit message should be blank, providing a spacer between the commit message and body.
<type>[optional scope]: <description>
[optional body]
[optional footer]\n
EOF
)
help_footerspacer="- The second last line of a multi lined commit message should be blank, providing a spacer between the commit message and footer."
function fail_msg {
case $1 in
firstline) echo -e "$help_firstline" ;;
commitperiod) echo -e "$help_commitperiod" ;;
longcommit) echo -e "$help_longcommit" ;;
footerspacer) echo -e "$help_footerspacer" ;;
longbody) echo -e "$help_longbody" ;;
secondline) echo -e "$help_secondline" ;;
esac
}
declare -a failures
# Tests
grep -E "${conventional_commit_regex}" $1 &>/dev/null || failures+=('firstline')
[[ $commit_firstline_end != '.' ]] || failures+=('commitperiod')
(( $commit_firstline_len < 73 )) || failures+=('longcommit')
[[ -n $commit_firstline_case ]] || failues+=('commitcase')
if [[ -n $multiline ]]; then
commit_secondline=$(echo "$commit_content" | awk 'NR==2')
[[ -n $commit_secondline ]] && failures+=('secondline')
while read line; do
if [[ -z $longbody ]] && [[ -n $line ]]; then
len=$(echo "$line" | wc -m)
(( $len > 80 )) && longbody=1
fi
done <<< "$(echo "$commit_content" | awk 'NR>1')"
[[ -z $longbody ]] || failures+=('longbody')
[[ -n $commit_lastline ]] && [[ -z $commit_second_lastline ]] || failures+=('footerspacer')
fi
if [[ ${#failures[@]} > 0 ]]; then
if [[ -n "$permissive_mode" ]]; then
echo -e "WARNING - supplied commit message may not meet convention.\n###################################################################"
else
echo -e "COMMIT REJECTED - supplied commit message does not meet convention.\n###################################################################"
fi
for fail in "${failures[@]}"; do
fail_msg $fail
done
if [[ -n "$permissive_mode" ]]; then
echo -e "\n-------------------------------------------"
exec </dev/tty
read -n 1 -p "(c)ontinue anyway, any other key to abort..." choice
echo
exec <&-
case $choice in
[Cc]) exit 0 ;;
*) exit 1 ;;
esac
else
exit 1
fi
fi