Files
LibreMail/config/detekt/detekt.yml
T
mergify[bot] 677512760a Merge pull request #437 from JMR-dev/refactor-308-ui-nits
fix(ui): address below-cut UI/Compose review nits (#308)
2026-07-08 17:24:42 +00:00

112 lines
5.9 KiB
YAML

# Project overrides merged onto detekt's bundled defaults (buildUponDefaultConfig = true in
# app/build.gradle.kts). Only rules that need tuning for this project appear here.
#
# Guiding principle: Compose UI intentionally breaks several OOP-era metrics, and a few default
# thresholds are stricter than this project's chosen style. Those are relaxed here with a reason.
# Genuine smells (swallowed exceptions, an over-complex condition, a misnamed file) are fixed in
# the code, not silenced.
complexity:
LongMethod:
# Declarative @Composable functions are read top-to-bottom and are legitimately long.
ignoreAnnotated: ['Composable']
CyclomaticComplexMethod:
# Branchy layout code (when/if inside a UI tree) isn't algorithmic complexity.
ignoreAnnotated: ['Composable']
TooManyFunctions:
# Screen files group many small @Composable helpers next to their screen. The data layer
# (repositories, DAOs, mappers) and complex mailbox screen/ViewModel are intentionally
# operation-rich cohesive APIs; detekt's default of 11 is far too low for them. Files past
# ~40 functions still flag as genuinely bloated.
ignoreAnnotated: ['Composable']
allowedFunctionsPerFile: 40
allowedFunctionsPerClass: 40
allowedFunctionsPerInterface: 40
LargeClass:
# MailRepositoryImplTest is one cohesive single-SUT suite (a test per MailRepositoryImpl method
# plus folder-resolution / spam cases) already at detekt's LLOC boundary; the reader-path perf
# logging (issue #358) added its required android.util.Log mock + one breadcrumb test, tipping it
# over. Excluded rather than artificially split — same "operation-rich cohesive suite" rationale as
# the TooManyFunctions relaxation above.
excludes: ['**/data/repository/MailRepositoryImplTest.kt']
naming:
FunctionNaming:
# @Composable functions are PascalCase by Compose convention.
ignoreAnnotated: ['Composable']
style:
ForbiddenImport:
# Strangler guard for epic #324: production code must log through
# org.libremail.reporting.AppLog, which mirrors every line into the debug-report
# RingLogBuffer. A raw android.util.Log import writes to Logcat only and bypasses that
# buffer, so it never reaches a user-reviewed DebugReport. Excludes cover the ONE allowed
# wrapper (AppLog) plus the unit tests that import Log solely to mockkStatic/verify it —
# AppLog forwards to Log, a throwing stub under plain JVM unit tests, so those tests must
# mock it. They do not bypass the facade. Do NOT add production files here; migrate them to
# AppLog instead.
active: true
forbiddenImports:
- value: 'android.util.Log'
reason: >-
Log via org.libremail.reporting.AppLog so lines reach the debug-report RingLogBuffer;
raw android.util.Log bypasses it (epic #324).
excludes:
# The facade itself — the single sanctioned wrapper around android.util.Log.
- '**/reporting/AppLog.kt'
# Facade tests: mockkStatic(Log) to verify AppLog forwards to Logcat.
- '**/reporting/AppLogTest.kt'
- '**/reporting/AppLogUninstalledTest.kt'
- '**/restart/RestartActivityLoggingTest.kt'
# Unit tests that mockkStatic(Log::class) because the code under test logs via AppLog,
# which forwards to android.util.Log (a no-op throwing stub under plain JVM unit tests).
- '**/ui/lock/AppLockViewModelTest.kt'
- '**/ui/accountsetup/AccountSetupViewModelTest.kt'
- '**/data/sync/SyncWorkerTest.kt'
- '**/data/sync/MailSyncerTest.kt'
- '**/data/sync/MailBackfillerTest.kt'
- '**/data/sync/MailPrunerTest.kt'
- '**/data/sync/MailMaintenanceGateTest.kt'
- '**/data/sync/MailSyncConcurrencyTest.kt'
- '**/data/sync/PruneWorkerTest.kt'
- '**/data/sync/BackfillWorkerTest.kt'
# Reader-path perf logging (issue #358): the repository's openMessage and the reader ViewModel
# log via AppLog, so their unit tests mockkStatic(Log) too.
- '**/data/repository/MailRepositoryImplTest.kt'
# SignatureRepository.delete breadcrumbs a default-promotion via AppLog (issue #313), so its unit
# test mockkStatic(Log) — it does not bypass the facade.
- '**/data/settings/SignatureRepositoryTest.kt'
- '**/data/repository/MailRepositoryImplCoverageTest.kt'
# Account-add breadcrumb (issue #403): addImapAccount/addOutlookAccount log via AppLog, so this
# suite mockkStatic(Log) so the calls don't crash on the throwing JVM stub.
- '**/data/repository/AccountRepositoryImplTest.kt'
- '**/ui/reader/ReaderViewModelTest.kt'
- '**/ui/reader/ReaderViewModelActionsTest.kt'
# First-account onboarding breadcrumb (issue #308): onAccountAdded logs via AppLog, so this
# suite mockkStatic(Log) so the call doesn't crash on the throwing JVM stub.
- '**/ui/onboarding/OnboardingViewModelTest.kt'
MagicNumber:
# dp / sp / duration literals are idiomatic inline in Compose.
ignoreAnnotated: ['Composable']
ignorePropertyDeclaration: true
ignoreNamedArgument: true
ReturnCount:
# Allow guard-clause-style early returns; detekt's default of 2 is overly strict.
max: 4
LoopWithTooManyJumpStatements:
# Clear early-continue / early-return loops (e.g. MIME-part walking) read fine; default 1 is strict.
maxJumpCount: 3
ThrowsCount:
# Guard-clause throws don't count; allow a few more for functions validating several
# preconditions (e.g. the OAuth token exchange checks response, auth code, and email).
excludeGuardClauses: true
max: 3
exceptions:
TooGenericExceptionCaught:
# Background sync, the push service, and the IMAP client intentionally catch broadly at their
# boundaries to stay resilient to arbitrary mail-library/network failures; each catch is logged
# and handled (retry with backoff, or SMTP fallback). The SwallowedException rule stays active
# (exceptions are logged, not dropped).
active: false