On 9/29/26 1:00 PM, Ales Musil wrote:
> Long commit message lines are difficult to read after git and email add
> indentation or quotation prefixes.  Enforce the documented 75-character
> limit while allowing Git-style trailers to remain unwrapped.
> 
> Add coverage for boundary values, trailer exemptions, and raw email
> input.
> 
> Assisted-by: GPT-5.6-Sol, OpenCode
> Signed-off-by: Ales Musil <[email protected]>
> ---

Hi Ales,

>  tests/checkpatch.at     | 103 ++++++++++++++++++++++++++++++++++++++++
>  utilities/checkpatch.py |  16 ++++++-
>  2 files changed, 117 insertions(+), 2 deletions(-)
> 
> diff --git a/tests/checkpatch.at b/tests/checkpatch.at
> index 352a5f4d2..af95579bf 100755
> --- a/tests/checkpatch.at
> +++ b/tests/checkpatch.at
> @@ -39,6 +39,23 @@ try_checkpatch__() {
>          AT_CHECK([$1 $top_srcdir/utilities/checkpatch.py -q test.patch])
>      fi
>  }
> +
> +try_checkpatch_stdin() {
> +    echo "$1" | sed 's/^    //' > test.patch
> +    if test -n "$2"; then
> +        echo "$2" | sed 's/^    //' > expout
> +    else
> +        : > expout
> +    fi
> +
> +    if test -s expout; then
> +        AT_CHECK([$PYTHON3 $top_srcdir/utilities/checkpatch.py -q < 
> test.patch],
> +                 [1], [stdout])
> +        AT_CHECK([sed '/^Lines checked:/,$d' stdout], [0], [expout])
> +    else
> +        AT_CHECK([$PYTHON3 $top_srcdir/utilities/checkpatch.py -q < 
> test.patch])
> +    fi
> +}
>  OVS_END_SHELL_HELPERS
>  
>  AT_SETUP([checkpatch - sign-offs])
> @@ -433,6 +450,92 @@ try_checkpatch \
>  
>  AT_CLEANUP
>  
> +AT_SETUP([checkpatch - commit message body length])
> +
> +body_75=$(printf '%75s' '' | tr ' ' x)
> +body_76=${body_75}x
> +long_tag_value=$(printf '%80s' '' | tr ' ' x)
> +
> +try_checkpatch \
> +   "Author: A
> +    Commit: A
> +
> +    $body_75
> +    Signed-off-by: A"
> +
> +try_checkpatch \
> +   "Author: A
> +    Commit: A
> +
> +    $body_76
> +    Signed-off-by: A" \
> +   "WARNING: Commit message body line is 76 characters long (recommended 
> limit is 75)
> +    1: $body_76
> +"
> +
> +try_checkpatch_stdin \
> +   "Author: A
> +    Commit: A
> +    Subject: checkpatch: Test body length.
> +     $long_tag_value
> +
> +    $body_76
> +    Signed-off-by: A
> +    ---" \
> +   "WARNING: Commit message body line is 76 characters long (recommended 
> limit is 75)
> +    6: $body_76
> +"
> +
> +try_checkpatch \
> +   "Author: A
> +    Commit: A
> +
> +    Acked-by: B
> +    Tested-at: https://example.com/test/1
> +    Link: https://example.com/reviews/$long_tag_value
> +    Arbitrary-Tag: $long_tag_value
> +    Reported-at: https://example.com/bugs/$long_tag_value
> +    Assisted-by: $long_tag_value
> +    Fixes: 123456789abc (\"$long_tag_value\")
> +    Signed-off-by: A"
> +
> +try_checkpatch \
> +   "Author: A
> +    Commit: A
> +
> +    This is ordinary prose with a colon: $long_tag_value
> +    Signed-off-by: A" \
> +   "WARNING: Commit message body line is 117 characters long (recommended 
> limit is 75)
> +    1: This is ordinary prose with a colon: $long_tag_value
> +"
> +
> +try_checkpatch \
> +   "Author: A
> +    Commit: A
> +
> +    Not/A/Trailer: $long_tag_value
> +    Signed-off-by: A" \
> +   "WARNING: Commit message body line is 95 characters long (recommended 
> limit is 75)
> +    1: Not/A/Trailer: $long_tag_value
> +"
> +
> +raw_patch="From 123456789abc Mon Sep 17 00:00:00 2001
> +From: A
> +Date: Tue, 29 Sep 2026 08:00:00 +0000
> +X-Long-Header: $long_tag_value
> + $long_tag_value
> +Subject: [PATCH] checkpatch: Test body length.
> +
> +$body_75
> +Link: https://example.com/reviews/$long_tag_value
> +Signed-off-by: A
> +---"
> +
> +try_checkpatch "$raw_patch"
> +try_checkpatch_stdin "$raw_patch"
> +
> +AT_CLEANUP
> +
>  AT_SETUP([checkpatch - malformed tags])
>  try_checkpatch \
>     "    Author: A
> diff --git a/utilities/checkpatch.py b/utilities/checkpatch.py
> index d644db9e1..49de50b19 100755
> --- a/utilities/checkpatch.py
> +++ b/utilities/checkpatch.py
> @@ -886,7 +886,8 @@ def run_subject_checks(subject, spellcheck=False):
>      return warnings
>  
>  
> -def ovs_checkpatch_parse(text, filename, author=None, committer=None):
> +def ovs_checkpatch_parse(text, filename, author=None, committer=None,
> +                         body_only=False):
>      global print_file_name, total_line, checking_file, \
>          empty_return_check_state
>  
> @@ -915,6 +916,7 @@ def ovs_checkpatch_parse(text, filename, author=None, 
> committer=None):
>                                       re.I | re.M | re.S)
>      is_fixes = re.compile(r'(\s*(Fixes:)(.*))$', re.I | re.M | re.S)
>      is_fixes_exact = re.compile(r'^Fixes: [0-9a-f]{12} \(".*"\)$')
> +    is_trailer = re.compile(r'^[A-Za-z0-9][A-Za-z0-9-]*:[ \t]+\S')
>  
>      tags_typos = {
>          r'^Acked by:': 'Acked-by:',
> @@ -929,6 +931,8 @@ def ovs_checkpatch_parse(text, filename, author=None, 
> committer=None):
>      reset_counters()
>  
>      current_line = ""
> +    subject_seen = False
> +    in_commit_body = body_only
>      for line in text.split("\n"):
>          if current_file != previous_file:
>              previous_file = current_file
> @@ -953,6 +957,8 @@ def ovs_checkpatch_parse(text, filename, author=None, 
> committer=None):
>              # Form feed
>              continue
>          if len(line) <= 0:
> +            if subject_seen:
> +                in_commit_body = True
>              continue
>  
>          if checking_file:
> @@ -1022,6 +1028,7 @@ def ovs_checkpatch_parse(text, filename, author=None, 
> committer=None):
>              elif is_author.match(line):
>                  author = is_author.match(line).group(2)
>              elif is_subject.match(line):
> +                subject_seen = True
>                  run_subject_checks(line, spellcheck)
>              elif is_signature.match(line):
>                  m = is_signature.match(line)
> @@ -1041,6 +1048,11 @@ def ovs_checkpatch_parse(text, filename, author=None, 
> committer=None):
>                              '--pretty=format:"Fixes: %h (\\\"%s\\\")" '
>                              '--abbrev=12 COMMIT_REF\n')
>                  print("%d: %s\n" % (lineno, line))
> +            elif (in_commit_body and len(line) > 75
> +                  and not is_trailer.match(line)):
> +                print_warning("Commit message body line is %d characters "
> +                              "long (recommended limit is 75)" % len(line))
> +                print("%d: %s\n" % (lineno, line))
>              elif spellcheck:
>                  check_spelling(line, False)

We'd skip spell checking for long lines.  That's not that bad but we
could probably fix it if we do:

            else:
                if (in_commit_body and len(line) > 75
                    and not is_trailer.match(line)):
                    print_warning("Commit message body line is %d characters "
                                  "long (recommended limit is 75)" % len(line))
                    print("%d: %s\n" % (lineno, line))
                if spellcheck:
                    check_spelling(line, False)

I can fold that in, what do you think?

>              for typo, correct in tags_typos.items():
> @@ -1138,7 +1150,7 @@ def ovs_checkpatch_file(filename):
>              continue
>      result = ovs_checkpatch_parse(part.get_payload(decode=False), filename,
>                                    mail.get('Author', mail['From']),
> -                                  mail['Commit'])
> +                                  mail['Commit'], body_only=True)
>  
>      if not mail['Subject'] or not mail['Subject'].strip():
>          if mail['Subject']:

Regards,
Dumitru

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to