Skip to content

feat: add --fail-on-unfixable flag for single-pass fix and validation#6540

Open
omar-y-abdi wants to merge 3 commits intorealm:mainfrom
omar-y-abdi:feat/6450-fail-on-unfixable
Open

feat: add --fail-on-unfixable flag for single-pass fix and validation#6540
omar-y-abdi wants to merge 3 commits intorealm:mainfrom
omar-y-abdi:feat/6450-fail-on-unfixable

Conversation

@omar-y-abdi
Copy link

Fixes #6450

Problem: swiftlint --fix always returns exit code 0, even when unfixable violations
remain. Users in CI/pre-commit hooks must run SwiftLint twice: swiftlint --fix && swiftlint --strict,
doubling execution time.

Solution: Add --fail-on-unfixable flag that performs autocorrection as usual, then
re-lints to detect remaining violations. If serious violations remain, exits with code 2.
Reuses existing lintOrAnalyze() path, so --strict/--lenient work naturally with the
re-lint pass.

Why: The two-pass approach (fix then lint) reuses existing infrastructure with minimal code
changes. Configuration parsing is cached (O(1) on second pass), and ignoreCache: true
ensures stale cache entries from modified files are not used. This is architecturally the
simplest solution that correctly handles all edge cases.

Test:

  • swift build passes
  • LintOrAnalyzeOptionsTests passes (0 failures)
  • Manual e2e verification:
    • Mixed violations (fixable + unfixable) + --fail-on-unfixable → exit 2 → works
    • Same without flag → exit 0 → works
    • Only fixable violations + --fail-on-unfixable → exit 0 → works
    • --fail-on-unfixable without --fix → prints warning → works

Closes #6450

@SwiftLintBot
Copy link

SwiftLintBot commented Mar 14, 2026

1 Warning
⚠️ This PR may need tests.
19 Messages
📖 Building this branch resulted in a binary size of 27358.1 KiB vs 27357.74 KiB when built on main (0% larger).
📖 Linting Aerial with this PR took 0.81 s vs 0.81 s on main (0% slower).
📖 Linting Alamofire with this PR took 1.06 s vs 1.06 s on main (0% slower).
📖 Linting Brave with this PR took 7.21 s vs 7.22 s on main (0% faster).
📖 Linting DuckDuckGo with this PR took 26.66 s vs 26.66 s on main (0% slower).
📖 Linting Firefox with this PR took 11.95 s vs 12.01 s on main (0% faster).
📖 Linting Kickstarter with this PR took 8.24 s vs 8.28 s on main (0% faster).
📖 Linting Moya with this PR took 0.47 s vs 0.47 s on main (0% slower).
📖 Linting NetNewsWire with this PR took 2.54 s vs 2.53 s on main (0% slower).
📖 Linting Nimble with this PR took 0.68 s vs 0.72 s on main (5% faster).
📖 Linting PocketCasts with this PR took 7.68 s vs 7.71 s on main (0% faster).
📖 Linting Quick with this PR took 0.48 s vs 0.47 s on main (2% slower).
📖 Linting Realm with this PR took 2.98 s vs 3.02 s on main (1% faster).
📖 Linting Sourcery with this PR took 1.88 s vs 1.87 s on main (0% slower).
📖 Linting Swift with this PR took 4.68 s vs 4.68 s on main (0% slower).
📖 Linting SwiftLintPerformanceTests with this PR took 0.36 s vs 0.35 s on main (2% slower).
📖 Linting VLC with this PR took 1.21 s vs 1.19 s on main (1% slower).
📖 Linting Wire with this PR took 18.68 s vs 18.78 s on main (0% faster).
📖 Linting WordPress with this PR took 12.67 s vs 12.72 s on main (0% faster).

Generated by 🚫 Danger

Fixes prefer_self_in_static_references violations caught by
SwiftLint's integration tests.
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.

Add --fail-on-unfixable flag for single-pass fix + validation

3 participants