Repository navigation
Conversation
.editorconfig has set trim_trailing_whitespace = true for every file all along, and nothing enforced it. ruff only sees Python, and the invisible-character check looks for a specific set of code points that does not include a plain space. So the rule held only where someone's editor honoured it, and two lines had slipped past: a trailing line in django-bootstrap4's .github/dependabot.yml and one in django-icons' docs/index.rst. Finding those by hand is not a safeguard. lint checks rather than fixes, deliberately. These packages render HTML, and trailing space inside a template is output, so stripping it can change what a page looks like. That belongs in a diff a person reads, not in a check that quietly rewrites files. just format does the fixing, and the test suites assert rendered output, so a change that matters will fail there. format uses trailing-whitespace-fixer from pre-commit-hooks through uvx: the same implementation the pre-commit standard runs, invoked the way this justfile already invokes ruff, typos and twine, so it needs no config file and no developer install step. Verified it leaves binary files untouched, which matters because django-icons tracks a PNG. Final newlines are deliberately left alone, even though .editorconfig also asks for them. Eleven files across the five packages lack one, and they include Django templates where appending a newline changes rendered output, LICENSE, and that PNG. That needs case-by-case judgement rather than a blanket fixer. Verified both directions: lint exits 1 naming the file and telling you to run just format, and passes again once format has run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The first version piped every tracked file into the fixer, binaries included. It was harmless, since the fixer detects binary content and leaves it alone, but handing a PNG to a whitespace fixer and trusting it to decline is the wrong shape. It also opened several hundred files to change at most a couple. The file list now comes from the same `git grep -lIP` the check uses, so -I excludes binaries and the pattern excludes everything that is already correct. On a clean tree the fixer is not invoked at all. Verified: with trailing whitespace planted in docs/db.rst the list is exactly that one file, lint exits 1, format fixes it, lint passes. On a clean tree format reports nothing changed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two trailing spaces in Markdown are a hard line break, not an accident, and the first version of this change deleted them silently. pre-commit-hooks has --markdown-linebreak-ext for exactly that and I had not used it. The fixer now keeps exactly two trailing spaces in .md and still strips one or three, and the check excludes .md entirely. They have to agree: a check that failed on something `just format` deliberately preserves would leave you stuck between the two with no way out. Verified all four cases: a clean tree is untouched, a Markdown hard break survives format and passes lint, a single stray space in Markdown is still cleaned, and trailing whitespace outside Markdown still fails lint. Rebasing onto main also meant resolving the Unreleased section, which had grown four separate `## Unreleased` headings. Several of my pull requests prepended a new one instead of appending to the existing one, and git merged them cleanly because they sat at different line positions. All ten entries are now under a single heading. A release cut against the old file would have stamped the first heading and orphaned the other three. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
dyve
force-pushed
the
lint-no-trailing-whitespace
branch
from
October 11, 2026 10:33
5509b0d to
33131f8
Compare
Branches that each add `## Unreleased` instead of appending to the existing one merge without a conflict, because the two sides touch different lines. This repository reached four headings before anyone looked, and several of them were mine. The consequence is not cosmetic. Cutting a release stamps the first heading and leaves the rest untouched, so the entries below ship as unreleased notes for a version that already went out. That is the failure `just release-check` was widened to prevent, arriving through a door the changelog itself left open. Also rejects the heading sitting below a released section, which is the same mistake with the insertion point moved. None at all passes, deliberately. That is the correct state between a cut and the next change, and MAINTAINING.md already says what it means. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two rules this repository has stated for a long time and never enforced, so both held only while someone remembered. Each is a
git grepor agrepinjust lint, in the same shape as the existing_no-invisible-charactersrecipe.Trailing whitespace
.editorconfighas settrim_trailing_whitespace = truefor every file since the beginning, and nothing checked it. ruff only sees Python, and the invisible-character check looks for a specific set of code points that does not include a plain space. Two lines had slipped past: django-bootstrap4's.github/dependabot.ymland django-icons'docs/index.rst.lintchecks,formatfixes, matching the existing contract. Both are scoped bygit grep -lIP, so-Iexcludes binaries and the pattern excludes files already correct — on a clean tree the fixer is never invoked.Markdown hard line breaks are preserved. Two trailing spaces in Markdown are a hard break, not an accident, and an earlier revision of this branch deleted them silently.
formatnow passes--markdown-linebreak-ext=md, so exactly two spaces survive while one or three are still stripped, and the check excludes.md. The two have to agree: a check that failed on somethingformatdeliberately preserves would leave you stuck between them.Checking rather than auto-fixing elsewhere is deliberate. These packages render HTML, and trailing space inside a template is output, so stripping it can change a rendered page. That belongs in a diff a person reads.
On the "is there a standard" question: yes, and this uses it.
formatrunstrailing-whitespace-fixerfrompre-commit-hooksthroughuvx, the same implementation the pre-commit framework runs for this hook, invoked the way this justfile already runs ruff, typos and twine. No.pre-commit-config.yaml, nopre-commit installstep for contributors, no second place where linting is configured.One
## UnreleasedheadingBranches that each add the heading instead of appending to the existing one merge without a conflict, because the two sides touch different lines. This repository reached four before anyone looked, and several were mine. The consequence is not cosmetic: cutting a release stamps the first heading and leaves the rest, so those entries ship as pending notes for a version that already went out. That is the failure #694 was written to prevent, arriving through a door the changelog itself left open.
The check also rejects the heading sitting below a released section, and deliberately allows none at all, which is the correct state between a cut and the next change.
This branch's rebase consolidated the four headings into one, so main is already repaired by merging it.
Verified
Clean tree passes and
formattouches nothing. Trailing whitespace outside Markdown fails lint and is fixed byformat. A Markdown hard break survives both. A single stray space in Markdown is still cleaned. Two## Unreleasedheadings fail with the line numbers printed, a misplaced heading fails, and no heading passes.Propagation waits on django-bootstrap4#912 and django-icons#668, since the whitespace check would fail in those two until their stray lines are gone.
🤖 Generated with Claude Code