From 178371b2fa272469148003ca1d6d63d7d50152c9 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 27 May 2023 13:31:33 +0100 Subject: [PATCH 01/54] started to add Configure command --- Source/swiftlint/Commands/Configure.swift | 13 +++++++++++++ Source/swiftlint/Commands/SwiftLint.swift | 1 + 2 files changed, 14 insertions(+) create mode 100644 Source/swiftlint/Commands/Configure.swift diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift new file mode 100644 index 0000000000..9ba74d3d9f --- /dev/null +++ b/Source/swiftlint/Commands/Configure.swift @@ -0,0 +1,13 @@ +import ArgumentParser +import SwiftLintFramework + +extension SwiftLint { + struct Configure: ParsableCommand { + static let configuration = CommandConfiguration(abstract: "Configure SwiftLint") + + func run() throws { + print("Hello") + ExitHelper.successfullyExit() + } + } +} diff --git a/Source/swiftlint/Commands/SwiftLint.swift b/Source/swiftlint/Commands/SwiftLint.swift index c0b0772533..c3963bb283 100644 --- a/Source/swiftlint/Commands/SwiftLint.swift +++ b/Source/swiftlint/Commands/SwiftLint.swift @@ -25,6 +25,7 @@ struct SwiftLint: AsyncParsableCommand { version: Version.value, subcommands: [ Analyze.self, + Configure.self, Docs.self, GenerateDocs.self, Lint.self, From f88016212ef9c78a8f954933fd3ce3ced2d59f0c Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 27 May 2023 18:54:44 +0100 Subject: [PATCH 02/54] More setup --- Source/swiftlint/Commands/Configure.swift | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 9ba74d3d9f..ce56e08fdb 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -1,13 +1,27 @@ import ArgumentParser import SwiftLintFramework +#if os(Linux) + import Glibc +#else + import Darwin.C +#endif extension SwiftLint { struct Configure: ParsableCommand { static let configuration = CommandConfiguration(abstract: "Configure SwiftLint") func run() throws { - print("Hello") + doYouWantToContinue("Welcome to SwiftLint! Do you want to continue? (Y/n)") ExitHelper.successfullyExit() } } } + +private func print(_ message: String, terminator: String = "\n") { + Swift.print(message, terminator: terminator) + fflush(stdout) +} + +private func doYouWantToContinue(_ message: String) { + print(message, terminator: " ") +} From 662c9f630e1f06769f6ec3fcc856ba19cca75c39 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 27 May 2023 19:08:23 +0100 Subject: [PATCH 03/54] Better prompting --- Source/swiftlint/Commands/Configure.swift | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index ce56e08fdb..1628c32de4 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -22,6 +22,17 @@ private func print(_ message: String, terminator: String = "\n") { fflush(stdout) } -private func doYouWantToContinue(_ message: String) { - print(message, terminator: " ") +private func doYouWantToContinue(_ message: String) -> Bool { + while true { + print(message, terminator: " ") + if let character = readLine() { + if character == "" || character.lowercased() == "y" { + return true + } else if character.lowercased() == "n" { + return false + } else { + print("Invalid Response") + } + } + } } From 65e5ffcb056b603bb578f64abba5a75696f8651a Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 27 May 2023 21:46:51 +0100 Subject: [PATCH 04/54] Kind of have bold working --- Source/swiftlint/Commands/Configure.swift | 61 ++++++++++++++++++----- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 1628c32de4..5f82cf6605 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -1,4 +1,5 @@ import ArgumentParser +import Foundation import SwiftLintFramework #if os(Linux) import Glibc @@ -10,10 +11,43 @@ extension SwiftLint { struct Configure: ParsableCommand { static let configuration = CommandConfiguration(abstract: "Configure SwiftLint") + @Flag(help: "Colorize output regardless of terminal settings.") + var colorizeOutput = false + @Flag(help: "Do not colorize output regardless of terminal settings.") + var noColorizeOutput = false + + private lazy var shouldColorizeOutput: Bool = { + terminalSupportsColor() && (!noColorizeOutput || colorizeOutput) + }() + func run() throws { doYouWantToContinue("Welcome to SwiftLint! Do you want to continue? (Y/n)") ExitHelper.successfullyExit() } + + private func doYouWantToContinue(_ message: String) { + if !askUser(message) { + ExitHelper.successfullyExit() + } + } + + private func askUser(_ message: String) -> Bool { + // let colorizeOutput = shouldColorizeOutput + let colorizedMessage = true ? message.boldify : message + while true { + print(colorizedMessage, terminator: " ") + if let character = readLine() { + if character == "" || character.lowercased() == "y" { + return true + } else if character.lowercased() == "n" { + return false + } else { + print("Invalid Response") + } + } + } + } + } } @@ -22,17 +56,20 @@ private func print(_ message: String, terminator: String = "\n") { fflush(stdout) } -private func doYouWantToContinue(_ message: String) -> Bool { - while true { - print(message, terminator: " ") - if let character = readLine() { - if character == "" || character.lowercased() == "y" { - return true - } else if character.lowercased() == "n" { - return false - } else { - print("Invalid Response") - } - } + + +private func terminalSupportsColor() -> Bool { + if + isatty(1) != 0, let term = ProcessInfo.processInfo.environment["TERM"], + term.contains("color"), term.contains("256") + { + return true + } + return false +} + +private extension String { + var boldify: String { + "\u{001B}[0;1m\(self)" } } From 1e55cf109a7244050c8f2ff1fab949d7e23d701c Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 27 May 2023 21:54:27 +0100 Subject: [PATCH 05/54] colorization --- Source/swiftlint/Commands/Configure.swift | 42 ++++++++++------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 5f82cf6605..01da47726f 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -12,13 +12,13 @@ extension SwiftLint { static let configuration = CommandConfiguration(abstract: "Configure SwiftLint") @Flag(help: "Colorize output regardless of terminal settings.") - var colorizeOutput = false + var colorize = false @Flag(help: "Do not colorize output regardless of terminal settings.") - var noColorizeOutput = false + var noColorize = false - private lazy var shouldColorizeOutput: Bool = { - terminalSupportsColor() && (!noColorizeOutput || colorizeOutput) - }() + private var shouldColorizeOutput: Bool { + terminalSupportsColor() && (!noColorize || colorize) + } func run() throws { doYouWantToContinue("Welcome to SwiftLint! Do you want to continue? (Y/n)") @@ -26,28 +26,26 @@ extension SwiftLint { } private func doYouWantToContinue(_ message: String) { - if !askUser(message) { + if !askUser(message, colorizeOutput: shouldColorizeOutput) { ExitHelper.successfullyExit() } } + } +} - private func askUser(_ message: String) -> Bool { - // let colorizeOutput = shouldColorizeOutput - let colorizedMessage = true ? message.boldify : message - while true { - print(colorizedMessage, terminator: " ") - if let character = readLine() { - if character == "" || character.lowercased() == "y" { - return true - } else if character.lowercased() == "n" { - return false - } else { - print("Invalid Response") - } - } +private func askUser(_ message: String, colorizeOutput: Bool) -> Bool { + let colorizedMessage = colorizeOutput ? message.boldify : message + while true { + print(colorizedMessage, terminator: " ") + if let character = readLine() { + if character == "" || character.lowercased() == "y" { + return true + } else if character.lowercased() == "n" { + return false + } else { + print("Invalid Response") } } - } } @@ -56,8 +54,6 @@ private func print(_ message: String, terminator: String = "\n") { fflush(stdout) } - - private func terminalSupportsColor() -> Bool { if isatty(1) != 0, let term = ProcessInfo.processInfo.environment["TERM"], From 3ab75b0015295593837df4ef46d0fa095616470c Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 27 May 2023 23:57:15 +0100 Subject: [PATCH 06/54] Searching for more configurations --- Source/swiftlint/Commands/Configure.swift | 34 ++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 01da47726f..6497228dce 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -22,9 +22,28 @@ extension SwiftLint { func run() throws { doYouWantToContinue("Welcome to SwiftLint! Do you want to continue? (Y/n)") + checkForExistingConfiguration() + checkForExistingChildConfigurations() ExitHelper.successfullyExit() } + private func checkForExistingConfiguration() { + print("Checking for existing .swiftlint.yml configuration file.") + if FileManager.default.fileExists(atPath: ".swiftlint.yml") { + doYouWantToContinue("Found an existing .swiftlint.yml configuration file - do you want to continue? (Y/n)") + } + } + + private func checkForExistingChildConfigurations() { + print("Checking for any other .swiftlint.yml configuration files.") + let files = FileManager.default.filesMatching(".swiftlint.yml").filter { $0 != ".swiftlint.yml" } + if files.isNotEmpty { + print("Found existing child configurations:\n") + files.forEach { print($0) } + doYouWantToContinue("\nDo you want to continue? (Y/n)") + } + } + private func doYouWantToContinue(_ message: String) { if !askUser(message, colorizeOutput: shouldColorizeOutput) { ExitHelper.successfullyExit() @@ -66,6 +85,19 @@ private func terminalSupportsColor() -> Bool { private extension String { var boldify: String { - "\u{001B}[0;1m\(self)" + "\u{001B}[0;1m\(self)\u{001B}[0;0m" + } +} + +private extension FileManager { + func filesMatching(_ fileName: String) -> [String] { + var results: [String] = [] + let directoryEnumerator = enumerator(atPath: currentDirectoryPath) + while let file = directoryEnumerator?.nextObject() as? String { + if file.hasSuffix(".swiftlint.yml") { + results.append(file) + } + } + return results } } From 34725dd3c833ec20bef381b9b67b5866d2fb996d Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 28 May 2023 01:11:20 +0100 Subject: [PATCH 07/54] Directory scanning --- Source/swiftlint/Commands/Configure.swift | 53 +++++++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 6497228dce..64d3bc9b74 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -21,16 +21,17 @@ extension SwiftLint { } func run() throws { - doYouWantToContinue("Welcome to SwiftLint! Do you want to continue? (Y/n)") + doYouWantToContinue("Welcome to SwiftLint! Do you want to continue?") checkForExistingConfiguration() checkForExistingChildConfigurations() + let topLevelDirectories = checkForSwiftFiles() ExitHelper.successfullyExit() } private func checkForExistingConfiguration() { print("Checking for existing .swiftlint.yml configuration file.") if FileManager.default.fileExists(atPath: ".swiftlint.yml") { - doYouWantToContinue("Found an existing .swiftlint.yml configuration file - do you want to continue? (Y/n)") + doYouWantToContinue("Found an existing .swiftlint.yml configuration file - do you want to continue?") } } @@ -40,12 +41,43 @@ extension SwiftLint { if files.isNotEmpty { print("Found existing child configurations:\n") files.forEach { print($0) } + doYouWantToContinue("\nDo you want to continue?") + } + } + + private func checkForSwiftFiles() -> [String] { + print("Checking for .swift files.") + let topLevelDirectories = FileManager.default.filesMatching(".swift") + .compactMap { $0.firstPathComponent } + .unique() + .filter { !$0.isSwiftFile() } + if topLevelDirectories.isNotEmpty { + print("Found .swift files in the following top level directories:\n") + topLevelDirectories.forEach { print($0) } + if askUser("\nDo you want SwiftLint to scan all of those directories?") { + return topLevelDirectories + } else { + var selectedDirectories: [String] = [] + for topLevelDirectory in topLevelDirectories { + if askUser("Do you want SwiftLint to scan the \(topLevelDirectory) directory?") { + selectedDirectories.append(topLevelDirectory) + } + } + return selectedDirectories + } + } else { + print("No .swift files found.") doYouWantToContinue("\nDo you want to continue? (Y/n)") + return [] } } + private func askUser(_ message: String) -> Bool { + swiftlint.askUser(message, colorizeOutput: shouldColorizeOutput) + } + private func doYouWantToContinue(_ message: String) { - if !askUser(message, colorizeOutput: shouldColorizeOutput) { + if !askUser(message) { ExitHelper.successfullyExit() } } @@ -53,6 +85,7 @@ extension SwiftLint { } private func askUser(_ message: String, colorizeOutput: Bool) -> Bool { + let message = "\(message) (Y/n)" let colorizedMessage = colorizeOutput ? message.boldify : message while true { print(colorizedMessage, terminator: " ") @@ -87,6 +120,11 @@ private extension String { var boldify: String { "\u{001B}[0;1m\(self)\u{001B}[0;0m" } + + var firstPathComponent: String? { + let components = components(separatedBy: "/") + return components.first + } } private extension FileManager { @@ -94,10 +132,17 @@ private extension FileManager { var results: [String] = [] let directoryEnumerator = enumerator(atPath: currentDirectoryPath) while let file = directoryEnumerator?.nextObject() as? String { - if file.hasSuffix(".swiftlint.yml") { + if file.hasSuffix(fileName) { results.append(file) } } return results } } + +private extension Sequence where Iterator.Element: Hashable { + func unique() -> [Iterator.Element] { + var seen: Set = [] + return filter { seen.insert($0).inserted } + } +} From e40229d1c76cb3aeb0798077f2065bb6efcb41ba Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 28 May 2023 01:12:58 +0100 Subject: [PATCH 08/54] refactor --- Source/swiftlint/Commands/Configure.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 64d3bc9b74..d3158791b3 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -37,7 +37,7 @@ extension SwiftLint { private func checkForExistingChildConfigurations() { print("Checking for any other .swiftlint.yml configuration files.") - let files = FileManager.default.filesMatching(".swiftlint.yml").filter { $0 != ".swiftlint.yml" } + let files = FileManager.default.filesWithSuffix(".swiftlint.yml").filter { $0 != ".swiftlint.yml" } if files.isNotEmpty { print("Found existing child configurations:\n") files.forEach { print($0) } @@ -47,7 +47,7 @@ extension SwiftLint { private func checkForSwiftFiles() -> [String] { print("Checking for .swift files.") - let topLevelDirectories = FileManager.default.filesMatching(".swift") + let topLevelDirectories = FileManager.default.filesWithSuffix(".swift") .compactMap { $0.firstPathComponent } .unique() .filter { !$0.isSwiftFile() } @@ -128,7 +128,7 @@ private extension String { } private extension FileManager { - func filesMatching(_ fileName: String) -> [String] { + func filesWithSuffix(_ fileName: String) -> [String] { var results: [String] = [] let directoryEnumerator = enumerator(atPath: currentDirectoryPath) while let file = directoryEnumerator?.nextObject() as? String { From cb899e17c1bed25d1a16f63ac925fa87398a2ff8 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 28 May 2023 01:48:55 +0100 Subject: [PATCH 09/54] About to run --- Source/swiftlint/Commands/Configure.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index d3158791b3..55b5967e0c 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -25,6 +25,7 @@ extension SwiftLint { checkForExistingConfiguration() checkForExistingChildConfigurations() let topLevelDirectories = checkForSwiftFiles() + try checkForExistingViolations(topLevelDirectories) ExitHelper.successfullyExit() } @@ -72,6 +73,19 @@ extension SwiftLint { } } + private func checkForExistingViolations(_ topLevelDirectories: [String]) throws { + let configuration = try writeTemporaryConfigurationFile(topLevelDirectories) + } + + private func writeTemporaryConfigurationFile(_ topLevelDirectories: [String]) throws -> String { + var configuration = "included:\n" + topLevelDirectories.forEach { configuration += " - \($0)" } + configuration += "opt_in_rules:\n - all\n" + let filename = ".\(UUID().uuidString).swiftlint.yml" + try configuration.write(toFile: filename, atomically: true, encoding: .utf8) + return filename + } + private func askUser(_ message: String) -> Bool { swiftlint.askUser(message, colorizeOutput: shouldColorizeOutput) } From d2ede5032e2ef1b5d6ff79ea812bef6614bd0677 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 28 May 2023 11:04:17 +0100 Subject: [PATCH 10/54] Now running the linter --- .../LintOrAnalyzeCommand.swift | 6 ++++ Source/swiftlint/Commands/Configure.swift | 35 ++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift index 3f2bcdfbcc..7beeb3b169 100644 --- a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift +++ b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift @@ -139,6 +139,12 @@ package struct LintOrAnalyzeCommand { } } + static func lintOrAnalyze(_ options: LintOrAnalyzeOptions) async throws -> [StyleViolation] { + let builder = LintOrAnalyzeResultBuilder(options) + _ = try await collectViolations(builder: builder) + return builder.violations + } + private static func lintOrAnalyze(_ options: LintOrAnalyzeOptions) async throws { let builder = LintOrAnalyzeResultBuilder(options) let files = try await collectViolations(builder: builder) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 55b5967e0c..d65565afff 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -8,7 +8,7 @@ import SwiftLintFramework #endif extension SwiftLint { - struct Configure: ParsableCommand { + struct Configure: AsyncParsableCommand { static let configuration = CommandConfiguration(abstract: "Configure SwiftLint") @Flag(help: "Colorize output regardless of terminal settings.") @@ -20,12 +20,12 @@ extension SwiftLint { terminalSupportsColor() && (!noColorize || colorize) } - func run() throws { + func run() async throws { doYouWantToContinue("Welcome to SwiftLint! Do you want to continue?") checkForExistingConfiguration() checkForExistingChildConfigurations() let topLevelDirectories = checkForSwiftFiles() - try checkForExistingViolations(topLevelDirectories) + try await checkForExistingViolations(topLevelDirectories) ExitHelper.successfullyExit() } @@ -73,8 +73,35 @@ extension SwiftLint { } } - private func checkForExistingViolations(_ topLevelDirectories: [String]) throws { + private func checkForExistingViolations(_ topLevelDirectories: [String]) async throws { let configuration = try writeTemporaryConfigurationFile(topLevelDirectories) + + let options = LintOrAnalyzeOptions( + mode: .lint, + paths: [""], + useSTDIN: false, + configurationFiles: [configuration], + strict: false, + lenient: true, + forceExclude: false, + useExcludingByPrefix: false, + useScriptInputFiles: false, + benchmark: false, + reporter: "summary", + quiet: false, + output: nil, + progress: true, + cachePath: nil, + ignoreCache: false, + enableAllRules: true, + autocorrect: false, + format: false, + compilerLogPath: nil, + compileCommands: nil, + inProcessSourcekit: false + ) + + _ = try await LintOrAnalyzeCommand.lintOrAnalyze(options) } private func writeTemporaryConfigurationFile(_ topLevelDirectories: [String]) throws -> String { From f64f932f06ca740ec51eeb45e2f76fcf0265cf23 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 28 May 2023 13:14:54 +0100 Subject: [PATCH 11/54] Now running SwiftLint --- .../LintOrAnalyzeCommand.swift | 4 ++++ Source/swiftlint/Commands/Configure.swift | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift index 7beeb3b169..e5afd34613 100644 --- a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift +++ b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift @@ -142,6 +142,10 @@ package struct LintOrAnalyzeCommand { static func lintOrAnalyze(_ options: LintOrAnalyzeOptions) async throws -> [StyleViolation] { let builder = LintOrAnalyzeResultBuilder(options) _ = try await collectViolations(builder: builder) + let report = builder.reporter.generateReport(builder.violations) + if !report.isEmpty { + queuedPrint(report) + } return builder.violations } diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index d65565afff..56e5ef50e3 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -25,7 +25,8 @@ extension SwiftLint { checkForExistingConfiguration() checkForExistingChildConfigurations() let topLevelDirectories = checkForSwiftFiles() - try await checkForExistingViolations(topLevelDirectories) + let rulesToDisable = try await checkForExistingViolations(topLevelDirectories) + print("rulesToDisable = \(rulesToDisable)") ExitHelper.successfullyExit() } @@ -73,8 +74,12 @@ extension SwiftLint { } } - private func checkForExistingViolations(_ topLevelDirectories: [String]) async throws { + private func checkForExistingViolations(_ topLevelDirectories: [String]) async throws -> [String] { + print("Checking for violations.") let configuration = try writeTemporaryConfigurationFile(topLevelDirectories) + defer { + try? FileManager.default.removeItem(atPath: configuration) + } let options = LintOrAnalyzeOptions( mode: .lint, @@ -101,12 +106,18 @@ extension SwiftLint { inProcessSourcekit: false ) - _ = try await LintOrAnalyzeCommand.lintOrAnalyze(options) + let violations = try await LintOrAnalyzeCommand.lintOrAnalyze(options) + if violations.isNotEmpty { + if askUser("\nDo you want to disable all of the SwiftLint rules with existing violations?") { + return violations.map { $0.ruleIdentifier }.unique() + } + } + return [] } private func writeTemporaryConfigurationFile(_ topLevelDirectories: [String]) throws -> String { var configuration = "included:\n" - topLevelDirectories.forEach { configuration += " - \($0)" } + topLevelDirectories.forEach { configuration += " - \($0)\n" } configuration += "opt_in_rules:\n - all\n" let filename = ".\(UUID().uuidString).swiftlint.yml" try configuration.write(toFile: filename, atomically: true, encoding: .utf8) From 9c2a41b1de3288da9a195004d24f88b3dbc5e231 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 28 May 2023 21:38:32 +0100 Subject: [PATCH 12/54] rule disablement --- Source/swiftlint/Commands/Configure.swift | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 56e5ef50e3..cefed68ced 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -25,7 +25,7 @@ extension SwiftLint { checkForExistingConfiguration() checkForExistingChildConfigurations() let topLevelDirectories = checkForSwiftFiles() - let rulesToDisable = try await checkForExistingViolations(topLevelDirectories) + let rulesToDisable = try await rulesToDisable(topLevelDirectories) print("rulesToDisable = \(rulesToDisable)") ExitHelper.successfullyExit() } @@ -74,7 +74,8 @@ extension SwiftLint { } } - private func checkForExistingViolations(_ topLevelDirectories: [String]) async throws -> [String] { + private func rulesToDisable(_ topLevelDirectories: [String]) async throws -> [String] { + var ruleIdentifiersToDisable: [String] = [] print("Checking for violations.") let configuration = try writeTemporaryConfigurationFile(topLevelDirectories) defer { @@ -109,10 +110,17 @@ extension SwiftLint { let violations = try await LintOrAnalyzeCommand.lintOrAnalyze(options) if violations.isNotEmpty { if askUser("\nDo you want to disable all of the SwiftLint rules with existing violations?") { - return violations.map { $0.ruleIdentifier }.unique() + let dictionary = Dictionary(grouping: violations) { $0.ruleIdentifier } + ruleIdentifiersToDisable = dictionary.keys.sorted { + if dictionary[$0]!.count != dictionary[$1]!.count { + return dictionary[$0]!.count > dictionary[$1]!.count + } else { + return $0 > $1 + } + } } } - return [] + return ruleIdentifiersToDisable } private func writeTemporaryConfigurationFile(_ topLevelDirectories: [String]) throws -> String { From 6a4b49a9c2a3c66fd20b4233ddc4da655c8cdb98 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 28 May 2023 21:52:27 +0100 Subject: [PATCH 13/54] Implemented auto --- Source/swiftlint/Commands/Configure.swift | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index cefed68ced..179cae977e 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -12,12 +12,14 @@ extension SwiftLint { static let configuration = CommandConfiguration(abstract: "Configure SwiftLint") @Flag(help: "Colorize output regardless of terminal settings.") - var colorize = false + var color = false @Flag(help: "Do not colorize output regardless of terminal settings.") - var noColorize = false + var noColor = false + @Flag(help: "Complete setup automatically.") + var auto = false private var shouldColorizeOutput: Bool { - terminalSupportsColor() && (!noColorize || colorize) + terminalSupportsColor() && (!noColor || color) } func run() async throws { @@ -133,7 +135,7 @@ extension SwiftLint { } private func askUser(_ message: String) -> Bool { - swiftlint.askUser(message, colorizeOutput: shouldColorizeOutput) + swiftlint.askUser(message, colorizeOutput: shouldColorizeOutput, auto: auto) } private func doYouWantToContinue(_ message: String) { @@ -144,11 +146,14 @@ extension SwiftLint { } } -private func askUser(_ message: String, colorizeOutput: Bool) -> Bool { +private func askUser(_ message: String, colorizeOutput: Bool, auto: Bool) -> Bool { let message = "\(message) (Y/n)" let colorizedMessage = colorizeOutput ? message.boldify : message while true { - print(colorizedMessage, terminator: " ") + print(colorizedMessage, terminator: auto ? "\n" : " ") + if auto { + return true + } if let character = readLine() { if character == "" || character.lowercased() == "y" { return true From 189be595fc142e41ee5d62994279db1b72edd41b Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 29 May 2023 01:23:45 +0100 Subject: [PATCH 14/54] More tweaks --- Source/swiftlint/Commands/Configure.swift | 60 ++++++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 179cae977e..1108030d80 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -17,6 +17,8 @@ extension SwiftLint { var noColor = false @Flag(help: "Complete setup automatically.") var auto = false + @Flag(help: "In automatic mode, overwrite any existing configuration.") + var overwrite = false private var shouldColorizeOutput: Bool { terminalSupportsColor() && (!noColor || color) @@ -28,20 +30,24 @@ extension SwiftLint { checkForExistingChildConfigurations() let topLevelDirectories = checkForSwiftFiles() let rulesToDisable = try await rulesToDisable(topLevelDirectories) - print("rulesToDisable = \(rulesToDisable)") + try writeConfiguration(topLevelDirectories, rulesToDisable) ExitHelper.successfullyExit() } private func checkForExistingConfiguration() { - print("Checking for existing .swiftlint.yml configuration file.") - if FileManager.default.fileExists(atPath: ".swiftlint.yml") { - doYouWantToContinue("Found an existing .swiftlint.yml configuration file - do you want to continue?") + print("Checking for existing \(Configuration.defaultFileName) configuration file.") + if hasExistingConfiguration() { + doYouWantToContinue("Found an existing \(Configuration.defaultFileName) configuration file - do you want to continue?") } } + private func hasExistingConfiguration() -> Bool { + FileManager.default.fileExists(atPath: \(Configuration.defaultFileName)) + } + private func checkForExistingChildConfigurations() { - print("Checking for any other .swiftlint.yml configuration files.") - let files = FileManager.default.filesWithSuffix(".swiftlint.yml").filter { $0 != ".swiftlint.yml" } + print("Checking for any other \(Configuration.defaultFileName) configuration files.") + let files = FileManager.default.filesWithSuffix(\(Configuration.defaultFileName)).filter { $0 != \(Configuration.defaultFileName) } if files.isNotEmpty { print("Found existing child configurations:\n") files.forEach { print($0) } @@ -125,11 +131,49 @@ extension SwiftLint { return ruleIdentifiersToDisable } - private func writeTemporaryConfigurationFile(_ topLevelDirectories: [String]) throws -> String { + private func writeConfiguration(_ topLevelDirectories: [String], _ rulesToDisable: [String]) throws -> Bool { + var configuration = configuration(forTopLevelDirectories: topLevelDirectories) + configuration += "disabled_rules:\n" + rulesToDisable.forEach { configuration += " - \($0)\n" } + print("Proposed configuration\n\n") + print(configuration) + if hasExistingConfiguration() { + if auto && overwrite { + print("Overwriting existing configuration.") + try writeConfiguration(configuration) + return true + } else { + print("Found an existing configuration.") + if !askUser("Do you want to exit without overwriting the existing configuration?") { + try writeConfiguration(configuration) + return true + } + } + } else { + if askUser("Do you want to save the configuration?") { + try writeConfiguration(configuration) + return true + } + } + + return false + } + + private func writeConfiguration(_ configuration: String) throws { + print("Saving configuration to \(Configuration.defaultFileName)") + try configuration.write(toFile: Configuration.defaultFileName, atomically: true, encoding: .utf8) + } + + private func configuration(forTopLevelDirectories topLevelDirectories: [String]) -> String { var configuration = "included:\n" topLevelDirectories.forEach { configuration += " - \($0)\n" } configuration += "opt_in_rules:\n - all\n" - let filename = ".\(UUID().uuidString).swiftlint.yml" + return configuration + } + + private func writeTemporaryConfigurationFile(_ topLevelDirectories: [String]) throws -> String { + var configuration = configuration(forTopLevelDirectories: topLevelDirectories) + let filename = ".\(UUID().uuidString)\(Configuration.defaultFileName)" try configuration.write(toFile: filename, atomically: true, encoding: .utf8) return filename } From 1cf5e71e3bd9b1e0aa612bb8db819dbbb637d73e Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 29 May 2023 02:36:07 +0100 Subject: [PATCH 15/54] Tidyup --- Source/swiftlint/Commands/Configure.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 1108030d80..73f31992f8 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -30,24 +30,24 @@ extension SwiftLint { checkForExistingChildConfigurations() let topLevelDirectories = checkForSwiftFiles() let rulesToDisable = try await rulesToDisable(topLevelDirectories) - try writeConfiguration(topLevelDirectories, rulesToDisable) + _ = try writeConfiguration(topLevelDirectories, rulesToDisable) ExitHelper.successfullyExit() } private func checkForExistingConfiguration() { print("Checking for existing \(Configuration.defaultFileName) configuration file.") if hasExistingConfiguration() { - doYouWantToContinue("Found an existing \(Configuration.defaultFileName) configuration file - do you want to continue?") + doYouWantToContinue("Found an existing \(Configuration.defaultFileName) configuration file - Do you want to continue?") } } private func hasExistingConfiguration() -> Bool { - FileManager.default.fileExists(atPath: \(Configuration.defaultFileName)) + FileManager.default.fileExists(atPath: Configuration.defaultFileName) } private func checkForExistingChildConfigurations() { print("Checking for any other \(Configuration.defaultFileName) configuration files.") - let files = FileManager.default.filesWithSuffix(\(Configuration.defaultFileName)).filter { $0 != \(Configuration.defaultFileName) } + let files = FileManager.default.filesWithSuffix(Configuration.defaultFileName).filter { $0 != Configuration.defaultFileName } if files.isNotEmpty { print("Found existing child configurations:\n") files.forEach { print($0) } From d62083c41dfb8725081ab05d53803f4230e32d65 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 29 May 2023 13:26:57 +0100 Subject: [PATCH 16/54] Tidyup --- Source/swiftlint/Commands/Configure.swift | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 73f31992f8..78d09b05f1 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -59,7 +59,7 @@ extension SwiftLint { print("Checking for .swift files.") let topLevelDirectories = FileManager.default.filesWithSuffix(".swift") .compactMap { $0.firstPathComponent } - .unique() + .unique .filter { !$0.isSwiftFile() } if topLevelDirectories.isNotEmpty { print("Found .swift files in the following top level directories:\n") @@ -135,7 +135,7 @@ extension SwiftLint { var configuration = configuration(forTopLevelDirectories: topLevelDirectories) configuration += "disabled_rules:\n" rulesToDisable.forEach { configuration += " - \($0)\n" } - print("Proposed configuration\n\n") + print("Proposed configuration\n") print(configuration) if hasExistingConfiguration() { if auto && overwrite { @@ -172,7 +172,7 @@ extension SwiftLint { } private func writeTemporaryConfigurationFile(_ topLevelDirectories: [String]) throws -> String { - var configuration = configuration(forTopLevelDirectories: topLevelDirectories) + let configuration = configuration(forTopLevelDirectories: topLevelDirectories) let filename = ".\(UUID().uuidString)\(Configuration.defaultFileName)" try configuration.write(toFile: filename, atomically: true, encoding: .utf8) return filename @@ -229,10 +229,8 @@ private extension String { var boldify: String { "\u{001B}[0;1m\(self)\u{001B}[0;0m" } - var firstPathComponent: String? { - let components = components(separatedBy: "/") - return components.first + components(separatedBy: "/").first } } @@ -248,10 +246,3 @@ private extension FileManager { return results } } - -private extension Sequence where Iterator.Element: Hashable { - func unique() -> [Iterator.Element] { - var seen: Set = [] - return filter { seen.insert($0).inserted } - } -} From ad7b319dcf06c17ef06973f83574c9585037ff1e Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 29 May 2023 13:40:46 +0100 Subject: [PATCH 17/54] We now write the temporary file to a temporary directory --- Source/swiftlint/Commands/Configure.swift | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 78d09b05f1..736e41b1ba 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -1,4 +1,5 @@ import ArgumentParser +import ArgumentParser import Foundation import SwiftLintFramework #if os(Linux) @@ -145,6 +146,7 @@ extension SwiftLint { } else { print("Found an existing configuration.") if !askUser("Do you want to exit without overwriting the existing configuration?") { + doYouWantToContinue("Overwrite the existing configuration?") try writeConfiguration(configuration) return true } @@ -164,18 +166,27 @@ extension SwiftLint { try configuration.write(toFile: Configuration.defaultFileName, atomically: true, encoding: .utf8) } - private func configuration(forTopLevelDirectories topLevelDirectories: [String]) -> String { + private func configuration(forTopLevelDirectories topLevelDirectories: [String], path: String? = nil) -> String { var configuration = "included:\n" - topLevelDirectories.forEach { configuration += " - \($0)\n" } + topLevelDirectories.forEach { + let absolutePath: String + if let path = path { + absolutePath = path.bridge().appendingPathComponent($0) + } else { + absolutePath = $0 + } + configuration += " - \(absolutePath)\n" + } configuration += "opt_in_rules:\n - all\n" return configuration } private func writeTemporaryConfigurationFile(_ topLevelDirectories: [String]) throws -> String { - let configuration = configuration(forTopLevelDirectories: topLevelDirectories) + let configuration = configuration(forTopLevelDirectories: topLevelDirectories, path: FileManager.default.currentDirectoryPath) let filename = ".\(UUID().uuidString)\(Configuration.defaultFileName)" - try configuration.write(toFile: filename, atomically: true, encoding: .utf8) - return filename + let filePath = FileManager.default.temporaryDirectory.path.bridge().appendingPathComponent(filename) + try configuration.write(toFile: filePath, atomically: true, encoding: .utf8) + return filePath } private func askUser(_ message: String) -> Bool { From 6434d8f8e5b8855ac252deb8e44d61f8e22da5e6 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 29 May 2023 14:12:46 +0100 Subject: [PATCH 18/54] Added deprecated rule support --- Source/swiftlint/Commands/Configure.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 736e41b1ba..a232e2acd8 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -129,6 +129,13 @@ extension SwiftLint { } } } + + let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers).subtracting(ruleIdentifiersToDisable) + if deprecatedRuleIdentifiers.isNotEmpty { + if askUser("\nDo you want to disable any deprecated rules?") { + ruleIdentifiersToDisable.append(contentsOf: deprecatedRuleIdentifiers.sorted()) + } + } return ruleIdentifiersToDisable } @@ -257,3 +264,11 @@ private extension FileManager { return results } } + +private extension RuleRegistry { + var deprecatedRuleIdentifiers: [String] { + RuleRegistry.shared.list.list.compactMap { ruleID, ruleType in + ruleType is DeprecatedRule.Type ? ruleID : nil + } + } +} From 26c2adb93157c216275c81635f7bdf5e499f6f18 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 29 May 2023 14:20:02 +0100 Subject: [PATCH 19/54] Better writing --- Source/swiftlint/Commands/Configure.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index a232e2acd8..0cc40cb034 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -153,9 +153,10 @@ extension SwiftLint { } else { print("Found an existing configuration.") if !askUser("Do you want to exit without overwriting the existing configuration?") { - doYouWantToContinue("Overwrite the existing configuration?") - try writeConfiguration(configuration) - return true + if askUser("Do you want to overwrite the existing configuration?") { + try writeConfiguration(configuration) + return true + } } } } else { From b8ccd0c8cce60ce84094433b3cfaec4f4e099b80 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 29 May 2023 14:23:09 +0100 Subject: [PATCH 20/54] Added start over support --- Source/swiftlint/Commands/Configure.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 0cc40cb034..785d405caa 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -26,13 +26,21 @@ extension SwiftLint { } func run() async throws { + while try await configure() == false, auto == false { + if askUser("Do you want to start over?") == false { + break + } + } + ExitHelper.successfullyExit() + } + + func configure() async throws -> Bool { doYouWantToContinue("Welcome to SwiftLint! Do you want to continue?") checkForExistingConfiguration() checkForExistingChildConfigurations() let topLevelDirectories = checkForSwiftFiles() let rulesToDisable = try await rulesToDisable(topLevelDirectories) - _ = try writeConfiguration(topLevelDirectories, rulesToDisable) - ExitHelper.successfullyExit() + return try writeConfiguration(topLevelDirectories, rulesToDisable) } private func checkForExistingConfiguration() { From 22df8053fdbcb37689ae512507a6b81d62a309b5 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 29 May 2023 14:50:05 +0100 Subject: [PATCH 21/54] Added support for analyzer rules --- Source/swiftlint/Commands/Configure.swift | 31 ++++++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 785d405caa..081b3d0cdd 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -39,8 +39,9 @@ extension SwiftLint { checkForExistingConfiguration() checkForExistingChildConfigurations() let topLevelDirectories = checkForSwiftFiles() - let rulesToDisable = try await rulesToDisable(topLevelDirectories) - return try writeConfiguration(topLevelDirectories, rulesToDisable) + let rulesIdentifiersToDisable = try await rulesToDisable(topLevelDirectories) + let analyzerRuleIdentifiers = analyzerRulesToEnable() + return try writeConfiguration(topLevelDirectories, rulesIdentifiersToDisable, analyzerRuleIdentifiers) } private func checkForExistingConfiguration() { @@ -147,10 +148,27 @@ extension SwiftLint { return ruleIdentifiersToDisable } - private func writeConfiguration(_ topLevelDirectories: [String], _ rulesToDisable: [String]) throws -> Bool { + private func analyzerRulesToEnable() -> [String] { + let analyzerRuleIdentifiers = RuleRegistry.shared.analyzerRuleIdentifiers.sorted() + if askUser("\nDo you want to enable all (\(analyzerRuleIdentifiers.count)) of the analyzer rules?") { +return analyzerRuleIdentifiers + } else { + return [] + } + } + + private func writeConfiguration( + _ topLevelDirectories: [String], + _ ruleIdentifiersToDisable: [String], + _ analyzerRuleIdentifiers: [String] + ) throws -> Bool { var configuration = configuration(forTopLevelDirectories: topLevelDirectories) configuration += "disabled_rules:\n" - rulesToDisable.forEach { configuration += " - \($0)\n" } + ruleIdentifiersToDisable.forEach { configuration += " - \($0)\n" } + if analyzerRuleIdentifiers.isNotEmpty { + configuration += "analyzer_rules:\n" + analyzerRuleIdentifiers.forEach { configuration += " - \($0)\n" } + } print("Proposed configuration\n") print(configuration) if hasExistingConfiguration() { @@ -280,4 +298,9 @@ private extension RuleRegistry { ruleType is DeprecatedRule.Type ? ruleID : nil } } + var analyzerRuleIdentifiers: [String] { + RuleRegistry.shared.list.list.compactMap { ruleID, ruleType in + ruleType is AnalyzerRule.Type ? ruleID : nil + } + } } From aede947ac1fab569af1a76cae16fe118f792234b Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Tue, 30 May 2023 02:39:42 +0100 Subject: [PATCH 22/54] A few tweaks --- Source/swiftlint/Commands/Configure.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 081b3d0cdd..73d0036765 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -94,7 +94,7 @@ extension SwiftLint { private func rulesToDisable(_ topLevelDirectories: [String]) async throws -> [String] { var ruleIdentifiersToDisable: [String] = [] - print("Checking for violations.") + print("Checking for violations. This may take some time.") let configuration = try writeTemporaryConfigurationFile(topLevelDirectories) defer { try? FileManager.default.removeItem(atPath: configuration) @@ -171,6 +171,9 @@ return analyzerRuleIdentifiers } print("Proposed configuration\n") print(configuration) + if askUser("Does that look good?") == false { + return false + } if hasExistingConfiguration() { if auto && overwrite { print("Overwriting existing configuration.") From dbd903bcf9847307cc3a298363b7e7ced2187f40 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Tue, 30 May 2023 02:48:06 +0100 Subject: [PATCH 23/54] Support zero lintable files --- Source/swiftlint/Commands/Configure.swift | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 73d0036765..7efa80cd69 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -39,9 +39,14 @@ extension SwiftLint { checkForExistingConfiguration() checkForExistingChildConfigurations() let topLevelDirectories = checkForSwiftFiles() + let allowZeroLintableFiles = topLevelDirectories.isEmpty ? allowZeroLintableFiles() : false let rulesIdentifiersToDisable = try await rulesToDisable(topLevelDirectories) let analyzerRuleIdentifiers = analyzerRulesToEnable() - return try writeConfiguration(topLevelDirectories, rulesIdentifiersToDisable, analyzerRuleIdentifiers) + return try writeConfiguration( + topLevelDirectories, + allowZeroLintableFiles, + rulesIdentifiersToDisable, + analyzerRuleIdentifiers) } private func checkForExistingConfiguration() { @@ -92,6 +97,10 @@ extension SwiftLint { } } + private func allowZeroLintableFiles() -> Bool { + false + } + private func rulesToDisable(_ topLevelDirectories: [String]) async throws -> [String] { var ruleIdentifiersToDisable: [String] = [] print("Checking for violations. This may take some time.") @@ -159,10 +168,14 @@ return analyzerRuleIdentifiers private func writeConfiguration( _ topLevelDirectories: [String], + _ allowZeroLintableFiles: Bool, _ ruleIdentifiersToDisable: [String], _ analyzerRuleIdentifiers: [String] ) throws -> Bool { var configuration = configuration(forTopLevelDirectories: topLevelDirectories) + if allowZeroLintableFiles { + configuration += "allow_zero_lintable_files: true\n" + } configuration += "disabled_rules:\n" ruleIdentifiersToDisable.forEach { configuration += " - \($0)\n" } if analyzerRuleIdentifiers.isNotEmpty { From e118c4e4edd88a91641054d163023480abef9c63 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Tue, 30 May 2023 22:45:44 +0100 Subject: [PATCH 24/54] Linting fixes --- Source/swiftlint/Commands/Configure.swift | 40 +++++++++++++++-------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 7efa80cd69..15afa7741d 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -1,5 +1,4 @@ import ArgumentParser -import ArgumentParser import Foundation import SwiftLintFramework #if os(Linux) @@ -52,7 +51,10 @@ extension SwiftLint { private func checkForExistingConfiguration() { print("Checking for existing \(Configuration.defaultFileName) configuration file.") if hasExistingConfiguration() { - doYouWantToContinue("Found an existing \(Configuration.defaultFileName) configuration file - Do you want to continue?") + doYouWantToContinue( + "Found an existing \(Configuration.defaultFileName) configuration file" + + " - Do you want to continue?" + ) } } @@ -62,7 +64,10 @@ extension SwiftLint { private func checkForExistingChildConfigurations() { print("Checking for any other \(Configuration.defaultFileName) configuration files.") - let files = FileManager.default.filesWithSuffix(Configuration.defaultFileName).filter { $0 != Configuration.defaultFileName } + + let files = FileManager.default.filesWithSuffix(Configuration.defaultFileName).filter { + $0 != Configuration.defaultFileName + } if files.isNotEmpty { print("Found existing child configurations:\n") files.forEach { print($0) } @@ -83,9 +88,9 @@ extension SwiftLint { return topLevelDirectories } else { var selectedDirectories: [String] = [] - for topLevelDirectory in topLevelDirectories { - if askUser("Do you want SwiftLint to scan the \(topLevelDirectory) directory?") { - selectedDirectories.append(topLevelDirectory) + topLevelDirectories.forEach { + if askUser("Do you want SwiftLint to scan the \($0) directory?") { + selectedDirectories.append($0) } } return selectedDirectories @@ -148,10 +153,11 @@ extension SwiftLint { } } - let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers).subtracting(ruleIdentifiersToDisable) - if deprecatedRuleIdentifiers.isNotEmpty { + let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers) + let undisableDeprecatedRuleIdentifiers = deprecatedRuleIdentifiers.subtracting(ruleIdentifiersToDisable) + if undisableDeprecatedRuleIdentifiers.isNotEmpty { if askUser("\nDo you want to disable any deprecated rules?") { - ruleIdentifiersToDisable.append(contentsOf: deprecatedRuleIdentifiers.sorted()) + ruleIdentifiersToDisable.append(contentsOf: undisableDeprecatedRuleIdentifiers.sorted()) } } return ruleIdentifiersToDisable @@ -160,7 +166,7 @@ extension SwiftLint { private func analyzerRulesToEnable() -> [String] { let analyzerRuleIdentifiers = RuleRegistry.shared.analyzerRuleIdentifiers.sorted() if askUser("\nDo you want to enable all (\(analyzerRuleIdentifiers.count)) of the analyzer rules?") { -return analyzerRuleIdentifiers + return analyzerRuleIdentifiers } else { return [] } @@ -216,11 +222,14 @@ return analyzerRuleIdentifiers try configuration.write(toFile: Configuration.defaultFileName, atomically: true, encoding: .utf8) } - private func configuration(forTopLevelDirectories topLevelDirectories: [String], path: String? = nil) -> String { + private func configuration( + forTopLevelDirectories topLevelDirectories: [String], + path: String? = nil + ) -> String { var configuration = "included:\n" topLevelDirectories.forEach { let absolutePath: String - if let path = path { + if let path { absolutePath = path.bridge().appendingPathComponent($0) } else { absolutePath = $0 @@ -232,7 +241,10 @@ return analyzerRuleIdentifiers } private func writeTemporaryConfigurationFile(_ topLevelDirectories: [String]) throws -> String { - let configuration = configuration(forTopLevelDirectories: topLevelDirectories, path: FileManager.default.currentDirectoryPath) + let configuration = configuration( + forTopLevelDirectories: topLevelDirectories, + path: FileManager.default.currentDirectoryPath + ) let filename = ".\(UUID().uuidString)\(Configuration.defaultFileName)" let filePath = FileManager.default.temporaryDirectory.path.bridge().appendingPathComponent(filename) try configuration.write(toFile: filePath, atomically: true, encoding: .utf8) @@ -260,7 +272,7 @@ private func askUser(_ message: String, colorizeOutput: Bool, auto: Bool) -> Boo return true } if let character = readLine() { - if character == "" || character.lowercased() == "y" { + if character.isEmpty || character.lowercased() == "y" { return true } else if character.lowercased() == "n" { return false From e39165aee32c8bbbd8c9a6f71f4fb8ba3dbc2ae3 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Thu, 22 Jun 2023 09:07:37 +0100 Subject: [PATCH 25/54] Suppress deprecation warnings --- Source/swiftlint/Commands/Configure.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 15afa7741d..c83a271efe 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -139,6 +139,7 @@ extension SwiftLint { inProcessSourcekit: false ) + Issue.printDeprecationWarnings = false let violations = try await LintOrAnalyzeCommand.lintOrAnalyze(options) if violations.isNotEmpty { if askUser("\nDo you want to disable all of the SwiftLint rules with existing violations?") { From 357cdec26261c5c51c2f5819e9a60b40f593bac6 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 25 Jun 2023 10:47:55 +0100 Subject: [PATCH 26/54] Use the summary reporter identifier --- Source/swiftlint/Commands/Configure.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index c83a271efe..0d07705efa 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -125,7 +125,7 @@ extension SwiftLint { useExcludingByPrefix: false, useScriptInputFiles: false, benchmark: false, - reporter: "summary", + reporter: SummaryReporter.identifier, quiet: false, output: nil, progress: true, From 636cf7f21fec1f09aa147912cc982232c0f5b6fa Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 25 Jun 2023 11:11:31 +0100 Subject: [PATCH 27/54] implemented allow zero lintable files --- Source/swiftlint/Commands/Configure.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 0d07705efa..8ed9b2cecf 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -97,13 +97,13 @@ extension SwiftLint { } } else { print("No .swift files found.") - doYouWantToContinue("\nDo you want to continue? (Y/n)") + doYouWantToContinue("\nDo you want to continue?") return [] } } private func allowZeroLintableFiles() -> Bool { - false + askUser("Do you want SwiftLint to succeed even if there are no files to lint?") } private func rulesToDisable(_ topLevelDirectories: [String]) async throws -> [String] { From aa1c63b097212b2a071a4d83f78032a630301f77 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 25 Jun 2023 11:44:54 +0100 Subject: [PATCH 28/54] Better handling when no files are present --- Source/swiftlint/Commands/Configure.swift | 24 +++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 8ed9b2cecf..6b7cd63553 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -33,7 +33,7 @@ extension SwiftLint { ExitHelper.successfullyExit() } - func configure() async throws -> Bool { + private func configure() async throws -> Bool { doYouWantToContinue("Welcome to SwiftLint! Do you want to continue?") checkForExistingConfiguration() checkForExistingChildConfigurations() @@ -107,6 +107,21 @@ extension SwiftLint { } private func rulesToDisable(_ topLevelDirectories: [String]) async throws -> [String] { + var ruleIdentifiersToDisable: [String] = [] + if topLevelDirectories.isNotEmpty { + ruleIdentifiersToDisable.append(contentsOf: try await checkExistingViolations(topLevelDirectories)) + } + let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers) + let undisableDeprecatedRuleIdentifiers = deprecatedRuleIdentifiers.subtracting(ruleIdentifiersToDisable) + if undisableDeprecatedRuleIdentifiers.isNotEmpty { + if askUser("\nDo you want to disable any deprecated rules?") { + ruleIdentifiersToDisable.append(contentsOf: undisableDeprecatedRuleIdentifiers.sorted()) + } + } + return ruleIdentifiersToDisable + } + + private func checkExistingViolations(_ topLevelDirectories: [String]) async throws -> [String] { var ruleIdentifiersToDisable: [String] = [] print("Checking for violations. This may take some time.") let configuration = try writeTemporaryConfigurationFile(topLevelDirectories) @@ -154,13 +169,6 @@ extension SwiftLint { } } - let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers) - let undisableDeprecatedRuleIdentifiers = deprecatedRuleIdentifiers.subtracting(ruleIdentifiersToDisable) - if undisableDeprecatedRuleIdentifiers.isNotEmpty { - if askUser("\nDo you want to disable any deprecated rules?") { - ruleIdentifiersToDisable.append(contentsOf: undisableDeprecatedRuleIdentifiers.sorted()) - } - } return ruleIdentifiersToDisable } From 5cb017623122ab0dc807556c4e69a78bba1486c1 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 25 Jun 2023 11:51:07 +0100 Subject: [PATCH 29/54] Better messaging for deprecated rules --- Source/swiftlint/Commands/Configure.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 6b7cd63553..3209374d68 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -112,10 +112,10 @@ extension SwiftLint { ruleIdentifiersToDisable.append(contentsOf: try await checkExistingViolations(topLevelDirectories)) } let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers) - let undisableDeprecatedRuleIdentifiers = deprecatedRuleIdentifiers.subtracting(ruleIdentifiersToDisable) - if undisableDeprecatedRuleIdentifiers.isNotEmpty { - if askUser("\nDo you want to disable any deprecated rules?") { - ruleIdentifiersToDisable.append(contentsOf: undisableDeprecatedRuleIdentifiers.sorted()) + let undisabledDeprecatedRuleIdentifiers = deprecatedRuleIdentifiers.subtracting(ruleIdentifiersToDisable) + if undisabledDeprecatedRuleIdentifiers.isNotEmpty { + if askUser("\nDo you want to disable all (\(undisabledDeprecatedRuleIdentifiers.count)) of the deprecated rules?") { + ruleIdentifiersToDisable.append(contentsOf: undisabledDeprecatedRuleIdentifiers.sorted()) } } return ruleIdentifiersToDisable From 74a4e822ff77a4319c45727966380251bf9cc05d Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 25 Jun 2023 16:18:41 +0100 Subject: [PATCH 30/54] Changed formatting slightly --- Source/swiftlint/Commands/Configure.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 3209374d68..f70c24f545 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -96,8 +96,7 @@ extension SwiftLint { return selectedDirectories } } else { - print("No .swift files found.") - doYouWantToContinue("\nDo you want to continue?") + doYouWantToContinue("No .swift files found. Do you want to continue?") return [] } } From 0a2c7b70a6aed60b879698c4ec015ae57fd1cd5f Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Tue, 27 Jun 2023 09:26:07 +0100 Subject: [PATCH 31/54] Fixed line length --- Source/swiftlint/Commands/Configure.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index f70c24f545..574a69d7f7 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -113,7 +113,8 @@ extension SwiftLint { let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers) let undisabledDeprecatedRuleIdentifiers = deprecatedRuleIdentifiers.subtracting(ruleIdentifiersToDisable) if undisabledDeprecatedRuleIdentifiers.isNotEmpty { - if askUser("\nDo you want to disable all (\(undisabledDeprecatedRuleIdentifiers.count)) of the deprecated rules?") { + let count = undisabledDeprecatedRuleIdentifiers.count + if askUser("\nDo you want to disable all (\(count)) of the deprecated rules?") { ruleIdentifiersToDisable.append(contentsOf: undisabledDeprecatedRuleIdentifiers.sorted()) } } From d54cf08f09438b7eebd4fde3423f82b143072742 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 2 Jul 2023 16:33:57 +0100 Subject: [PATCH 32/54] Do not start over any more --- Source/swiftlint/Commands/Configure.swift | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 574a69d7f7..e69f6abb55 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -25,11 +25,7 @@ extension SwiftLint { } func run() async throws { - while try await configure() == false, auto == false { - if askUser("Do you want to start over?") == false { - break - } - } + _ = try await configure() ExitHelper.successfullyExit() } @@ -45,7 +41,8 @@ extension SwiftLint { topLevelDirectories, allowZeroLintableFiles, rulesIdentifiersToDisable, - analyzerRuleIdentifiers) + analyzerRuleIdentifiers + ) } private func checkForExistingConfiguration() { From e6a8254926410db20e1fec6a455c6f65ca35f880 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 3 Jul 2023 18:52:41 +0100 Subject: [PATCH 33/54] Added reporter support --- Source/swiftlint/Commands/Configure.swift | 42 +++++++++++++++++++++-- Source/swiftlint/Commands/Reporters.swift | 7 +++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index e69f6abb55..615c37491f 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -37,11 +37,13 @@ extension SwiftLint { let allowZeroLintableFiles = topLevelDirectories.isEmpty ? allowZeroLintableFiles() : false let rulesIdentifiersToDisable = try await rulesToDisable(topLevelDirectories) let analyzerRuleIdentifiers = analyzerRulesToEnable() + let reporterIdentifier = reporterIdentifier() return try writeConfiguration( topLevelDirectories, allowZeroLintableFiles, rulesIdentifiersToDisable, - analyzerRuleIdentifiers + analyzerRuleIdentifiers, + reporterIdentifier ) } @@ -178,11 +180,33 @@ extension SwiftLint { } } + private func reporterIdentifier() -> String { + var reporterIdentifier = XcodeReporter.identifier + if askUser("Do you want to use the default (\(reporterIdentifier) reporter?") { + return reporterIdentifier + } + reporterIdentifier = "" + while !isValidReporterIdentifier(reporterIdentifier) { + if reporterIdentifier.isNotEmpty { + print("'\(reporterIdentifier)' is not a valid reporter identifier") + } + print("Available reporters:") + print(Reporters.reportersTable()) + reporterIdentifier = askUserWhichReporter() + } + return reporterIdentifier + } + + private func isValidReporterIdentifier(_ reporterIdentifier: String) -> Bool { + reportersList.contains { $0.identifier == reporterIdentifier } + } + private func writeConfiguration( _ topLevelDirectories: [String], _ allowZeroLintableFiles: Bool, _ ruleIdentifiersToDisable: [String], - _ analyzerRuleIdentifiers: [String] + _ analyzerRuleIdentifiers: [String], + _ reporterIdentifier: String ) throws -> Bool { var configuration = configuration(forTopLevelDirectories: topLevelDirectories) if allowZeroLintableFiles { @@ -194,6 +218,7 @@ extension SwiftLint { configuration += "analyzer_rules:\n" analyzerRuleIdentifiers.forEach { configuration += " - \($0)\n" } } + configuration += "reporter: \(reporterIdentifier)" print("Proposed configuration\n") print(configuration) if askUser("Does that look good?") == false { @@ -266,6 +291,19 @@ extension SwiftLint { ExitHelper.successfullyExit() } } + + private func askUserWhichReporter() -> String { + let message = "Which reporter would you like to use?" + let colorizedMessage = shouldColorizeOutput ? message.boldify : message + while true { + print(colorizedMessage, terminator: " ") + if let reporterIdentifier = readLine() { + if reporterIdentifier.isNotEmpty { + return reporterIdentifier + } + } + } + } } } diff --git a/Source/swiftlint/Commands/Reporters.swift b/Source/swiftlint/Commands/Reporters.swift index 56be3b3174..611b7977ae 100644 --- a/Source/swiftlint/Commands/Reporters.swift +++ b/Source/swiftlint/Commands/Reporters.swift @@ -7,7 +7,12 @@ extension SwiftLint { static let configuration = CommandConfiguration(abstract: "Display the list of reporters and their identifiers") func run() throws { - print(TextTable(reporters: reportersList).render()) + print(Self.reportersTable()) + ExitHelper.successfullyExit() + } + + static func reportersTable() -> String { + TextTable(reporters: reportersList).render() } } } From 9a871d293d776694638a6c372ca3566badc7a47c Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Wed, 30 Aug 2023 19:15:57 +0100 Subject: [PATCH 34/54] Hacked around reporter identifiers --- Source/swiftlint/Commands/Configure.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 615c37491f..1f725178cd 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -139,7 +139,7 @@ extension SwiftLint { useExcludingByPrefix: false, useScriptInputFiles: false, benchmark: false, - reporter: SummaryReporter.identifier, + reporter: "summary", // SummaryReporter.identifier, quiet: false, output: nil, progress: true, @@ -181,7 +181,8 @@ extension SwiftLint { } private func reporterIdentifier() -> String { - var reporterIdentifier = XcodeReporter.identifier + // var reporterIdentifier = XcodeReporter.identifier + var reporterIdentifier = "xcode" if askUser("Do you want to use the default (\(reporterIdentifier) reporter?") { return reporterIdentifier } From 12688684993f0568e398b46b0c9f627837b28e02 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Fri, 6 Oct 2023 22:17:45 +0100 Subject: [PATCH 35/54] Preserve configuration --- Source/swiftlint/Commands/Configure.swift | 98 ++++++++++++++++++----- 1 file changed, 76 insertions(+), 22 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 1f725178cd..623347c914 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -31,11 +31,14 @@ extension SwiftLint { private func configure() async throws -> Bool { doYouWantToContinue("Welcome to SwiftLint! Do you want to continue?") - checkForExistingConfiguration() + let existingConfiguration = checkForExistingConfiguration() checkForExistingChildConfigurations() let topLevelDirectories = checkForSwiftFiles() let allowZeroLintableFiles = topLevelDirectories.isEmpty ? allowZeroLintableFiles() : false - let rulesIdentifiersToDisable = try await rulesToDisable(topLevelDirectories) + let rulesIdentifiersToDisable = try await rulesToDisable( + topLevelDirectories, + configuration: existingConfiguration + ) let analyzerRuleIdentifiers = analyzerRulesToEnable() let reporterIdentifier = reporterIdentifier() return try writeConfiguration( @@ -47,14 +50,20 @@ extension SwiftLint { ) } - private func checkForExistingConfiguration() { - print("Checking for existing \(Configuration.defaultFileName) configuration file.") + private func checkForExistingConfiguration() -> Configuration? { + let fileName = Configuration.defaultFileName + print("Checking for existing \(fileName) configuration file.") if hasExistingConfiguration() { doYouWantToContinue( - "Found an existing \(Configuration.defaultFileName) configuration file" + "Found an existing \(fileName) configuration file" + " - Do you want to continue?" ) + if askUser("Do you want to you want to keep any custom configurations from \(fileName)") { + let configuration = Configuration(configurationFiles: [fileName]) + return configuration + } } + return nil } private func hasExistingConfiguration() -> Bool { @@ -104,10 +113,14 @@ extension SwiftLint { askUser("Do you want SwiftLint to succeed even if there are no files to lint?") } - private func rulesToDisable(_ topLevelDirectories: [String]) async throws -> [String] { + private func rulesToDisable(_ topLevelDirectories: [String], configuration: Configuration?) async throws -> [String] { var ruleIdentifiersToDisable: [String] = [] if topLevelDirectories.isNotEmpty { - ruleIdentifiersToDisable.append(contentsOf: try await checkExistingViolations(topLevelDirectories)) + let rulesWithExistingViolations = try await checkExistingViolations( + topLevelDirectories, + configuration: configuration + ) + ruleIdentifiersToDisable.append(contentsOf: rulesWithExistingViolations) } let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers) let undisabledDeprecatedRuleIdentifiers = deprecatedRuleIdentifiers.subtracting(ruleIdentifiersToDisable) @@ -120,19 +133,25 @@ extension SwiftLint { return ruleIdentifiersToDisable } - private func checkExistingViolations(_ topLevelDirectories: [String]) async throws -> [String] { + private func checkExistingViolations( + _ topLevelDirectories: [String], + configuration: Configuration? + ) async throws -> [String] { var ruleIdentifiersToDisable: [String] = [] print("Checking for violations. This may take some time.") - let configuration = try writeTemporaryConfigurationFile(topLevelDirectories) + let configurationPath = try writeTemporaryConfigurationFile( + topLevelDirectories, + configuration: configuration + ) defer { - try? FileManager.default.removeItem(atPath: configuration) + // try? FileManager.default.removeItem(atPath: configurationPath) } let options = LintOrAnalyzeOptions( mode: .lint, paths: [""], useSTDIN: false, - configurationFiles: [configuration], + configurationFiles: [configurationPath], strict: false, lenient: true, forceExclude: false, @@ -209,7 +228,7 @@ extension SwiftLint { _ analyzerRuleIdentifiers: [String], _ reporterIdentifier: String ) throws -> Bool { - var configuration = configuration(forTopLevelDirectories: topLevelDirectories) + var configuration = configurationYML(forTopLevelDirectories: topLevelDirectories) if allowZeroLintableFiles { configuration += "allow_zero_lintable_files: true\n" } @@ -254,11 +273,12 @@ extension SwiftLint { try configuration.write(toFile: Configuration.defaultFileName, atomically: true, encoding: .utf8) } - private func configuration( + private func configurationYML( forTopLevelDirectories topLevelDirectories: [String], - path: String? = nil + path: String? = nil, + configuration: Configuration? = nil ) -> String { - var configuration = "included:\n" + var configurationYML = "included:\n" topLevelDirectories.forEach { let absolutePath: String if let path { @@ -266,20 +286,28 @@ extension SwiftLint { } else { absolutePath = $0 } - configuration += " - \(absolutePath)\n" + configurationYML += " - \(absolutePath)\n" } - configuration += "opt_in_rules:\n - all\n" - return configuration + configurationYML += "opt_in_rules:\n - all\n" + if let configuration { + configurationYML += configuration.customYML + } + return configurationYML } - private func writeTemporaryConfigurationFile(_ topLevelDirectories: [String]) throws -> String { - let configuration = configuration( + private func writeTemporaryConfigurationFile( + _ topLevelDirectories: [String], + configuration: Configuration? + ) throws -> String { + let temporaryConfiguration = configurationYML( forTopLevelDirectories: topLevelDirectories, - path: FileManager.default.currentDirectoryPath + path: FileManager.default.currentDirectoryPath, + configuration: configuration ) let filename = ".\(UUID().uuidString)\(Configuration.defaultFileName)" let filePath = FileManager.default.temporaryDirectory.path.bridge().appendingPathComponent(filename) - try configuration.write(toFile: filePath, atomically: true, encoding: .utf8) + print(">>>> filePath = \(filePath)") + try temporaryConfiguration.write(toFile: filePath, atomically: true, encoding: .utf8) return filePath } @@ -377,3 +405,29 @@ private extension RuleRegistry { } } } + +private extension Configuration { + var customYML: String { + var customYML = "" + for rule in rules { + let ruleIdentifier = type(of: rule).description.identifier + guard ruleIdentifier != "file_name", ruleIdentifier != "required_enum_case" else { + continue + } + if rule.configurationDescription.hasContent { + let defaultRule = type(of: rule).init() + let defaultYML = defaultRule.configurationDescription.yaml() + let ruleYML = rule.configurationDescription.yaml() + if ruleYML != defaultYML { + customYML += """ + + \(type(of: rule).description.identifier): + \(ruleYML.indent(by: 4)) + + """ + } + } + } + return customYML + } +} From 1354b69a8225d48db070db861b412f514ec9bb03 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Fri, 13 Oct 2023 23:22:39 +0100 Subject: [PATCH 36/54] Commented out deprecated rule handling for right now --- Source/swiftlint/Commands/Configure.swift | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 623347c914..40c29929ce 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -122,14 +122,14 @@ extension SwiftLint { ) ruleIdentifiersToDisable.append(contentsOf: rulesWithExistingViolations) } - let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers) - let undisabledDeprecatedRuleIdentifiers = deprecatedRuleIdentifiers.subtracting(ruleIdentifiersToDisable) - if undisabledDeprecatedRuleIdentifiers.isNotEmpty { - let count = undisabledDeprecatedRuleIdentifiers.count - if askUser("\nDo you want to disable all (\(count)) of the deprecated rules?") { - ruleIdentifiersToDisable.append(contentsOf: undisabledDeprecatedRuleIdentifiers.sorted()) - } - } +// let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers) +// let undisabledDeprecatedRuleIdentifiers = deprecatedRuleIdentifiers.subtracting(ruleIdentifiersToDisable) +// if undisabledDeprecatedRuleIdentifiers.isNotEmpty { +// let count = undisabledDeprecatedRuleIdentifiers.count +// if askUser("\nDo you want to disable all (\(count)) of the deprecated rules?") { +// ruleIdentifiersToDisable.append(contentsOf: undisabledDeprecatedRuleIdentifiers.sorted()) +// } +// } return ruleIdentifiersToDisable } @@ -394,14 +394,14 @@ private extension FileManager { } private extension RuleRegistry { - var deprecatedRuleIdentifiers: [String] { - RuleRegistry.shared.list.list.compactMap { ruleID, ruleType in - ruleType is DeprecatedRule.Type ? ruleID : nil - } - } +// var deprecatedRuleIdentifiers: [String] { +// RuleRegistry.shared.list.list.compactMap { ruleID, ruleType in +// ruleType is DeprecatedRule.Type ? ruleID : nil +// } +// } var analyzerRuleIdentifiers: [String] { RuleRegistry.shared.list.list.compactMap { ruleID, ruleType in - ruleType is AnalyzerRule.Type ? ruleID : nil + ruleType is any AnalyzerRule.Type ? ruleID : nil } } } From a264ef73ed53c8a5d2f6ca11a7142414077ec012 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Fri, 13 Oct 2023 23:40:21 +0100 Subject: [PATCH 37/54] Restored deprecated rule handling --- Source/SwiftLintCore/Protocols/Rule.swift | 2 ++ Source/swiftlint/Commands/Configure.swift | 26 +++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Source/SwiftLintCore/Protocols/Rule.swift b/Source/SwiftLintCore/Protocols/Rule.swift index 5e0214b678..4ab1a92033 100644 --- a/Source/SwiftLintCore/Protocols/Rule.swift +++ b/Source/SwiftLintCore/Protocols/Rule.swift @@ -154,6 +154,8 @@ public extension Rule { /// A rule that is not enabled by default. Rules conforming to this need to be explicitly enabled by users. public protocol OptInRule: Rule {} +public protocol DeprecatedRule: Rule {} + /// A rule that can correct violations. public protocol CorrectableRule: Rule { /// Attempts to correct the violations to this rule in the specified file. diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 40c29929ce..c6d3fb41a9 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -122,14 +122,14 @@ extension SwiftLint { ) ruleIdentifiersToDisable.append(contentsOf: rulesWithExistingViolations) } -// let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers) -// let undisabledDeprecatedRuleIdentifiers = deprecatedRuleIdentifiers.subtracting(ruleIdentifiersToDisable) -// if undisabledDeprecatedRuleIdentifiers.isNotEmpty { -// let count = undisabledDeprecatedRuleIdentifiers.count -// if askUser("\nDo you want to disable all (\(count)) of the deprecated rules?") { -// ruleIdentifiersToDisable.append(contentsOf: undisabledDeprecatedRuleIdentifiers.sorted()) -// } -// } + let deprecatedRuleIdentifiers = Set(RuleRegistry.shared.deprecatedRuleIdentifiers) + let undisabledDeprecatedRuleIdentifiers = deprecatedRuleIdentifiers.subtracting(ruleIdentifiersToDisable) + if undisabledDeprecatedRuleIdentifiers.isNotEmpty { + let count = undisabledDeprecatedRuleIdentifiers.count + if askUser("\nDo you want to disable all (\(count)) of the deprecated rules?") { + ruleIdentifiersToDisable.append(contentsOf: undisabledDeprecatedRuleIdentifiers.sorted()) + } + } return ruleIdentifiersToDisable } @@ -394,11 +394,11 @@ private extension FileManager { } private extension RuleRegistry { -// var deprecatedRuleIdentifiers: [String] { -// RuleRegistry.shared.list.list.compactMap { ruleID, ruleType in -// ruleType is DeprecatedRule.Type ? ruleID : nil -// } -// } + var deprecatedRuleIdentifiers: [String] { + RuleRegistry.shared.list.list.compactMap { ruleID, ruleType in + ruleType is any DeprecatedRule.Type ? ruleID : nil + } + } var analyzerRuleIdentifiers: [String] { RuleRegistry.shared.list.list.compactMap { ruleID, ruleType in ruleType is any AnalyzerRule.Type ? ruleID : nil From 3a58b41d1382786a7d85f2e1e75ead597a0d545c Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 14 Oct 2023 11:21:38 +0100 Subject: [PATCH 38/54] Match our output and command line --- Source/swiftlint/Commands/Configure.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index c6d3fb41a9..84b37d4269 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -153,7 +153,7 @@ extension SwiftLint { useSTDIN: false, configurationFiles: [configurationPath], strict: false, - lenient: true, + lenient: false, forceExclude: false, useExcludingByPrefix: false, useScriptInputFiles: false, From 57391c7e2b3ae3c058a19c327e5eadaa69e313fe Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 14 Oct 2023 11:41:37 +0100 Subject: [PATCH 39/54] swiftlint fixes --- Source/swiftlint/Commands/Configure.swift | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 84b37d4269..2ced4e310a 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -7,6 +7,7 @@ import SwiftLintFramework import Darwin.C #endif +// swiftlint:disable file_length extension SwiftLint { struct Configure: AsyncParsableCommand { static let configuration = CommandConfiguration(abstract: "Configure SwiftLint") @@ -59,8 +60,7 @@ extension SwiftLint { + " - Do you want to continue?" ) if askUser("Do you want to you want to keep any custom configurations from \(fileName)") { - let configuration = Configuration(configurationFiles: [fileName]) - return configuration + return Configuration(configurationFiles: [fileName]) } } return nil @@ -113,11 +113,14 @@ extension SwiftLint { askUser("Do you want SwiftLint to succeed even if there are no files to lint?") } - private func rulesToDisable(_ topLevelDirectories: [String], configuration: Configuration?) async throws -> [String] { + private func rulesToDisable( + _ topLevelDirectories: [String], + configuration: Configuration?) async throws -> [String] + { var ruleIdentifiersToDisable: [String] = [] if topLevelDirectories.isNotEmpty { let rulesWithExistingViolations = try await checkExistingViolations( - topLevelDirectories, + topLevelDirectories, configuration: configuration ) ruleIdentifiersToDisable.append(contentsOf: rulesWithExistingViolations) From 2721107d6aa58962c2367ba57e1347305ae632dd Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 14 Oct 2023 16:53:16 +0100 Subject: [PATCH 40/54] Swiftlint fix --- Source/swiftlint/Commands/Configure.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 2ced4e310a..0a0b60ef0e 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -115,8 +115,8 @@ extension SwiftLint { private func rulesToDisable( _ topLevelDirectories: [String], - configuration: Configuration?) async throws -> [String] - { + configuration: Configuration? + ) async throws -> [String] { var ruleIdentifiersToDisable: [String] = [] if topLevelDirectories.isNotEmpty { let rulesWithExistingViolations = try await checkExistingViolations( From d13c01c3f66e9762974ac7cd596e3a7a923f77e8 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 14 Oct 2023 23:03:14 +0100 Subject: [PATCH 41/54] tweaks --- Source/swiftlint/Commands/Configure.swift | 69 +++++++++++++++-------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 0a0b60ef0e..b9a0052861 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -43,11 +43,12 @@ extension SwiftLint { let analyzerRuleIdentifiers = analyzerRulesToEnable() let reporterIdentifier = reporterIdentifier() return try writeConfiguration( - topLevelDirectories, - allowZeroLintableFiles, - rulesIdentifiersToDisable, - analyzerRuleIdentifiers, - reporterIdentifier + topLevelDirectories: topLevelDirectories, + allowZeroLintableFiles: allowZeroLintableFiles, + ruleIdentifiersToDisable: rulesIdentifiersToDisable, + analyzerRuleIdentifiers: analyzerRuleIdentifiers, + existingConfiguration: existingConfiguration, + reporterIdentifier: reporterIdentifier ) } @@ -198,6 +199,15 @@ extension SwiftLint { if askUser("\nDo you want to enable all (\(analyzerRuleIdentifiers.count)) of the analyzer rules?") { return analyzerRuleIdentifiers } else { + if askUser("\nDo you want to enable any of the analyzer rules?") { + var analyzerRulesToEnable: [String] = [] + RuleRegistry.shared.analyzerRuleIdentifiers.forEach { + if askUser("Do you want to enable the \($0) analyzer rule?") { + analyzerRulesToEnable.append($0) + } + } + return analyzerRulesToEnable + } return [] } } @@ -205,7 +215,7 @@ extension SwiftLint { private func reporterIdentifier() -> String { // var reporterIdentifier = XcodeReporter.identifier var reporterIdentifier = "xcode" - if askUser("Do you want to use the default (\(reporterIdentifier) reporter?") { + if askUser("Do you want to use the default (\(reporterIdentifier)) reporter?") { return reporterIdentifier } reporterIdentifier = "" @@ -225,45 +235,50 @@ extension SwiftLint { } private func writeConfiguration( - _ topLevelDirectories: [String], - _ allowZeroLintableFiles: Bool, - _ ruleIdentifiersToDisable: [String], - _ analyzerRuleIdentifiers: [String], - _ reporterIdentifier: String + topLevelDirectories: [String], + allowZeroLintableFiles: Bool, + ruleIdentifiersToDisable: [String], + analyzerRuleIdentifiers: [String], + existingConfiguration: Configuration?, + reporterIdentifier: String ) throws -> Bool { - var configuration = configurationYML(forTopLevelDirectories: topLevelDirectories) + var configurationYML = configurationYML(forTopLevelDirectories: topLevelDirectories) if allowZeroLintableFiles { - configuration += "allow_zero_lintable_files: true\n" + configurationYML += "allow_zero_lintable_files: true\n" } - configuration += "disabled_rules:\n" - ruleIdentifiersToDisable.forEach { configuration += " - \($0)\n" } + configurationYML += "disabled_rules:\n" + ruleIdentifiersToDisable.sorted().forEach { configurationYML += " - \($0)\n" } if analyzerRuleIdentifiers.isNotEmpty { - configuration += "analyzer_rules:\n" - analyzerRuleIdentifiers.forEach { configuration += " - \($0)\n" } + configurationYML += "analyzer_rules:\n" + analyzerRuleIdentifiers.forEach { configurationYML += " - \($0)\n" } + } + configurationYML += "reporter: \(reporterIdentifier)\n" + if let existingConfiguration { + configurationYML += "\n" + configurationYML += existingConfiguration.customYML } - configuration += "reporter: \(reporterIdentifier)" print("Proposed configuration\n") - print(configuration) + print(configurationYML) if askUser("Does that look good?") == false { return false } if hasExistingConfiguration() { if auto && overwrite { print("Overwriting existing configuration.") - try writeConfiguration(configuration) + try writeConfigurationYML(configurationYML) return true } else { print("Found an existing configuration.") if !askUser("Do you want to exit without overwriting the existing configuration?") { if askUser("Do you want to overwrite the existing configuration?") { - try writeConfiguration(configuration) + try writeConfigurationYML(configurationYML) return true } } } } else { if askUser("Do you want to save the configuration?") { - try writeConfiguration(configuration) + try writeConfigurationYML(configurationYML) return true } } @@ -271,9 +286,9 @@ extension SwiftLint { return false } - private func writeConfiguration(_ configuration: String) throws { + private func writeConfigurationYML(_ configurationYML: String) throws { print("Saving configuration to \(Configuration.defaultFileName)") - try configuration.write(toFile: Configuration.defaultFileName, atomically: true, encoding: .utf8) + try configurationYML.write(toFile: Configuration.defaultFileName, atomically: true, encoding: .utf8) } private func configurationYML( @@ -291,7 +306,11 @@ extension SwiftLint { } configurationYML += " - \(absolutePath)\n" } - configurationYML += "opt_in_rules:\n - all\n" + configurationYML += "opt_in_rules:\n - \(RuleIdentifier.all.stringRepresentation)\n" + configurationYML += "analyzer_rules:\n" + RuleRegistry.shared.analyzerRuleIdentifiers.forEach { + configurationYML += " - \($0)\n" + } if let configuration { configurationYML += configuration.customYML } From b14fc3b1a186b39360d3457e52e22b9449bb05b5 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Tue, 17 Oct 2023 23:57:52 +0100 Subject: [PATCH 42/54] Swiftlint disable --- Source/swiftlint/Commands/Configure.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index b9a0052861..d17c2e54f8 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -234,6 +234,7 @@ extension SwiftLint { reportersList.contains { $0.identifier == reporterIdentifier } } + // swiftlint:disable:next function_parameter_count private func writeConfiguration( topLevelDirectories: [String], allowZeroLintableFiles: Bool, From ba3926f910b475efe2913be6ae4b59e85be6a3cd Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 26 Nov 2023 21:58:59 +0000 Subject: [PATCH 43/54] Added documentation for DeprecatedRule --- Source/SwiftLintCore/Protocols/Rule.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/SwiftLintCore/Protocols/Rule.swift b/Source/SwiftLintCore/Protocols/Rule.swift index 4ab1a92033..03171d0868 100644 --- a/Source/SwiftLintCore/Protocols/Rule.swift +++ b/Source/SwiftLintCore/Protocols/Rule.swift @@ -154,6 +154,7 @@ public extension Rule { /// A rule that is not enabled by default. Rules conforming to this need to be explicitly enabled by users. public protocol OptInRule: Rule {} +/// A rule that has been deprecated, and that will be removed in a future release. public protocol DeprecatedRule: Rule {} /// A rule that can correct violations. From d542cc3216c9f2dd0491633ca1bbfc0dc2c489fd Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 30 Mar 2024 19:45:39 +0000 Subject: [PATCH 44/54] Autocorrects --- Source/swiftlint/Commands/Configure.swift | 60 ++++++++++------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index d17c2e54f8..f4b6837755 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -95,19 +95,17 @@ extension SwiftLint { topLevelDirectories.forEach { print($0) } if askUser("\nDo you want SwiftLint to scan all of those directories?") { return topLevelDirectories - } else { - var selectedDirectories: [String] = [] - topLevelDirectories.forEach { - if askUser("Do you want SwiftLint to scan the \($0) directory?") { - selectedDirectories.append($0) - } + } + var selectedDirectories: [String] = [] + topLevelDirectories.forEach { + if askUser("Do you want SwiftLint to scan the \($0) directory?") { + selectedDirectories.append($0) } - return selectedDirectories } - } else { - doYouWantToContinue("No .swift files found. Do you want to continue?") - return [] + return selectedDirectories } + doYouWantToContinue("No .swift files found. Do you want to continue?") + return [] } private func allowZeroLintableFiles() -> Bool { @@ -184,9 +182,8 @@ extension SwiftLint { ruleIdentifiersToDisable = dictionary.keys.sorted { if dictionary[$0]!.count != dictionary[$1]!.count { return dictionary[$0]!.count > dictionary[$1]!.count - } else { - return $0 > $1 } + return $0 > $1 } } } @@ -198,18 +195,17 @@ extension SwiftLint { let analyzerRuleIdentifiers = RuleRegistry.shared.analyzerRuleIdentifiers.sorted() if askUser("\nDo you want to enable all (\(analyzerRuleIdentifiers.count)) of the analyzer rules?") { return analyzerRuleIdentifiers - } else { - if askUser("\nDo you want to enable any of the analyzer rules?") { - var analyzerRulesToEnable: [String] = [] - RuleRegistry.shared.analyzerRuleIdentifiers.forEach { - if askUser("Do you want to enable the \($0) analyzer rule?") { - analyzerRulesToEnable.append($0) - } + } + if askUser("\nDo you want to enable any of the analyzer rules?") { + var analyzerRulesToEnable: [String] = [] + RuleRegistry.shared.analyzerRuleIdentifiers.forEach { + if askUser("Do you want to enable the \($0) analyzer rule?") { + analyzerRulesToEnable.append($0) } - return analyzerRulesToEnable } - return [] + return analyzerRulesToEnable } + return [] } private func reporterIdentifier() -> String { @@ -268,13 +264,12 @@ extension SwiftLint { print("Overwriting existing configuration.") try writeConfigurationYML(configurationYML) return true - } else { - print("Found an existing configuration.") - if !askUser("Do you want to exit without overwriting the existing configuration?") { - if askUser("Do you want to overwrite the existing configuration?") { - try writeConfigurationYML(configurationYML) - return true - } + } + print("Found an existing configuration.") + if !askUser("Do you want to exit without overwriting the existing configuration?") { + if askUser("Do you want to overwrite the existing configuration?") { + try writeConfigurationYML(configurationYML) + return true } } } else { @@ -370,11 +365,11 @@ private func askUser(_ message: String, colorizeOutput: Bool, auto: Bool) -> Boo if let character = readLine() { if character.isEmpty || character.lowercased() == "y" { return true - } else if character.lowercased() == "n" { + } + if character.lowercased() == "n" { return false - } else { - print("Invalid Response") } + print("Invalid Response") } } } @@ -387,8 +382,7 @@ private func print(_ message: String, terminator: String = "\n") { private func terminalSupportsColor() -> Bool { if isatty(1) != 0, let term = ProcessInfo.processInfo.environment["TERM"], - term.contains("color"), term.contains("256") - { + term.contains("color"), term.contains("256") { return true } return false From 166f89060048a0af59b77f043bba16fa4cb32f12 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 29 Apr 2024 21:54:48 +0100 Subject: [PATCH 45/54] Hoisted by my own petard --- Source/swiftlint/Commands/Configure.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index f4b6837755..daadae2860 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -293,12 +293,12 @@ extension SwiftLint { configuration: Configuration? = nil ) -> String { var configurationYML = "included:\n" - topLevelDirectories.forEach { + topLevelDirectories.forEach { directory in let absolutePath: String if let path { - absolutePath = path.bridge().appendingPathComponent($0) + absolutePath = path.bridge().appendingPathComponent(directory) } else { - absolutePath = $0 + absolutePath = directory } configurationYML += " - \(absolutePath)\n" } From 1fc57345d219a11dc84ffc5781963e9e8d59b9a9 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Wed, 1 May 2024 20:01:20 +0100 Subject: [PATCH 46/54] Fixed syntax error --- Source/swiftlint/Commands/Configure.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index daadae2860..33cd833cdf 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -161,6 +161,8 @@ extension SwiftLint { useScriptInputFiles: false, benchmark: false, reporter: "summary", // SummaryReporter.identifier, + baseline: nil, + writeBaseline: nil, quiet: false, output: nil, progress: true, From 959fc8a786970d76cc8e76256eb97326416c5845 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 29 Jun 2024 16:40:44 +0100 Subject: [PATCH 47/54] Account for working directory call --- Source/swiftlint/Commands/Configure.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 33cd833cdf..27fdce68aa 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -163,6 +163,7 @@ extension SwiftLint { reporter: "summary", // SummaryReporter.identifier, baseline: nil, writeBaseline: nil, + workingDirectory: nil, quiet: false, output: nil, progress: true, From 6f2f9aed7f761ac94fb49b9c799f425cc9a8c035 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 15 Jul 2024 21:22:19 +0100 Subject: [PATCH 48/54] Fixes --- Source/swiftlint/Commands/Configure.swift | 31 ++++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 27fdce68aa..844c40c93e 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -174,7 +174,8 @@ extension SwiftLint { format: false, compilerLogPath: nil, compileCommands: nil, - inProcessSourcekit: false + inProcessSourcekit: false, + checkForUpdates: false ) Issue.printDeprecationWarnings = false @@ -428,25 +429,25 @@ private extension RuleRegistry { private extension Configuration { var customYML: String { - var customYML = "" + let customYML = "" for rule in rules { let ruleIdentifier = type(of: rule).description.identifier guard ruleIdentifier != "file_name", ruleIdentifier != "required_enum_case" else { continue } - if rule.configurationDescription.hasContent { - let defaultRule = type(of: rule).init() - let defaultYML = defaultRule.configurationDescription.yaml() - let ruleYML = rule.configurationDescription.yaml() - if ruleYML != defaultYML { - customYML += """ - - \(type(of: rule).description.identifier): - \(ruleYML.indent(by: 4)) - - """ - } - } +// if rule.configurationDescription.hasContent { +// let defaultRule = type(of: rule).init() +// let defaultYML = defaultRule.configurationDescription.yaml() +// let ruleYML = rule.configurationDescription.yaml() +// if ruleYML != defaultYML { +// customYML += """ +// +// \(type(of: rule).description.identifier): +// \(ruleYML.indent(by: 4)) +// +// """ +// } +// } } return customYML } From cb4b573c37f93a2a195a7b8738d576a1218d93f0 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Tue, 20 Aug 2024 18:46:31 +0200 Subject: [PATCH 49/54] Fixed arguments --- Source/swiftlint/Commands/Configure.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 844c40c93e..0bf89dd27e 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -169,12 +169,12 @@ extension SwiftLint { progress: true, cachePath: nil, ignoreCache: false, - enableAllRules: true, + enableAllRules: true, + onlyRule: nil, autocorrect: false, format: false, compilerLogPath: nil, compileCommands: nil, - inProcessSourcekit: false, checkForUpdates: false ) From 9227e9b3224e93240326b0e1b9c769e190e914e7 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Fri, 23 Aug 2024 17:17:10 +0100 Subject: [PATCH 50/54] trailing whitespace --- Source/swiftlint/Commands/Configure.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 0bf89dd27e..7c2d93c116 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -169,7 +169,7 @@ extension SwiftLint { progress: true, cachePath: nil, ignoreCache: false, - enableAllRules: true, + enableAllRules: true, onlyRule: nil, autocorrect: false, format: false, From 0e72dda28750987a6bdc88bd573cc199cab0fa59 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 30 Sep 2024 00:29:41 +0100 Subject: [PATCH 51/54] Fixed accessibility --- Source/SwiftLintFramework/LintOrAnalyzeCommand.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift index e5afd34613..a4b33b55aa 100644 --- a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift +++ b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift @@ -139,7 +139,7 @@ package struct LintOrAnalyzeCommand { } } - static func lintOrAnalyze(_ options: LintOrAnalyzeOptions) async throws -> [StyleViolation] { + package static func lintOrAnalyze(_ options: LintOrAnalyzeOptions) async throws -> [StyleViolation] { let builder = LintOrAnalyzeResultBuilder(options) _ = try await collectViolations(builder: builder) let report = builder.reporter.generateReport(builder.violations) From e8fbff9905fede3fe7d5254bdc827ba230efb607 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 26 Oct 2024 14:50:17 +0100 Subject: [PATCH 52/54] fixed up a stray description.identifier --- Source/swiftlint/Commands/Configure.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 7c2d93c116..3353228828 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -431,7 +431,7 @@ private extension Configuration { var customYML: String { let customYML = "" for rule in rules { - let ruleIdentifier = type(of: rule).description.identifier + let ruleIdentifier = type(of: rule).identifier guard ruleIdentifier != "file_name", ruleIdentifier != "required_enum_case" else { continue } @@ -442,7 +442,7 @@ private extension Configuration { // if ruleYML != defaultYML { // customYML += """ // -// \(type(of: rule).description.identifier): +// \(type(of: rule).identifier): // \(ruleYML.indent(by: 4)) // // """ From 3e43c4b768afdd7fdd145c6325d7828fae58d08c Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 26 Oct 2024 15:08:24 +0100 Subject: [PATCH 53/54] Syntax fixes --- Source/swiftlint/Commands/Configure.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 3353228828..9ca9b24085 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -159,6 +159,7 @@ extension SwiftLint { forceExclude: false, useExcludingByPrefix: false, useScriptInputFiles: false, + useScriptInputFileLists: false, benchmark: false, reporter: "summary", // SummaryReporter.identifier, baseline: nil, @@ -170,7 +171,7 @@ extension SwiftLint { cachePath: nil, ignoreCache: false, enableAllRules: true, - onlyRule: nil, + onlyRule: [], autocorrect: false, format: false, compilerLogPath: nil, From 35efd4ef4c1907d185546ac01a2dc66aa798aede Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 22 Dec 2024 11:24:25 +0000 Subject: [PATCH 54/54] Fixed some issues/conflicts --- Source/swiftlint/Commands/Configure.swift | 3 +-- Source/swiftlint/Commands/Reporters.swift | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/swiftlint/Commands/Configure.swift b/Source/swiftlint/Commands/Configure.swift index 9ca9b24085..ab8bafc095 100644 --- a/Source/swiftlint/Commands/Configure.swift +++ b/Source/swiftlint/Commands/Configure.swift @@ -27,7 +27,6 @@ extension SwiftLint { func run() async throws { _ = try await configure() - ExitHelper.successfullyExit() } private func configure() async throws -> Bool { @@ -340,7 +339,7 @@ extension SwiftLint { private func doYouWantToContinue(_ message: String) { if !askUser(message) { - ExitHelper.successfullyExit() + exit() } } diff --git a/Source/swiftlint/Commands/Reporters.swift b/Source/swiftlint/Commands/Reporters.swift index 611b7977ae..5bf1e56f3f 100644 --- a/Source/swiftlint/Commands/Reporters.swift +++ b/Source/swiftlint/Commands/Reporters.swift @@ -7,10 +7,10 @@ extension SwiftLint { static let configuration = CommandConfiguration(abstract: "Display the list of reporters and their identifiers") func run() throws { - print(Self.reportersTable()) - ExitHelper.successfullyExit() + print(Self.reportersTable) } + static func reportersTable() -> String { TextTable(reporters: reportersList).render() }