From 11222e6eba27df13504a4da036164cca7278378f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Thu, 21 Feb 2019 16:56:10 +0100 Subject: [PATCH 1/6] Add configuration option `fail_on_warnings` --- Sources/PeripheryKit/Configuration.swift | 8 +++++++- .../Frontend/Commands/ScanBehavior.swift | 4 ++++ .../Frontend/Commands/ScanCommand.swift | 14 ++++++++++---- Sources/PeripheryKit/PeripheryKitError.swift | 3 +++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Sources/PeripheryKit/Configuration.swift b/Sources/PeripheryKit/Configuration.swift index 6d7b5a43f7..b672ada68f 100644 --- a/Sources/PeripheryKit/Configuration.swift +++ b/Sources/PeripheryKit/Configuration.swift @@ -28,6 +28,7 @@ public class Configuration: Singleton { var aggressive: Bool = false var updateCheck: Bool = true var diagnosisConsole: Bool = false + var failOnWarnings: Bool = false // Non user facing. var guidedSetup: Bool = false @@ -53,7 +54,8 @@ public class Configuration: Singleton { "quiet": quiet, "aggressive": aggressive, "disable_update_check": !updateCheck, - "diagnose": diagnosisConsole + "diagnose": diagnosisConsole, + "fail_on_warnings": failOnWarnings ] return try Yams.dump(object: config) @@ -132,6 +134,10 @@ public class Configuration: Singleton { if let value = yaml["disable_update_check"] as? Bool { self.updateCheck = !value } + + if let value = yaml["fail_on_warnings"] as? Bool { + self.failOnWarnings = value + } } // MARK: - Helpers diff --git a/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift b/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift index bb657b351c..afebfd8d23 100644 --- a/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift +++ b/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift @@ -84,6 +84,10 @@ class ScanBehavior { "Periphery is a very precise tool, false positives often turn out to be correct after further investigation." ) } + + if !filteredDeclarations.isEmpty && configuration.failOnWarnings { + throw PeripheryKitError.foundIssues(count: filteredDeclarations.count) + } } catch let error as PeripheryKitError { return .failure(error) } catch { diff --git a/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift b/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift index 98b1a03907..a410c5f566 100644 --- a/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift +++ b/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift @@ -121,9 +121,10 @@ public struct ScanOptions: OptionsProtocol { let disableUpdateCheck: BoolValue let saveBuildLog: String? let useBuildLog: String? + let failOnWarnings: BoolValue - public static func create(_ config: String?) -> (_ workspace: String?) -> (_ project: String?) -> (_ schemes: String) -> (_ targets: String) -> (_ retainPublic: BoolValue) -> (_ retainObjcAnnotated: BoolValue) -> (_ retainUnusedProtocolFuncParams: BoolValue) -> (_ aggressive: BoolValue) -> (_ format: String?) -> (_ indexExclude: String?) -> (_ reportExclude: String?) -> (_ saveBuildLog: String?) -> (_ useBuildLog: String?) -> (_ diagnose: BoolValue) -> (_ verbose: BoolValue) -> (_ quiet: BoolValue) -> (_ disableUpdateCheck: BoolValue) -> ScanOptions { - return { workspace in { project in { schemes in { targets in { retainPublic in { retainObjcAnnotated in { retainUnusedProtocolFuncParams in { aggressive in { format in { indexExclude in { reportExclude in { saveBuildLog in { useBuildLog in { diagnose in { verbose in { quiet in { disableUpdateCheck in + public static func create(_ config: String?) -> (_ workspace: String?) -> (_ project: String?) -> (_ schemes: String) -> (_ targets: String) -> (_ retainPublic: BoolValue) -> (_ retainObjcAnnotated: BoolValue) -> (_ retainUnusedProtocolFuncParams: BoolValue) -> (_ aggressive: BoolValue) -> (_ format: String?) -> (_ indexExclude: String?) -> (_ reportExclude: String?) -> (_ saveBuildLog: String?) -> (_ useBuildLog: String?) -> (_ diagnose: BoolValue) -> (_ verbose: BoolValue) -> (_ quiet: BoolValue) -> (_ disableUpdateCheck: BoolValue) -> (_ failOnWarnings: BoolValue) -> ScanOptions { + return { workspace in { project in { schemes in { targets in { retainPublic in { retainObjcAnnotated in { retainUnusedProtocolFuncParams in { aggressive in { format in { indexExclude in { reportExclude in { saveBuildLog in { useBuildLog in { diagnose in { verbose in { quiet in { disableUpdateCheck in { failOnWarnings in return self.init(config: config, workspace: workspace, project: project, @@ -141,8 +142,9 @@ public struct ScanOptions: OptionsProtocol { quiet: quiet, disableUpdateCheck: disableUpdateCheck, saveBuildLog: saveBuildLog, - useBuildLog: useBuildLog) - }}}}}}}}}}}}}}}}} + useBuildLog: useBuildLog, + failOnWarnings: failOnWarnings) + }}}}}}}}}}}}}}}}}} } public static func evaluate(_ mode: CommandMode) -> Result> { @@ -221,6 +223,10 @@ public struct ScanOptions: OptionsProtocol { <*> mode <| Option(key: "disable-update-check", defaultValue: BoolValue(!config.updateCheck), usage: "Disable checking for updates") + + <*> mode <| Option(key: "fail-on-warnings", + defaultValue: BoolValue(config.failOnWarnings), + usage: "Make sure command fails if any warnings are encountered") } private static func parse(_ option: String?, _ delimiter: Character) -> [String] { diff --git a/Sources/PeripheryKit/PeripheryKitError.swift b/Sources/PeripheryKit/PeripheryKitError.swift index a8cf575921..633a3bf2b9 100644 --- a/Sources/PeripheryKit/PeripheryKitError.swift +++ b/Sources/PeripheryKit/PeripheryKitError.swift @@ -21,6 +21,7 @@ public enum PeripheryKitError: Error, LocalizedError, CustomStringConvertible { case buildLogError(message: String) case xcodebuildNotConfigured case pathDoesNotExist(path: String) + case foundIssues(count: Int) public var errorDescription: String? { switch self { @@ -62,6 +63,8 @@ public enum PeripheryKitError: Error, LocalizedError, CustomStringConvertible { return "Xcode is not configured for command-line use. Please run 'sudo xcode-select -s /Applications/Xcode.app'." case .pathDoesNotExist(let path): return "No such file or directory: \(path)." + case .foundIssues(let count): + return "Found \(count) issues." } } From 0e667fdaca9cb9f0e8a78768712bea51011e0bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Thu, 21 Feb 2019 17:14:02 +0100 Subject: [PATCH 2/6] Handle singular & plural case in amount of issues properly --- Sources/PeripheryKit/PeripheryKitError.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/PeripheryKit/PeripheryKitError.swift b/Sources/PeripheryKit/PeripheryKitError.swift index 633a3bf2b9..705cc1bc0c 100644 --- a/Sources/PeripheryKit/PeripheryKitError.swift +++ b/Sources/PeripheryKit/PeripheryKitError.swift @@ -64,7 +64,7 @@ public enum PeripheryKitError: Error, LocalizedError, CustomStringConvertible { case .pathDoesNotExist(let path): return "No such file or directory: \(path)." case .foundIssues(let count): - return "Found \(count) issues." + return "Found \(count) \(count > 1 ? "issues" : "issue")." } } From 90be8bb71956627af5e80d3668ccbb5e91c21f80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Fri, 22 Feb 2019 10:41:49 +0100 Subject: [PATCH 3/6] Rename new option to "strict" as suggested by @ileitch --- Sources/PeripheryKit/Configuration.swift | 8 ++++---- .../PeripheryKit/Frontend/Commands/ScanBehavior.swift | 2 +- .../PeripheryKit/Frontend/Commands/ScanCommand.swift | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Sources/PeripheryKit/Configuration.swift b/Sources/PeripheryKit/Configuration.swift index b672ada68f..3850019196 100644 --- a/Sources/PeripheryKit/Configuration.swift +++ b/Sources/PeripheryKit/Configuration.swift @@ -28,7 +28,7 @@ public class Configuration: Singleton { var aggressive: Bool = false var updateCheck: Bool = true var diagnosisConsole: Bool = false - var failOnWarnings: Bool = false + var strict: Bool = false // Non user facing. var guidedSetup: Bool = false @@ -55,7 +55,7 @@ public class Configuration: Singleton { "aggressive": aggressive, "disable_update_check": !updateCheck, "diagnose": diagnosisConsole, - "fail_on_warnings": failOnWarnings + "strict": strict ] return try Yams.dump(object: config) @@ -135,8 +135,8 @@ public class Configuration: Singleton { self.updateCheck = !value } - if let value = yaml["fail_on_warnings"] as? Bool { - self.failOnWarnings = value + if let value = yaml["strict"] as? Bool { + self.strict = value } } diff --git a/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift b/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift index afebfd8d23..3ff22cf016 100644 --- a/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift +++ b/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift @@ -85,7 +85,7 @@ class ScanBehavior { ) } - if !filteredDeclarations.isEmpty && configuration.failOnWarnings { + if !filteredDeclarations.isEmpty && configuration.strict { throw PeripheryKitError.foundIssues(count: filteredDeclarations.count) } } catch let error as PeripheryKitError { diff --git a/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift b/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift index a410c5f566..8066678549 100644 --- a/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift +++ b/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift @@ -121,10 +121,10 @@ public struct ScanOptions: OptionsProtocol { let disableUpdateCheck: BoolValue let saveBuildLog: String? let useBuildLog: String? - let failOnWarnings: BoolValue + let strict: BoolValue - public static func create(_ config: String?) -> (_ workspace: String?) -> (_ project: String?) -> (_ schemes: String) -> (_ targets: String) -> (_ retainPublic: BoolValue) -> (_ retainObjcAnnotated: BoolValue) -> (_ retainUnusedProtocolFuncParams: BoolValue) -> (_ aggressive: BoolValue) -> (_ format: String?) -> (_ indexExclude: String?) -> (_ reportExclude: String?) -> (_ saveBuildLog: String?) -> (_ useBuildLog: String?) -> (_ diagnose: BoolValue) -> (_ verbose: BoolValue) -> (_ quiet: BoolValue) -> (_ disableUpdateCheck: BoolValue) -> (_ failOnWarnings: BoolValue) -> ScanOptions { - return { workspace in { project in { schemes in { targets in { retainPublic in { retainObjcAnnotated in { retainUnusedProtocolFuncParams in { aggressive in { format in { indexExclude in { reportExclude in { saveBuildLog in { useBuildLog in { diagnose in { verbose in { quiet in { disableUpdateCheck in { failOnWarnings in + public static func create(_ config: String?) -> (_ workspace: String?) -> (_ project: String?) -> (_ schemes: String) -> (_ targets: String) -> (_ retainPublic: BoolValue) -> (_ retainObjcAnnotated: BoolValue) -> (_ retainUnusedProtocolFuncParams: BoolValue) -> (_ aggressive: BoolValue) -> (_ format: String?) -> (_ indexExclude: String?) -> (_ reportExclude: String?) -> (_ saveBuildLog: String?) -> (_ useBuildLog: String?) -> (_ diagnose: BoolValue) -> (_ verbose: BoolValue) -> (_ quiet: BoolValue) -> (_ disableUpdateCheck: BoolValue) -> (_ strict: BoolValue) -> ScanOptions { + return { workspace in { project in { schemes in { targets in { retainPublic in { retainObjcAnnotated in { retainUnusedProtocolFuncParams in { aggressive in { format in { indexExclude in { reportExclude in { saveBuildLog in { useBuildLog in { diagnose in { verbose in { quiet in { disableUpdateCheck in { strict in return self.init(config: config, workspace: workspace, project: project, @@ -143,7 +143,7 @@ public struct ScanOptions: OptionsProtocol { disableUpdateCheck: disableUpdateCheck, saveBuildLog: saveBuildLog, useBuildLog: useBuildLog, - failOnWarnings: failOnWarnings) + strict: strict) }}}}}}}}}}}}}}}}}} } @@ -225,7 +225,7 @@ public struct ScanOptions: OptionsProtocol { usage: "Disable checking for updates") <*> mode <| Option(key: "fail-on-warnings", - defaultValue: BoolValue(config.failOnWarnings), + defaultValue: BoolValue(config.strict), usage: "Make sure command fails if any warnings are encountered") } From f308e645175bf8f7f78868714d9e9efbdfa5eb84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Fri, 22 Feb 2019 10:44:06 +0100 Subject: [PATCH 4/6] Update code according to review feedback from @ileitch --- Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift | 4 ++-- Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift b/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift index 3ff22cf016..fbbc66ee92 100644 --- a/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift +++ b/Sources/PeripheryKit/Frontend/Commands/ScanBehavior.swift @@ -85,6 +85,8 @@ class ScanBehavior { ) } + updateChecker.notifyIfAvailable() + if !filteredDeclarations.isEmpty && configuration.strict { throw PeripheryKitError.foundIssues(count: filteredDeclarations.count) } @@ -94,8 +96,6 @@ class ScanBehavior { return .failure(.underlyingError(error)) } - updateChecker.notifyIfAvailable() - if configuration.diagnosisConsole, let graph = result.graph { let console = DiagnosisConsole(graph: graph) console.start() diff --git a/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift b/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift index 8066678549..7196bb727c 100644 --- a/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift +++ b/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift @@ -224,9 +224,9 @@ public struct ScanOptions: OptionsProtocol { defaultValue: BoolValue(!config.updateCheck), usage: "Disable checking for updates") - <*> mode <| Option(key: "fail-on-warnings", + <*> mode <| Option(key: "strict", defaultValue: BoolValue(config.strict), - usage: "Make sure command fails if any warnings are encountered") + usage: "Exit with non-zero status if any unused code is found") } private static func parse(_ option: String?, _ delimiter: Character) -> [String] { From 381845f4c92e5f2ce25e83471cc4b138d5087902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Fri, 22 Feb 2019 11:05:47 +0100 Subject: [PATCH 5/6] [CHANGELOG.md] Add entry about new strict option --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abcd985ec1..71ac46044d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,10 @@ ##### Enhancements -* None. +* New `strict` option to exit with non-zero status if any unused code is found. + [Cihat Gündüz](https://github.com/Dschee)\ + [#22](https://github.com/peripheryapp/periphery/issues/22)\ + [#23](https://github.com/peripheryapp/periphery/pull/23) ##### Bug Fixes From df64d07558834c315d21abd709d97d46cfba8634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Fri, 22 Feb 2019 11:12:41 +0100 Subject: [PATCH 6/6] Ensure the new strict option works also as command line argument --- .../Frontend/Commands/ScanCommand.swift | 4 ++++ .../Frontend/Commands/ScanSyntaxCommand.swift | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift b/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift index 7196bb727c..37d11d80ff 100644 --- a/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift +++ b/Sources/PeripheryKit/Frontend/Commands/ScanCommand.swift @@ -81,6 +81,10 @@ public struct ScanCommand: CommandProtocol { configuration.schemes = options.schemes } + if options.strict.explicit { + configuration.strict = options.strict.value + } + do { if let formatName = options.format { configuration.outputFormat = try OutputFormat.make(named: formatName) diff --git a/Sources/PeripheryKit/Frontend/Commands/ScanSyntaxCommand.swift b/Sources/PeripheryKit/Frontend/Commands/ScanSyntaxCommand.swift index dbba8d3bdd..82afac37b2 100644 --- a/Sources/PeripheryKit/Frontend/Commands/ScanSyntaxCommand.swift +++ b/Sources/PeripheryKit/Frontend/Commands/ScanSyntaxCommand.swift @@ -31,6 +31,10 @@ public struct ScanSyntaxCommand: CommandProtocol { configuration.reportExclude = options.exclude } + if options.strict.explicit { + configuration.strict = options.strict.value + } + do { if let formatName = options.format { configuration.outputFormat = try OutputFormat.make(named: formatName) @@ -51,17 +55,19 @@ public struct ScanSyntaxOptions: OptionsProtocol { let exclude: [String] let verbose: BoolValue let quiet: BoolValue + let strict: BoolValue let path: String - public static func create(_ config: String?) -> (_ format: String?) -> (_ exclude: String?) -> (_ verbose: BoolValue) -> (_ quiet: BoolValue) -> (_ path: String) -> ScanSyntaxOptions { - return { format in { exclude in { verbose in { quiet in { path in + public static func create(_ config: String?) -> (_ format: String?) -> (_ exclude: String?) -> (_ verbose: BoolValue) -> (_ quiet: BoolValue) -> (_ strict: BoolValue) -> (_ path: String) -> ScanSyntaxOptions { + return { format in { exclude in { verbose in { quiet in { strict in { path in return self.init(config: config, format: format, exclude: parse(exclude, "|"), verbose: verbose, quiet: quiet, + strict: strict, path: path) - }}}}} + }}}}}} } public static func evaluate(_ m: CommandMode) -> Result> { @@ -89,6 +95,10 @@ public struct ScanSyntaxOptions: OptionsProtocol { defaultValue: BoolValue(config.quiet), usage: "Only output results") + <*> m <| Option(key: "strict", + defaultValue: BoolValue(config.strict), + usage: "Exit with non-zero status if any unused code is found") + <*> m <| Argument(usage: "Path glob to scan") }