Skip to content

fix: run generic autofix tools and report per file - #911

Open
zlum wants to merge 1 commit into
peteromallet:mainfrom
zlum:fix/generic-autofix-runs-and-reports
Open

zlum wants to merge 1 commit into
peteromallet:mainfrom
zlum:fix/generic-autofix-runs-and-reports

Conversation

@zlum

@zlum zlum commented Oct 30, 2026

Copy link
Copy Markdown

Problem

desloppify autofix <tool>-violation never runs the tool for generic (tool-backed) fixers, yet reports success.

cmd_autofix calls fixer.fix(entries, dry_run=dry_run) without a path. make_generic_fixer treats a missing path the same as a dry run (if dry_run or not path:), so it returns one {file, line} entry per issue without running fix_cmd. The existing tests always pass path= directly, so they never exercise the CLI call.

Seen on a Kotlin project (ktlint, 6390 violations in ~100 files):

  Fixed 6390 Fix ktlint issues across 6390 files

  app/src/main/java/.../MainActivity.kt  →  fixed
  app/src/main/java/.../MainActivity.kt  →  fixed
  ... and 6360 more files

  Auto-resolved 0 issues in state
  Fixed 6390/6390 (0 skipped, 0 issues resolved)

Nothing was changed on disk. Related problems in the same path:

  • Once the tool does run, success is len(entries) - len(remaining), and entries[:fixed_count] are reported as "the fixed ones", which is an arbitrary slice. If the re-check fails (the tool errors and detect returns []), every entry counts as fixed.
  • The summary and the query payload (files_fixed, files_would_fix) use len(results) as a file count. Generic fixers return one result per issue, hence "across 6390 files".
  • --dry-run prints an empty "Sample changes (before → after)" section for generic fixers. The preview only shows entries whose name is in removed, and generic results have neither. fix: handle generic fixers that return entries without 'removed' key #484 fixed the crash on this shape but not the empty preview.

Fix

  • FixerConfig.takes_scan_path (default False). make_generic_fixer sets it, and cmd_autofix passes path= only to fixers that set it, so the TypeScript and Rust fixer signatures are unchanged. A generic fixer called without a path outside dry-run now raises instead of silently doing nothing.
  • The generic fixer groups results by file: {file, fixed_count, summary}. After running fix_cmd, it re-runs the check through run_tool_result and counts fixes per file (before − after). If the re-check errors, it claims nothing and reports recheck_failed. The fix command's exit code is still not treated as failure, because formatters such as ktlint exit non-zero when unfixable violations remain.
  • _result_item_count() is shared by the command, the cascade and the preview: len(removed), else fixed_count, else 1.
  • The summary and the query count distinct files.
  • For tool-backed results, the dry-run preview shows the flagged lines with the tool's message under "Sample flagged lines". The tool decides the rewrite, so no "after" exists to show.

Tests

  • 8 new tests in tests/lang/common/test_generic_plugin_integrations.py and tests/commands/test_cmd_autofix.py. 7 of them fail on main; the eighth (fixers without the flag still get no path) guards against a regression and passes on both.
  • Full suite: 5636 passed, 35 failed. The same 35 tests fail on unmodified main on Windows (review runner and tree-sitter import tests), so none are related.
  • ruff check . --select E9,F63,F7,F82, mypy (configured files) and lint-imports all pass.

Not in scope

The ktlint JSON parser is #680 / #778, and #778 also adds a Kotlin-specific fixer. This PR fixes the shared generic path that every other tool-backed language still uses.

🤖 Generated with Claude Code

`desloppify autofix` called fixer.fix() without a path, and the generic
fixer treated a missing path as a dry run. Tool-backed fixers (ktlint,
rubocop, ...) never ran their fix command, yet printed "Fixed N".

- FixerConfig.takes_scan_path: the command passes the scan path to
  fixers that run an external tool.
- Count fixes per file (before vs after re-check) instead of slicing the
  first N entries. Claim nothing when the re-check fails.
- Summary and query count distinct files, not results.
- Dry-run preview shows the flagged lines for tool-backed fixers instead
  of an empty "Sample changes" section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
github-actions Bot added a commit to citizenadam/desloppify that referenced this pull request Oct 30, 2026

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant