Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a7c3047

Browse files
authored
Merge pull request #304 from sysprog21/check-commitlog
Improve commit checker and add bypass detection
2 parents bc44e71 + 29d963b commit a7c3047

File tree

2 files changed

+207
-19
lines changed

2 files changed

+207
-19
lines changed

‎scripts/check-commitlog.sh‎

Lines changed: 206 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#!/usr/bin/env bash
22

3-
# Check that every non-merge commit after the specified base commit has a commit
4-
# message ending with a valid Change-Id line. A valid Change-Id line must be the
5-
# last non-empty line of the commit message and follow the format:
6-
#
7-
# Change-Id: I<hexadecimal_hash>
3+
# This script checks:
4+
# 1. Change-Id presence (indicates commit-msg hook processing)
5+
# 2. Commit message quality (indicates pre-commit hook compliance)
6+
# 3. Bypass detection (detects --no-verify usage or web interface commits)
87
#
98
# Merge commits are excluded from this check.
109

@@ -24,26 +23,215 @@ BASE_COMMIT="0b8be2c15160c216e8b6ec82c99a000e81c0e429"
2423
# Get a list of non-merge commit hashes after BASE_COMMIT.
2524
commits=$(git rev-list --no-merges "${BASE_COMMIT}"..HEAD)
2625

26+
# Hook bypass detection patterns
27+
BYPASS_INDICATORS=(
28+
"--no-verify"
29+
"WIP"
30+
)
31+
32+
# Quality patterns that indicate hook processing
33+
PROBLEMATIC_PATTERNS=(
34+
'^[a-z]' # Uncapitalized subjects
35+
'\.$' # Ending with period
36+
'^.{1,10}$' # Too short subjects
37+
'^.{80,}' # Too long subjects
38+
'^(Update|Fix|Change|Modify) [a-zA-Z0-9_-]+\.(c|h)$' # Generic filename updates
39+
)
40+
41+
# Early exit if no commits to check
42+
[[ -z "$commits" ]] && { echo -e "${GREEN}No commits to check.${NC}"; exit 0; }
43+
44+
# Pre-compute indicator patterns for faster matching
45+
bypass_pattern=""
46+
for indicator in "${BYPASS_INDICATORS[@]}"; do
47+
bypass_pattern+="|${indicator,,}"
48+
done
49+
bypass_pattern="${bypass_pattern#|}"
50+
51+
# Ultra-fast approach: minimize git calls and parsing overhead
2752
failed=0
53+
warnings=0
54+
suspicious_commits=()
55+
56+
# Cache all commit data at once using the most efficient git format
57+
declare -A commit_cache short_cache subject_cache msg_cache
58+
59+
# Single git call to populate all caches - handle multiline messages properly
60+
current_commit=""
61+
current_msg=""
62+
reading_msg=false
63+
64+
while IFS= read -r line; do
65+
case "$line" in
66+
"COMMIT "*)
67+
# Save previous message if we were reading one
68+
if [[ "$reading_msg" = true && -n "$current_commit" ]]; then
69+
msg_cache["$current_commit"]="$current_msg"
70+
fi
71+
current_commit="${line#COMMIT }"
72+
commit_cache["$current_commit"]=1
73+
reading_msg=false
74+
current_msg=""
75+
;;
76+
"SHORT "*)
77+
short_cache["$current_commit"]="${line#SHORT }"
78+
;;
79+
"SUBJECT "*)
80+
subject_cache["$current_commit"]="${line#SUBJECT }"
81+
;;
82+
"MSGSTART")
83+
reading_msg=true
84+
current_msg=""
85+
;;
86+
*)
87+
# If we're reading a message, accumulate lines
88+
if [[ "$reading_msg" = true ]]; then
89+
if [[ -z "$current_msg" ]]; then
90+
current_msg="$line"
91+
else
92+
current_msg="$current_msg"$'\n'"$line"
93+
fi
94+
fi
95+
;;
96+
esac
97+
done < <(git log --format="COMMIT %H%nSHORT %h%nSUBJECT %s%nMSGSTART%n%B" --no-merges "${BASE_COMMIT}..HEAD")
2898

29-
for commit in $commits; do
30-
# Retrieve the commit message for the given commit.
31-
commit_msg=$(git log -1 --format=%B "${commit}")
99+
# Save the last message
100+
if [[ "$reading_msg" = true && -n "$current_commit" ]]; then
101+
msg_cache["$current_commit"]="$current_msg"
102+
fi
103+
104+
# Process cached data - no more git calls needed
105+
for commit in "${!commit_cache[@]}"; do
106+
[[ -z "$commit" ]] && continue
107+
108+
short_hash="${short_cache[$commit]}"
109+
subject="${subject_cache[$commit]}"
110+
full_msg="${msg_cache[$commit]}"
32111

33-
# Extract the last non-empty line from the commit message.
34-
last_line=$(echo "$commit_msg" | awk 'NF {line=0ドル} END {print line}')
112+
# Initialize issue tracking
113+
has_issues=0
114+
has_warnings=0
115+
issue_list=""
116+
warning_list=""
117+
118+
# Check 1: Change-Id validation (fastest check first)
119+
if [[ "$full_msg" != *"Change-Id: I"* ]]; then
120+
has_issues=1
121+
issue_list+="Missing valid Change-Id (likely bypassed commit-msg hook)|"
122+
((failed++))
123+
fi
35124

36-
# Check if the last line matches the expected Change-Id format.
37-
if [[ ! $last_line =~ ^Change-Id:\ I[0-9a-fA-F]+$ ]]; then
38-
subject=$(git log -1 --format=%s "${commit}")
39-
short_hash=$(git rev-parse --short "${commit}")
40-
echo "Commit ${short_hash} with subject '$subject' does not end with a valid Change-Id."
41-
failed=1
125+
# Check 2: Bypass indicators (single pattern match)
126+
full_msg_lower="${full_msg,,}"
127+
if [[ "$full_msg_lower" =~ ($bypass_pattern) ]]; then
128+
has_warnings=1
129+
warning_list+="Contains bypass indicator: '${BASH_REMATCH[1]}'|"
130+
((warnings++))
131+
fi
132+
133+
# Check 3: Subject validation (batch character operations)
134+
subject_len=${#subject}
135+
first_char="${subject:0:1}"
136+
last_char="${subject: -1}"
137+
138+
# Length checks
139+
if [[ $subject_len -le 10 ]]; then
140+
has_warnings=1
141+
warning_list+="Subject very short ($subject_len chars)|"
142+
((warnings++))
143+
elif [[ $subject_len -ge 80 ]]; then
144+
has_issues=1
145+
issue_list+="Subject too long ($subject_len chars)|"
146+
((failed++))
147+
fi
148+
149+
# Character validation using ASCII values
150+
if [[ ${#first_char} -eq 1 ]]; then
151+
# Check if it's a lowercase letter
152+
case "$first_char" in
153+
[a-z])
154+
has_issues=1
155+
issue_list+="Subject not capitalized|"
156+
((failed++))
157+
;;
158+
esac
159+
fi
160+
161+
# Period check
162+
if [[ "$last_char" == "." ]]; then
163+
has_issues=1
164+
issue_list+="Subject ends with period|"
165+
((failed++))
166+
fi
167+
168+
# Generic filename check (simplified pattern)
169+
if [[ "$subject" =~ ^(Update|Fix|Change|Modify)[[:space:]] ]]; then
170+
if [[ "$subject" =~ \.(c|h)$ ]]; then
171+
has_warnings=1
172+
warning_list+="Generic filename-only subject|"
173+
((warnings++))
174+
fi
175+
fi
176+
177+
# Check 4: Web interface (string contains check)
178+
if [[ "$full_msg" == *"Co-authored-by:"* ]]; then
179+
if [[ "$full_msg" != *"Change-Id:"* ]]; then
180+
has_issues=1
181+
issue_list+="Likely created via GitHub web interface|"
182+
((failed++))
183+
fi
184+
fi
185+
186+
# Check 5: Queue.c body (most expensive - do last and only when needed)
187+
if [[ "$full_msg" =~ ^[^$'\n']*$'\n'[[:space:]]*$'\n'Change-Id: ]]; then
188+
# Body appears empty - check if queue.c was modified
189+
if git diff-tree --no-commit-id --name-only -r "$commit" | grep -q "^queue\.c$"; then
190+
has_issues=1
191+
issue_list+="Missing commit body for queue.c changes|"
192+
((failed++))
193+
fi
194+
fi
195+
196+
# Report issues (only if found)
197+
if [[ $has_issues -eq 1 || $has_warnings -eq 1 ]]; then
198+
echo -e "${YELLOW}Commit ${short_hash}:${NC} ${subject}"
199+
200+
if [[ $has_issues -eq 1 ]]; then
201+
IFS='|' read -ra issues <<< "${issue_list%|}"
202+
for issue in "${issues[@]}"; do
203+
[[ -n "$issue" ]] && echo -e " [ ${RED}FAIL${NC} ] $issue"
204+
done
205+
suspicious_commits+=("$short_hash: $subject")
206+
fi
207+
208+
if [[ $has_warnings -eq 1 ]]; then
209+
IFS='|' read -ra warnings_arr <<< "${warning_list%|}"
210+
for warning in "${warnings_arr[@]}"; do
211+
[[ -n "$warning" ]] && echo -e " ${YELLOW}!${NC} $warning"
212+
done
213+
fi
42214
fi
43215
done
44216

45-
if [ $failed -ne 0 ]; then
46-
throw "Some commits are missing a valid Change-Id. Please amend the commit messages accordingly."
217+
if [[ $failed -gt 0 ]]; then
218+
echo -e "\n${RED}Problematic commits detected:${NC}"
219+
for commit in "${suspicious_commits[@]}"; do
220+
echo -e " ${RED}${NC} $commit"
221+
done
222+
223+
echo -e "\n${RED}These commits likely bypassed git hooks. Recommended actions:${NC}"
224+
echo -e "1. ${YELLOW}Verify hooks are installed:${NC} scripts/install-git-hooks"
225+
echo -e "2. ${YELLOW}Never use --no-verify flag${NC}"
226+
echo -e "3. ${YELLOW}Avoid GitHub web interface for commits${NC}"
227+
echo -e "4. ${YELLOW}Amend commits if possible:${NC} git rebase -i ${BASE_COMMIT}"
228+
echo
229+
230+
throw "Git hook compliance validation failed. Please fix the issues above."
231+
fi
232+
233+
if [[ $warnings -gt 0 ]]; then
234+
echo -e "\n${YELLOW}Some commits have quality warnings but passed basic validation.${NC}"
47235
fi
48236

49237
exit 0

‎scripts/checksums‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
25e7d2797e09bfafa0c0dee70111104648faec9d queue.h
22
b26e079496803ebe318174bda5850d2cce1fd0c1 list.h
3-
1029c2784b4cae3909190c64f53a06cba12ea38e scripts/check-commitlog.sh
3+
c286e18579b6461fc289732cee4a18a916f79659 scripts/check-commitlog.sh

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /