Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added lenient command line option #5801

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
)
}
}