| 
4 | 4 | # This source code is licensed under the BSD-style license found in the  | 
5 | 5 | # LICENSE file in the root directory of this source tree.  | 
6 | 6 | 
 
  | 
7 |  | -# Check 1: If commit header contains WIP, everything is ok  | 
8 |  | -git rev-list --format=%s --max-count=1 HEAD | grep -q WIP && exit 0  | 
9 |  | - | 
10 |  | -# Check 2: lintunner on latest patches.  | 
11 |  | -lintrunner --revision 'HEAD^'  | 
12 |  | -if [[ $? != 0 ]]  | 
13 |  | -	then  | 
14 |  | -	echo "Failed linting"  | 
15 |  | -	exit 1  | 
 | 7 | +RESET='\e[0m'  | 
 | 8 | +RED='\e[31m'  | 
 | 9 | +GREEN='\e[32m'  | 
 | 10 | +YELLOW='\e[33m'  | 
 | 11 | +BLUE='\e[34m'  | 
 | 12 | + | 
 | 13 | +INFO="${BLUE}[INFO]${RESET}"  | 
 | 14 | +WARNING="${YELLOW}[WARNING]${RESET}"  | 
 | 15 | +ERROR="${RED}[ERROR]${RESET}"  | 
 | 16 | +SUCCESS="${GREEN}[SUCCESS]${RESET}"  | 
 | 17 | + | 
 | 18 | +# This list of imperative verbs was compiled from the entire list of Executorch  | 
 | 19 | +# commits. It should be fairly exhaustive, but add more verbs if you find one  | 
 | 20 | +# that's missing.  | 
 | 21 | +VERBS="Add|Fix|Update|Refactor|Improve|Remove|Change|Implement|Create|Modify|"\  | 
 | 22 | +"Enable|Integrate|Make|Support|Deprecate|Extend|Enhance|Convert|Rewrite|Unify|"\  | 
 | 23 | +"Optimize|Expand|Reorganize|Adjust|Streamline|Clarify|Introduce|Document|"\  | 
 | 24 | +"Polish|Standardize|Revise|Simplify|Restore|Resolve|Replace|Suppress|Migrate|"\  | 
 | 25 | +"Generate|Delete|Exclude|Register|Include|Upgrade|Validate|Verify|Refine|"\  | 
 | 26 | +"Reimplement|Patch|Sync|Revert|Fixup|Enhance|Append|Annotate|Disable|Emit|"\  | 
 | 27 | +"Handle|Ignore|Interpret|Instantiate|Invoke|Limit|Load|Modify|Permit|Print|"\  | 
 | 28 | +"Profile|Recalculate|Reconstruct|Redefine|Redesign|Reevaluate|Relocate|Remap|"\  | 
 | 29 | +"Render|Reposition|Request|Revert|Sanitize|Specify|Strengthen|Stub|Substitute|"\  | 
 | 30 | +"Tag|Tweak|Unify|Unlock|Unset|Use|Validate|Verify"  | 
 | 31 | + | 
 | 32 | +# Remote branch  | 
 | 33 | +REMOTE=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null)  | 
 | 34 | + | 
 | 35 | +if [ -z "$REMOTE" ]; then  | 
 | 36 | +    echo -e "${WARNING} Could not find upstream branch to compare to."  | 
 | 37 | +    echo "Please specify the number of commits you are pushing."  | 
 | 38 | +    echo -n "Enter number of commits to check (default 1): " > /dev/tty  | 
 | 39 | +    read NUM_COMMITS < /dev/tty  | 
 | 40 | +    NUM_COMMITS=${NUM_COMMITS:-1} # Default to 1 if empty  | 
 | 41 | +    RANGE=$(git rev-list HEAD -n "$NUM_COMMITS")  | 
 | 42 | +    COMMITS=${RANGE}  | 
 | 43 | +elif [ "$(git rev-parse --abbrev-ref HEAD)" == "HEAD" ]; then  | 
 | 44 | +    echo -e "${WARNING} You're in a detached HEAD state."  | 
 | 45 | +    echo "Please specify the number of commits you are pushing."  | 
 | 46 | +    echo -n "Enter number of commits to check (default 1): " > /dev/tty  | 
 | 47 | +    read NUM_COMMITS < /dev/tty  | 
 | 48 | +    NUM_COMMITS=${NUM_COMMITS:-1} # Default to 1 if empty  | 
 | 49 | +    RANGE=$(git rev-list HEAD -n "$NUM_COMMITS")  | 
 | 50 | +    COMMITS=${RANGE}  | 
 | 51 | +else  | 
 | 52 | +    # Determine commits to check  | 
 | 53 | +    RANGE="$REMOTE..HEAD"  | 
 | 54 | +    COMMITS=$(git rev-list "$RANGE")  | 
 | 55 | +fi  | 
 | 56 | + | 
 | 57 | +if [ -z "$COMMITS" ]; then  | 
 | 58 | +    echo -e "${INFO} No new commits to check."  | 
 | 59 | +    exit 0  | 
16 | 60 | fi  | 
17 | 61 | 
 
  | 
18 |  | -# Check 3: License headers  | 
19 |  | -# We do a simple check of if all committed headers contain "$current_year Arm".  | 
20 |  | -# This does not guarantee OK in ci but should be ok most of the time.  | 
 | 62 | +for COMMIT in ${COMMITS}; do  | 
 | 63 | +    # If commit header contains WIP, everything is ok  | 
 | 64 | +    git rev-list --format=%s --max-count=1 ${COMMIT} | grep -q WIP && \  | 
 | 65 | +         continue  | 
 | 66 | + | 
 | 67 | +    echo -e "${INFO} Checking commit ${COMMIT}"  | 
 | 68 | + | 
 | 69 | +    # lintrunner on latest patches.  | 
 | 70 | +    echo -e "${INFO} Lintrunner"  | 
 | 71 | +    lintrunner --revision ${COMMIT}  | 
 | 72 | +    if [[ $? != 0 ]]; then  | 
 | 73 | +        echo -e "${ERROR} Failed linting"  | 
 | 74 | +        FAILED=1  | 
 | 75 | +    else  | 
 | 76 | +        echo -e "${SUCCESS} Lintrunner OK"  | 
 | 77 | +    fi  | 
 | 78 | + | 
 | 79 | +    # Check license headers  | 
 | 80 | +    # We do a simple check of if all committed headers contain  | 
 | 81 | +    # "$current_year Arm". This does not guarantee OK in ci but should be ok  | 
 | 82 | +    # most of the time.  | 
 | 83 | +    echo -e "${INFO} License check"  | 
 | 84 | + | 
 | 85 | +    current_year=$(date +%Y)  | 
 | 86 | +    failed_license_check=false  | 
 | 87 | +    commit_files=$(git diff-tree --no-commit-id --name-only \  | 
 | 88 | +        --diff-filter=ACMR ${COMMIT} -r)  | 
 | 89 | +    for commited_file in $commit_files; do  | 
 | 90 | +        head $commited_file | grep -q "$current_year Arm"  | 
 | 91 | +        if [[ $? != 0 ]]; then  | 
 | 92 | +            echo -e "${ERROR} Header in $commited_file did not contain"\  | 
 | 93 | +            "'$current_year Arm'"  | 
 | 94 | +            failed_license_check=true  | 
 | 95 | +        else  | 
 | 96 | +            echo -e "${SUCCESS} $commited_file passed license check"  | 
 | 97 | +        fi  | 
 | 98 | +    done  | 
 | 99 | + | 
 | 100 | +    if [[ $failed_license_check == true ]]; then  | 
 | 101 | +        FAILED=1  | 
 | 102 | +    else  | 
 | 103 | +        echo -e "${SUCCESS} All files passed license check"  | 
 | 104 | +    fi  | 
 | 105 | + | 
 | 106 | +    # Check commit message  | 
 | 107 | +    echo -e "${INFO} Checking commit message"  | 
 | 108 | +    COMMIT_MSG=$(git log -1 --format=%B "$COMMIT")  | 
21 | 109 | 
 
  | 
22 |  | -current_year=$(date +%Y)  | 
23 |  | -failed_license_check=false  | 
24 |  | -commit_files=$(git diff-tree --no-commit-id --name-only --diff-filter=ACMR HEAD -r)  | 
 | 110 | +    SUBJECT=$(echo "$COMMIT_MSG" | head -n1)  | 
 | 111 | +    BODY=$(echo "$COMMIT_MSG" | tail -n +2)  | 
25 | 112 | 
 
  | 
 | 113 | +    # Check subject length (72 chars)  | 
 | 114 | +    SUBJECT_MAX_LEN=72  | 
 | 115 | +    if [ ${#SUBJECT} -gt ${SUBJECT_MAX_LEN} ]; then  | 
 | 116 | +        echo -e "${ERROR} Subject exceeds ${SUBJECT_MAX_LEN} characters:"\  | 
 | 117 | +            "'${SUBJECT}'" >&2  | 
26 | 118 | 
 
  | 
27 |  | -for commited_file in $commit_files; do  | 
28 |  | -	head $commited_file | grep -q "$current_year Arm"  | 
29 |  | -	if [[ $? != 0 ]]  | 
30 |  | -		then  | 
31 |  | -			echo "Header in $commited_file did not contain '$current_year Arm'"  | 
32 |  | -			failed_license_check=true  | 
33 |  | -		else  | 
34 |  | -			echo "$commited_file passed license check"  | 
35 |  | -	fi  | 
 | 119 | +        FAILED=1  | 
 | 120 | +    else  | 
 | 121 | +        echo -e "${SUCCESS} Commit message subject OK"  | 
 | 122 | +    fi  | 
 | 123 | + | 
 | 124 | +    # Check body line length (72 chars)  | 
 | 125 | +    BODY_MAX_LEN=72  | 
 | 126 | +    line_number=2 # Subject + 1 empty line  | 
 | 127 | +    failed_body_check=false  | 
 | 128 | +    while IFS= read -r line; do  | 
 | 129 | +        if [ ${#line} -gt ${BODY_MAX_LEN} ]; then  | 
 | 130 | +            echo -e "${ERROR} Line ${line_number} in body exceeds"\  | 
 | 131 | +                "${BODY_MAX_LEN} characters: '$line'" >&2  | 
 | 132 | + | 
 | 133 | +            failed_body_check=true  | 
 | 134 | +        fi  | 
 | 135 | + | 
 | 136 | +        ((line_number++))  | 
 | 137 | +    done <<< "$BODY"  | 
 | 138 | + | 
 | 139 | +    if [[ $failed_body_check == true ]]; then  | 
 | 140 | +        FAILED=1  | 
 | 141 | +    else  | 
 | 142 | +        echo -e "${SUCCESS} Commit message body OK"  | 
 | 143 | +    fi  | 
 | 144 | + | 
 | 145 | +    # Check for Signed-off-by  | 
 | 146 | +    if ! echo "$COMMIT_MSG" | grep -qE "^Signed-off-by: "; then  | 
 | 147 | +        echo -e "${ERROR} Commit message must contain a 'Signed-off-by'"\  | 
 | 148 | +            "footer." >&2  | 
 | 149 | + | 
 | 150 | +        FAILED=1  | 
 | 151 | +    fi  | 
 | 152 | + | 
 | 153 | +    # Check subject format, should start with 'Arm backend: ' and be  | 
 | 154 | +    # imperative mood.  | 
 | 155 | +    if [[ ! "$SUBJECT" =~ ^"Arm backend":\ (${VERBS}) ]]; then  | 
 | 156 | +        echo -e "${WARNING} Subject should start with 'Arm backend: '"\  | 
 | 157 | +            "followed by an imperative verb." >&2  | 
 | 158 | +        echo -n "There are warnings in your commit message. Do you want to"\  | 
 | 159 | +            "ignore the warning (y/N): " > /dev/tty  | 
 | 160 | + | 
 | 161 | +        read USER_INPUT < /dev/tty  | 
 | 162 | + | 
 | 163 | +        # Check user input for warnings  | 
 | 164 | +        if [[ ! "$USER_INPUT" =~ ^[Yy]$ ]]; then  | 
 | 165 | +            FAILED=1  | 
 | 166 | +        fi  | 
 | 167 | +    fi  | 
 | 168 | + | 
 | 169 | +    echo "" # Newline to visually separate commit processing  | 
36 | 170 | done  | 
37 | 171 | 
 
  | 
38 |  | -if [[ $failed_license_check == true ]]  | 
39 |  | -	then  | 
40 |  | -		exit 1  | 
41 |  | -	else  | 
42 |  | -		echo "Passed simple license check"  | 
 | 172 | +if [[ $FAILED ]]; then  | 
 | 173 | +    echo -e "${INFO} Fix your commit message errors with"\  | 
 | 174 | +        "'git commit --amend' or 'git commit --fixup=<SHA>'"  | 
 | 175 | + | 
 | 176 | +    exit 1  | 
 | 177 | +else  | 
 | 178 | +    echo -e "${SUCCESS} All checks passed"  | 
43 | 179 | fi  | 
44 | 180 | 
 
  | 
45 | 181 | exit 0  | 
0 commit comments