Skip to content

Feature/ add a tag(--body-length-limit) for command commit#1849

Open
yjaw wants to merge 2 commits intocommitizen-tools:masterfrom
yjaw:feature/commit-line-limt
Open

Feature/ add a tag(--body-length-limit) for command commit#1849
yjaw wants to merge 2 commits intocommitizen-tools:masterfrom
yjaw:feature/commit-line-limt

Conversation

@yjaw
Copy link
Contributor

@yjaw yjaw commented Feb 5, 2026

Description

I added a tag (—body-length-limit) for command commit. This tag utilizes Python’s built-in library, textwrap, to rewrap the body. It also respects the user’s |(\n) signal. This tag will affect the footer as well.
The flow is as follows:

  1. Split the body into separate lines using the \n character.
  2. Start from the third line, where the body begins. Use textwrap to rewrap that line.
  3. Reconstruct the entire body message from those rewrapped lines.

Checklist

Was generative AI tooling used to co-author this PR?

  • Yes (please specify the tool below)

Generated-by: [Gemini] following the guidelines

Code Changes

  • Add test cases to all the changes you introduce
  • Run uv run poe all locally to ensure this change passes linter check and tests
  • Manually test the changes:
    • Verify the feature/bug fix works as expected in real-world scenarios
    • Test edge cases and error conditions
    • Ensure backward compatibility is maintained
    • Document any manual testing steps performed
  • Update the documentation for the changes

Documentation Changes

  • Run uv run poe doc locally to ensure the documentation pages renders correctly
  • Check and fix any broken links (internal or external)

Expected Behavior

  1. This option should modify the line length for your message if its length exceeds the limit you’ve set.
  2. Adding this tag or setting it to 0 should have no effect.
  3. If the message body is empty, it will be fine.
  4. This option will affect the text in both the body and footer sections.

Steps to Test This Pull Request

  1. When using the commit command, you can add the —body-length-limit [int] option to set a limit on the length of the commit message. If you don’t want to set a limit, you can set the option to 0.

Additional Context

close #1597

@codecov
Copy link

codecov bot commented Feb 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.00%. Comparing base (26e5d80) to head (1f74bb2).
⚠️ Report is 15 commits behind head on master.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1849      +/-   ##
==========================================
+ Coverage   97.98%   98.00%   +0.01%     
==========================================
  Files          60       60              
  Lines        2686     2711      +25     
==========================================
+ Hits         2632     2657      +25     
  Misses         54       54              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Collaborator

@bearomorphism bearomorphism left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

)

# Execute with body_length_limit
commands.Commit(config, {"body_length_limit": 72})()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The number 72 should be extracted.

assert len(line) <= 72, (
f"Line exceeds 72 chars: '{line}' ({len(line)} chars)"
)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a file regression check here and remove assert line[0] == ... and assert line[1] == ...

Comment on lines +387 to +389
commit_mock = mocker.patch(
"commitizen.git.commit", return_value=cmd.Command("success", "", b"", b"", 0)
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please reuse commit_mock fixture. Same for other new tests.

assert lines[1] == ""
body_lines = lines[2:]
for line in body_lines:
if line.strip():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if can be removed?

# All lines should be <= 45 chars
for line in body_lines:
if line.strip():
assert len(line) == 45, (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not <=?



@pytest.mark.usefixtures("staging_is_clean")
def test_commit_command_with_body_length_limit_wrapping(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all the new tests can be merged into one and use parameterize to shorten the tests

Basically we can do like following:

fixtures
parameterize
def test_...(...):
    mocker.patch(
        "questionary.prompt",
        return_value={
            "prefix": "feat",
            "subject": "add feature",
            "scope": "",
            "is_breaking_change": False,
            "body": body, # parameterized, can be a long text with / without line breaks or short strings or an empty string
            "footer": "",
        },
    )

    # commit with parameterized config

    # check each line in line[2:] does not exceed the line length limit if it is not 0

    # file regression check

Comment on lines +113 to +115
if (
body_length_limit is None or body_length_limit <= 0
): # do nothing for no limit
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (
body_length_limit is None or body_length_limit <= 0
): # do nothing for no limit
if (
body_length_limit <= 0
): # do nothing for no limit

): # do nothing for no limit
return message

message_parts = message.split("\n", 2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
message_parts = message.split("\n", 2)
lines = message.split("\n")

and I'm entirely not sure whether there will be issues related to LF and CRLF. Need to check further

Comment on lines +122 to +131
# First line is subject, second is blank line, rest is body
subject = message_parts[0]
blank_line = message_parts[1]
body = message_parts[2].strip()
body_lines = body.split("\n")
wrapped_body_lines = []
for line in body_lines:
wrapped_body_lines.append(textwrap.fill(line, width=body_length_limit))
wrapped_body = "\n".join(wrapped_body_lines)
return f"{subject}\n{blank_line}\n{wrapped_body}"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# First line is subject, second is blank line, rest is body
subject = message_parts[0]
blank_line = message_parts[1]
body = message_parts[2].strip()
body_lines = body.split("\n")
wrapped_body_lines = []
for line in body_lines:
wrapped_body_lines.append(textwrap.fill(line, width=body_length_limit))
wrapped_body = "\n".join(wrapped_body_lines)
return f"{subject}\n{blank_line}\n{wrapped_body}"
# First line is subject, second is blank line, rest is body
wrapped_body_lines = [textwrap.fill(line, width=body_length_limit) for line in lines[2:]]
return "\n".join(chain(lines[:2], wrapped_body_lines))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add option for body line length

2 participants