Skip to content

Commit

Permalink
Added lenient command line option (#5801)
Browse files Browse the repository at this point in the history
  • Loading branch information
mildm8nnered authored Oct 30, 2024
1 parent f410ea5 commit 23d6a7c
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 7 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
argument `--use-script-input-file-lists`.
[BlueVirusX](https://github.com/BlueVirusX)

* Adds a `lenient` configuration file setting, equivalent to the `--lenient`
command line option.
[Martin Redington](https://github.com/mildm8nnered)
[#5801](https://github.com/realm/SwiftLint/issues/5801)

#### Bug Fixes

* Run command plugin in whole package if no targets are defined in the
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,9 @@ allow_zero_lintable_files: false
# If true, SwiftLint will treat all warnings as errors.
strict: false
# If true, SwiftLint will treat all errors as warnings.
lenient: false
# The path to a baseline file, which will be used to filter out detected violations.
baseline: Baseline.json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ extension Configuration {
cachePath: cachePath,
allowZeroLintableFiles: childConfiguration.allowZeroLintableFiles,
strict: childConfiguration.strict,
lenient: childConfiguration.lenient,
baseline: childConfiguration.baseline,
writeBaseline: childConfiguration.writeBaseline,
checkForUpdates: childConfiguration.checkForUpdates
Expand Down
2 changes: 2 additions & 0 deletions Source/SwiftLintCore/Extensions/Configuration+Parsing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extension Configuration {
case analyzerRules = "analyzer_rules"
case allowZeroLintableFiles = "allow_zero_lintable_files"
case strict = "strict"
case lenient = "lenient"
case baseline = "baseline"
case writeBaseline = "write_baseline"
case checkForUpdates = "check_for_updates"
Expand Down Expand Up @@ -103,6 +104,7 @@ extension Configuration {
pinnedVersion: dict[Key.swiftlintVersion.rawValue].map { ($0 as? String) ?? String(describing: $0) },
allowZeroLintableFiles: dict[Key.allowZeroLintableFiles.rawValue] as? Bool ?? false,
strict: dict[Key.strict.rawValue] as? Bool ?? false,
lenient: dict[Key.lenient.rawValue] as? Bool ?? false,
baseline: dict[Key.baseline.rawValue] as? String,
writeBaseline: dict[Key.writeBaseline.rawValue] as? String,
checkForUpdates: dict[Key.checkForUpdates.rawValue] as? Bool ?? false
Expand Down
11 changes: 11 additions & 0 deletions Source/SwiftLintCore/Models/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public struct Configuration {
/// Treat warnings as errors.
public let strict: Bool

/// Treat errors as warnings.
public let lenient: Bool

/// The path to read a baseline from.
public let baseline: String?

Expand Down Expand Up @@ -83,6 +86,7 @@ public struct Configuration {
cachePath: String?,
allowZeroLintableFiles: Bool,
strict: Bool,
lenient: Bool,
baseline: String?,
writeBaseline: String?,
checkForUpdates: Bool
Expand All @@ -97,6 +101,7 @@ public struct Configuration {
self.cachePath = cachePath
self.allowZeroLintableFiles = allowZeroLintableFiles
self.strict = strict
self.lenient = lenient
self.baseline = baseline
self.writeBaseline = writeBaseline
self.checkForUpdates = checkForUpdates
Expand All @@ -117,6 +122,7 @@ public struct Configuration {
cachePath = configuration.cachePath
allowZeroLintableFiles = configuration.allowZeroLintableFiles
strict = configuration.strict
lenient = configuration.lenient
baseline = configuration.baseline
writeBaseline = configuration.writeBaseline
checkForUpdates = configuration.checkForUpdates
Expand All @@ -143,6 +149,7 @@ public struct Configuration {
/// - parameter allowZeroLintableFiles: Allow SwiftLint to exit successfully when passed ignored or unlintable
/// files.
/// - parameter strict: Treat warnings as errors.
/// - parameter lenient: Treat errors as warnings.
/// - parameter baseline: The path to read a baseline from.
/// - parameter writeBaseline: The path to write a baseline to.
/// - parameter checkForUpdates: Check for updates to SwiftLint.
Expand All @@ -160,6 +167,7 @@ public struct Configuration {
pinnedVersion: String? = nil,
allowZeroLintableFiles: Bool = false,
strict: Bool = false,
lenient: Bool = false,
baseline: String? = nil,
writeBaseline: String? = nil,
checkForUpdates: Bool = false
Expand Down Expand Up @@ -189,6 +197,7 @@ public struct Configuration {
cachePath: cachePath,
allowZeroLintableFiles: allowZeroLintableFiles,
strict: strict,
lenient: lenient,
baseline: baseline,
writeBaseline: writeBaseline,
checkForUpdates: checkForUpdates
Expand Down Expand Up @@ -304,6 +313,7 @@ extension Configuration: Hashable {
hasher.combine(reporter)
hasher.combine(allowZeroLintableFiles)
hasher.combine(strict)
hasher.combine(lenient)
hasher.combine(baseline)
hasher.combine(writeBaseline)
hasher.combine(checkForUpdates)
Expand All @@ -325,6 +335,7 @@ extension Configuration: Hashable {
lhs.fileGraph == rhs.fileGraph &&
lhs.allowZeroLintableFiles == rhs.allowZeroLintableFiles &&
lhs.strict == rhs.strict &&
lhs.lenient == rhs.lenient &&
lhs.baseline == rhs.baseline &&
lhs.writeBaseline == rhs.writeBaseline &&
lhs.checkForUpdates == rhs.checkForUpdates &&
Expand Down
26 changes: 19 additions & 7 deletions Source/SwiftLintFramework/LintOrAnalyzeCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ package struct LintOrAnalyzeCommand {
currentViolations = applyLeniency(
options: options,
strict: builder.configuration.strict,
lenient: builder.configuration.lenient,
violations: violationsBeforeLeniency
)
visitorMutationQueue.sync {
Expand All @@ -179,6 +180,7 @@ package struct LintOrAnalyzeCommand {
currentViolations = applyLeniency(
options: options,
strict: builder.configuration.strict,
lenient: builder.configuration.lenient,
violations: linter.styleViolations(using: builder.storage)
)
}
Expand Down Expand Up @@ -273,23 +275,24 @@ package struct LintOrAnalyzeCommand {
private static func applyLeniency(
options: LintOrAnalyzeOptions,
strict: Bool,
lenient: Bool,
violations: [StyleViolation]
) -> [StyleViolation] {
let strict = (strict && !options.lenient) || options.strict
let leniency = options.leniency(strict: strict, lenient: lenient)

switch (options.lenient, strict) {
switch leniency {
case (false, false):
return violations

case (true, false):
case (false, true):
return violations.map {
if $0.severity == .error {
return $0.with(severity: .warning)
}
return $0
}

case (false, true):
case (true, false):
return violations.map {
if $0.severity == .warning {
return $0.with(severity: .error)
Expand All @@ -298,7 +301,7 @@ package struct LintOrAnalyzeCommand {
}

case (true, true):
queuedFatalError("Invalid command line options: 'lenient' and 'strict' are mutually exclusive.")
queuedFatalError("Invalid command line or config options: 'strict' and 'lenient' are mutually exclusive.")
}
}

Expand Down Expand Up @@ -394,8 +397,8 @@ private class LintOrAnalyzeResultBuilder {
}
}

private extension LintOrAnalyzeOptions {
func writeToOutput(_ string: String) {
extension LintOrAnalyzeOptions {
fileprivate func writeToOutput(_ string: String) {
guard let outFile = output else {
queuedPrint(string)
return
Expand All @@ -411,6 +414,15 @@ private extension LintOrAnalyzeOptions {
Issue.fileNotWritable(path: outFile).print()
}
}

typealias Leniency = (strict: Bool, lenient: Bool)

// Config file settings can be overridden by either `--strict` or `--lenient` command line options.
func leniency(strict configurationStrict: Bool, lenient configurationLenient: Bool) -> Leniency {
let strict = self.strict || (configurationStrict && !self.lenient)
let lenient = self.lenient || (configurationLenient && !self.strict)
return Leniency(strict: strict, lenient: lenient)
}
}

private actor CorrectionsBuilder {
Expand Down
6 changes: 6 additions & 0 deletions Tests/SwiftLintFrameworkTests/ConfigurationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ final class ConfigurationTests: SwiftLintTestCase {
XCTAssertEqual(reporterFrom(identifier: config.reporter).identifier, "xcode")
XCTAssertFalse(config.allowZeroLintableFiles)
XCTAssertFalse(config.strict)
XCTAssertFalse(config.lenient)
XCTAssertNil(config.baseline)
XCTAssertNil(config.writeBaseline)
XCTAssertFalse(config.checkForUpdates)
Expand Down Expand Up @@ -458,6 +459,11 @@ final class ConfigurationTests: SwiftLintTestCase {
XCTAssertTrue(configuration.strict)
}

func testLenient() throws {
let configuration = try Configuration(dict: ["lenient": true])
XCTAssertTrue(configuration.lenient)
}

func testBaseline() throws {
let baselinePath = "Baseline.json"
let configuration = try Configuration(dict: ["baseline": baselinePath])
Expand Down
72 changes: 72 additions & 0 deletions Tests/SwiftLintFrameworkTests/LintOrAnalyzeOptionsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
@testable import SwiftLintFramework
import XCTest

final class LintOrAnalyzeOptionsTests: XCTestCase {
private typealias Leniency = LintOrAnalyzeOptions.Leniency

func testLeniency() {
let parameters = [
Leniency(strict: false, lenient: false),
Leniency(strict: true, lenient: true),
Leniency(strict: true, lenient: false),
Leniency(strict: false, lenient: true),
]

for commandLine in parameters {
let options = LintOrAnalyzeOptions(leniency: commandLine)
for configuration in parameters {
let leniency = options.leniency(strict: configuration.strict, lenient: configuration.lenient)
if commandLine.strict {
// Command line takes precedence.
XCTAssertTrue(leniency.strict)
if !commandLine.lenient {
// `--strict` should disable configuration lenience.
XCTAssertFalse(leniency.lenient)
}
} else if commandLine.lenient {
// Command line takes precedence, and should override
// `strict` in the configuration.
XCTAssertTrue(leniency.lenient)
XCTAssertFalse(leniency.strict)
} else if configuration.strict {
XCTAssertTrue(leniency.strict)
} else if configuration.lenient {
XCTAssertTrue(leniency.lenient)
}
}
}
}
}

private extension LintOrAnalyzeOptions {
init(leniency: Leniency) {
self.init(mode: .lint,
paths: [],
useSTDIN: true,
configurationFiles: [],
strict: leniency.strict,
lenient: leniency.lenient,
forceExclude: false,
useExcludingByPrefix: false,
useScriptInputFiles: false,
useScriptInputFileLists: false,
benchmark: false,
reporter: nil,
baseline: nil,
writeBaseline: nil,
workingDirectory: nil,
quiet: false,
output: nil,
progress: false,
cachePath: nil,
ignoreCache: false,
enableAllRules: false,
onlyRule: [],
autocorrect: false,
format: false,
compilerLogPath: nil,
compileCommands: nil,
checkForUpdates: false
)
}
}

0 comments on commit 23d6a7c

Please sign in to comment.