From c529734cfa97072f2841b7196556b41fad5203c0 Mon Sep 17 00:00:00 2001 From: Sudeep Kini Date: Thu, 4 Aug 2022 12:06:37 +0530 Subject: [PATCH 1/3] Adds filter Options for warnings 1. Adds a enum to specify which files should show warnings using Danger 2. Add code to generates list of file names from the options 3. Add code to filter warning issues based on file names list generate above. --- .../Kantoku+IssueComments.swift | 18 +++++++--- Sources/DangerSwiftKantoku/Kantoku.swift | 35 ++++++++++++++++--- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/Sources/DangerSwiftKantoku/Kantoku+IssueComments.swift b/Sources/DangerSwiftKantoku/Kantoku+IssueComments.swift index c70a63c..abda3bc 100644 --- a/Sources/DangerSwiftKantoku/Kantoku+IssueComments.swift +++ b/Sources/DangerSwiftKantoku/Kantoku+IssueComments.swift @@ -45,23 +45,33 @@ extension Kantoku { } - func post(_ summaries: [PostableIssueSummary], as level: CommentLevel) { - + func post(_ summaries: [PostableIssueSummary], + as level: CommentLevel, + targetFilesNmes: [File]? = nil) { for summary in summaries { let message = summary.issueMessage let filePath = summary.documentLocation?.relativePath(against: workingDirectoryPath) - + + if let filePath = filePath { let lineNumber = filePath.queries?.endingLineNumber + if let targetFilesNmes = targetFilesNmes { + if !(targetFilesNmes.contains(filePath.filePath.finalFileName)) { + continue + } + } // Line numbers in XCResult starts from `0`, while on web pages like GitHub starts from `1` post(as: level)(message, filePath.filePath, lineNumber.map({ $0 + 1 }) ?? 0) } else { + if targetFilesNmes != nil { + continue + } post(as: level)(message) } } } - + } diff --git a/Sources/DangerSwiftKantoku/Kantoku.swift b/Sources/DangerSwiftKantoku/Kantoku.swift index 4ff4ed9..16e4686 100644 --- a/Sources/DangerSwiftKantoku/Kantoku.swift +++ b/Sources/DangerSwiftKantoku/Kantoku.swift @@ -7,6 +7,7 @@ import Foundation import XCResultKit +import Danger public struct Kantoku { @@ -77,9 +78,23 @@ extension Kantoku { } +public typealias File = String +extension File { + var finalFileName: String { + return self.components(separatedBy: "/").last ?? "" + + } +} + extension Kantoku { - private func postIssuesIfNeeded(from resultFile: XCResultFile, configuration: XCResultParsingConfiguration) { + public enum WariningFilter { + case all + case modifiedAndCreatedFiles + case files([File]) + } + + private func postIssuesIfNeeded(from resultFile: XCResultFile, configuration: XCResultParsingConfiguration, warnFor: WariningFilter = .all) { if configuration.needsIssues { @@ -87,9 +102,19 @@ extension Kantoku { warn("Failed to get invocation record from \(resultFile.url.absoluteString)") return } - + + var targetFileNames: [String]? = nil + switch warnFor { + case .all : break + case .files(let files) : + targetFileNames = files.map{ $0.finalFileName } + case .modifiedAndCreatedFiles : + let allFilePaths = Danger().git.modifiedFiles + Danger().git.createdFiles + targetFileNames = allFilePaths.map { $0.finalFileName } + } + if configuration.parseBuildWarnings { - post(issues.warningSummaries, as: .warning) + post(issues.warningSummaries, as: .warning, targetFilesNmes: targetFileNames) } if configuration.parseBuildErrors { @@ -123,11 +148,11 @@ extension Kantoku { } - public func parseXCResultFile(at filePath: String, configuration: XCResultParsingConfiguration) { + public func parseXCResultFile(at filePath: String, configuration: XCResultParsingConfiguration, warnFor: WariningFilter) { let resultFile = XCResultFile(url: .init(fileURLWithPath: filePath)) - postIssuesIfNeeded(from: resultFile, configuration: configuration) + postIssuesIfNeeded(from: resultFile, configuration: configuration, warnFor: warnFor) postCoverageIfNeeded(from: resultFile, configuration: configuration) } From 6433d523659966ad23aac6be7875abd70678184c Mon Sep 17 00:00:00 2001 From: Sudeep Kini Date: Thu, 18 Aug 2022 14:57:26 +0530 Subject: [PATCH 2/3] Updates as per PR comments --- Sources/DangerSwiftKantoku/DangerDSL+.swift | 2 + .../Kantoku+IssueComments.swift | 13 +--- Sources/DangerSwiftKantoku/Kantoku.swift | 66 +++++++++++-------- .../XCResultParsingConfiguration.swift | 13 +++- 4 files changed, 54 insertions(+), 40 deletions(-) diff --git a/Sources/DangerSwiftKantoku/DangerDSL+.swift b/Sources/DangerSwiftKantoku/DangerDSL+.swift index 719443b..5c4bb9e 100644 --- a/Sources/DangerSwiftKantoku/DangerDSL+.swift +++ b/Sources/DangerSwiftKantoku/DangerDSL+.swift @@ -12,6 +12,8 @@ extension DangerDSL { public var kantoku: Kantoku { .init( workingDirectoryPath: utils.exec("pwd"), + modifiedFiles: git.modifiedFiles, + createdFiles: git.createdFiles, markdownCommentExecutor: { markdown($0) }, inlineCommentExecutor: { message(message: $0, file: $1, line: $2) }, normalCommentExecutor: { message($0) }, diff --git a/Sources/DangerSwiftKantoku/Kantoku+IssueComments.swift b/Sources/DangerSwiftKantoku/Kantoku+IssueComments.swift index abda3bc..4b0f205 100644 --- a/Sources/DangerSwiftKantoku/Kantoku+IssueComments.swift +++ b/Sources/DangerSwiftKantoku/Kantoku+IssueComments.swift @@ -45,28 +45,17 @@ extension Kantoku { } - func post(_ summaries: [PostableIssueSummary], - as level: CommentLevel, - targetFilesNmes: [File]? = nil) { + func post(_ summaries: [PostableIssueSummary], as level: CommentLevel) { for summary in summaries { let message = summary.issueMessage let filePath = summary.documentLocation?.relativePath(against: workingDirectoryPath) - if let filePath = filePath { let lineNumber = filePath.queries?.endingLineNumber - if let targetFilesNmes = targetFilesNmes { - if !(targetFilesNmes.contains(filePath.filePath.finalFileName)) { - continue - } - } // Line numbers in XCResult starts from `0`, while on web pages like GitHub starts from `1` post(as: level)(message, filePath.filePath, lineNumber.map({ $0 + 1 }) ?? 0) } else { - if targetFilesNmes != nil { - continue - } post(as: level)(message) } diff --git a/Sources/DangerSwiftKantoku/Kantoku.swift b/Sources/DangerSwiftKantoku/Kantoku.swift index 16e4686..ff8f498 100644 --- a/Sources/DangerSwiftKantoku/Kantoku.swift +++ b/Sources/DangerSwiftKantoku/Kantoku.swift @@ -7,11 +7,12 @@ import Foundation import XCResultKit -import Danger public struct Kantoku { let workingDirectoryPath: String + let modifiedFiles: [String] + let createdFiles: [String] private let markdownCommentExecutor: (_ comment: String) -> Void @@ -26,6 +27,8 @@ public struct Kantoku { init( workingDirectoryPath: String, + modifiedFiles: [String], + createdFiles: [String], markdownCommentExecutor: @escaping (_ comment: String) -> Void, inlineCommentExecutor: @escaping (_ comment: String, _ filePath: String, _ lineNumber: Int) -> Void, normalCommentExecutor: @escaping (_ comment: String) -> Void, @@ -35,6 +38,8 @@ public struct Kantoku { normalFailureExecutor: @escaping (_ comment: String) -> Void ) { self.workingDirectoryPath = workingDirectoryPath + self.modifiedFiles = modifiedFiles + self.createdFiles = createdFiles self.markdownCommentExecutor = markdownCommentExecutor self.inlineCommentExecutor = inlineCommentExecutor self.normalCommentExecutor = normalCommentExecutor @@ -78,23 +83,11 @@ extension Kantoku { } -public typealias File = String -extension File { - var finalFileName: String { - return self.components(separatedBy: "/").last ?? "" - } -} extension Kantoku { - public enum WariningFilter { - case all - case modifiedAndCreatedFiles - case files([File]) - } - - private func postIssuesIfNeeded(from resultFile: XCResultFile, configuration: XCResultParsingConfiguration, warnFor: WariningFilter = .all) { + private func postIssuesIfNeeded(from resultFile: XCResultFile, configuration: XCResultParsingConfiguration) { if configuration.needsIssues { @@ -103,18 +96,9 @@ extension Kantoku { return } - var targetFileNames: [String]? = nil - switch warnFor { - case .all : break - case .files(let files) : - targetFileNames = files.map{ $0.finalFileName } - case .modifiedAndCreatedFiles : - let allFilePaths = Danger().git.modifiedFiles + Danger().git.createdFiles - targetFileNames = allFilePaths.map { $0.finalFileName } - } - if configuration.parseBuildWarnings { - post(issues.warningSummaries, as: .warning, targetFilesNmes: targetFileNames) + let filteredSummaries = summaries(of: issues.warningSummaries, filteredBy: configuration.reportingFileType) + post(filteredSummaries, as: .warning) } if configuration.parseBuildErrors { @@ -148,11 +132,11 @@ extension Kantoku { } - public func parseXCResultFile(at filePath: String, configuration: XCResultParsingConfiguration, warnFor: WariningFilter) { + public func parseXCResultFile(at filePath: String, configuration: XCResultParsingConfiguration) { let resultFile = XCResultFile(url: .init(fileURLWithPath: filePath)) - postIssuesIfNeeded(from: resultFile, configuration: configuration, warnFor: warnFor) + postIssuesIfNeeded(from: resultFile, configuration: configuration) postCoverageIfNeeded(from: resultFile, configuration: configuration) } @@ -180,3 +164,31 @@ extension XCResultParsingConfiguration.CodeCoverageRequirement { } } + +extension Kantoku { + + private func summaries(of summaries: [T], filteredBy fileType: XCResultParsingConfiguration.ReportingFileType) -> [T] { + + let filteringPredicate: (XCResultParsingConfiguration.RelativeFilePath) -> Bool + + switch fileType { + case .all: + return summaries + + case .modifiedAndCreatedFiles: + filteringPredicate = { (modifiedFiles + createdFiles).contains($0) } + + case .custom(predicate: let predicate): + filteringPredicate = predicate + } + + return summaries.filter { summary in + guard let relativePath = summary.documentLocation?.relativePath(against: workingDirectoryPath) else { + return false + } + return filteringPredicate(relativePath.filePath) + } + + } + +} diff --git a/Sources/DangerSwiftKantoku/XCResultParsingConfiguration.swift b/Sources/DangerSwiftKantoku/XCResultParsingConfiguration.swift index 927a8a4..3af2be7 100644 --- a/Sources/DangerSwiftKantoku/XCResultParsingConfiguration.swift +++ b/Sources/DangerSwiftKantoku/XCResultParsingConfiguration.swift @@ -8,6 +8,14 @@ import Foundation public struct XCResultParsingConfiguration { + + public typealias RelativeFilePath = String + + public enum ReportingFileType { + case all + case modifiedAndCreatedFiles + case custom(predicate: (RelativeFilePath) -> Bool) + } public enum CodeCoverageRequirement { public struct CoverageThreshold { @@ -28,19 +36,22 @@ public struct XCResultParsingConfiguration { public var parseTestFailures: Bool public var codeCoverageRequirement: CodeCoverageRequirement + public var reportingFileType: ReportingFileType public init( parseBuildWarnings: Bool = true, parseBuildErrors: Bool = true, parseAnalyzerWarnings: Bool = true, parseTestFailures: Bool = true, - codeCoverageRequirement: CodeCoverageRequirement = .required(.init(acceptable: 0, recommended: 0.6)) + codeCoverageRequirement: CodeCoverageRequirement = .required(.init(acceptable: 0, recommended: 0.6)), + reportingFileType: ReportingFileType = .all ) { self.parseBuildWarnings = parseBuildWarnings self.parseBuildErrors = parseBuildErrors self.parseAnalyzerWarnings = parseAnalyzerWarnings self.parseTestFailures = parseTestFailures self.codeCoverageRequirement = codeCoverageRequirement + self.reportingFileType = reportingFileType } } From dec6e57b320d904226387833c8e5230b37334684 Mon Sep 17 00:00:00 2001 From: Sudeep Kini Date: Tue, 23 Aug 2022 19:09:46 +0530 Subject: [PATCH 3/3] Add code to PostCodeCoverage 1. adds 'failIfCoverageUnavailable' to allow user to fail the build if coverage is'nt avaiable 2. adds 'excludeCoverageTarget' to allow the user to filter out specific targets like pods or tests 3. adds 'showCoverageForChangedFiles' to allow user to show coverage for code changes and 'excludeCoverageForFiles' to exclude specific files 4. add code to support the above config vairables we first filter out the exculded targets, then exludedFiles. After which we proceed to post the Overall coverage following the coverage for diff files grouped by target. https://github.com/yumemi-inc/danger-swift-kantoku/issues/4 --- .../DangerSwiftKantoku/Kantoku+Coverage.swift | 109 ++++++++++++------ Sources/DangerSwiftKantoku/Kantoku.swift | 84 ++++++-------- .../XCResultParsingConfiguration.swift | 37 +++++- 3 files changed, 145 insertions(+), 85 deletions(-) diff --git a/Sources/DangerSwiftKantoku/Kantoku+Coverage.swift b/Sources/DangerSwiftKantoku/Kantoku+Coverage.swift index 130abff..1800e1c 100644 --- a/Sources/DangerSwiftKantoku/Kantoku+Coverage.swift +++ b/Sources/DangerSwiftKantoku/Kantoku+Coverage.swift @@ -1,6 +1,6 @@ // // Kantoku+Coverage.swift -// +// // // Created by 史 翔新 on 2022/03/03. // @@ -9,79 +9,122 @@ import Foundation import XCResultKit extension Kantoku { - var coverageNumberFormatter: NumberFormatter { - let formatter = NumberFormatter() formatter.numberStyle = .percent formatter.maximumFractionDigits = 2 return formatter - } - } extension Kantoku { - enum CoverageAcceptance { case good case acceptable case reject } - + private struct CoverageCommentItem { var title: String var coverage: Double var acceptance: CoverageAcceptance } - - func post(_ coverage: CodeCoverage, as acceptanceDecision: (Double) -> CoverageAcceptance) { - + + func post(_ coverage: CodeCoverage, for files: [XCResultParsingConfiguration.RelativeFilePath], as acceptanceDecision: (Double) -> CoverageAcceptance) { let formatter = coverageNumberFormatter - let title = "Overall" - let overallCoverage = coverage.lineCoverage - let overallAcceptance = acceptanceDecision(overallCoverage) - let coverageText = formatter.string(from: overallCoverage as NSNumber) ?? { - fail("Failed to extract overall coverage from \(overallCoverage)") + let overallCoverageText = formatter.string(from: coverage.lineCoverage as NSNumber) ?? { + warn("Failed to extract overall coverage, line coverage \(coverage.lineCoverage)") return "NaN" }() - - let markdownLines: [String] = [ - "| | Coverage | Acceptance |", - "|:---:|:---:|:---:|", - "| \(title) | \(coverageText) | \(overallAcceptance.markdownDescription) |", - // TODO: Coverage of diff files - ] + let overallAcceptance = acceptanceDecision(coverage.lineCoverage) + var markdownLines: [String] = ["##Overall Coverage", + "\(overallCoverageText) \(overallAcceptance.markdownDescription)"] + + markdownLines.append("") + coverage.targets.forEach { target in + let filtered = target.filteringFiles(on: files) + if filtered.files.count > 0 { + markdownLines.append("") + let acceptance = acceptanceDecision(target.lineCoverage) + let coverageText = formatter.string(from: target.lineCoverage as NSNumber) ?? "NaN" + markdownLines.append(contentsOf: ["| ###\(target.name) | \(coverageText) | \(acceptance.markdownDescription) |", + ""]) + markdownLines.append(contentsOf: ["| File | Coverage | Acceptance |", + "|:---:|:---:|:---:|"]) + filtered.files.forEach { + let acceptance = acceptanceDecision($0.lineCoverage) + let coverageText = formatter.string(from: $0.lineCoverage as NSNumber) ?? "NaN" + markdownLines.append("| \($0.name) | \(coverageText) | \(acceptance.markdownDescription) |") + } + } + } + markdown(markdownLines.joined(separator: "\n")) - switch overallAcceptance { case .good: break - + case .acceptable: - warn("Overall coverage is \(overallCoverage)") - + warn("Overall coverage is \(coverage.lineCoverage)") + case .reject: - fail("Overall coverage is \(overallCoverage), which is not enough") + fail("Overall coverage is \(coverage.lineCoverage), which is not enough") } - } - +} + +extension CodeCoverage { + func filterTargets(excludedTargets: [ExcludedTarget]) -> CodeCoverage { + let targets = self.targets.filter { target in + !target.files.isEmpty && !excludedTargets.contains { + $0.matches(string: target.name) + } + } + return CodeCoverage(targets: targets) + } + + func filterTarget(excludeFiles: (XCResultParsingConfiguration.RelativeFilePath) -> Bool) -> CodeCoverage { + let targets = self.targets + .map { $0.filteringFiles(excludeFiles: excludeFiles) } + .filter { target in + !target.files.isEmpty + } + return CodeCoverage(targets: targets) + } + + func filteringTargets(on files: [String]) -> CodeCoverage { + let targets = self.targets + .map { $0.filteringFiles(on: files) } + .filter { target in + !target.files.isEmpty + } + return CodeCoverage(targets: targets) + } +} + +extension CodeCoverageTarget { + func filteringFiles(on files: [String]) -> CodeCoverageTarget { + let files = self.files.filter { files.contains($0.path) } + return CodeCoverageTarget(name: name, buildProductPath: buildProductPath, files: files) + } + + func filteringFiles(excludeFiles: (XCResultParsingConfiguration.RelativeFilePath) -> Bool) -> CodeCoverageTarget { + let files = self.files.filter { excludeFiles($0.path) } + return CodeCoverageTarget(name: name, buildProductPath: buildProductPath, files: files) + } } extension Kantoku.CoverageAcceptance { - var markdownDescription: String { switch self { case .good: return ":white_flower:" - + case .acceptable: return ":thinking:" - + case .reject: return ":no_good:" } } - } diff --git a/Sources/DangerSwiftKantoku/Kantoku.swift b/Sources/DangerSwiftKantoku/Kantoku.swift index ff8f498..8d7f189 100644 --- a/Sources/DangerSwiftKantoku/Kantoku.swift +++ b/Sources/DangerSwiftKantoku/Kantoku.swift @@ -1,6 +1,6 @@ // // Kantoku.swift -// +// // // Created by 史 翔新 on 2022/02/10. // @@ -9,22 +9,21 @@ import Foundation import XCResultKit public struct Kantoku { - let workingDirectoryPath: String let modifiedFiles: [String] let createdFiles: [String] - + private let markdownCommentExecutor: (_ comment: String) -> Void - + private let inlineCommentExecutor: (_ comment: String, _ filePath: String, _ lineNumber: Int) -> Void private let normalCommentExecutor: (_ comment: String) -> Void - + private let inlineWarningExecutor: (_ comment: String, _ filePath: String, _ lineNumber: Int) -> Void private let normalWarningExecutor: (_ comment: String) -> Void - + private let inlineFailureExecutor: (_ comment: String, _ filePath: String, _ lineNumber: Int) -> Void private let normalFailureExecutor: (_ comment: String) -> Void - + init( workingDirectoryPath: String, modifiedFiles: [String], @@ -48,108 +47,104 @@ public struct Kantoku { self.inlineFailureExecutor = inlineFailureExecutor self.normalFailureExecutor = normalFailureExecutor } - } extension Kantoku { - func markdown(_ comment: String) { markdownCommentExecutor(comment) } - + func comment(_ comment: String, to filePath: String, at lineNumber: Int) { inlineCommentExecutor(comment, filePath, lineNumber) } - + func comment(_ comment: String) { normalCommentExecutor(comment) } - + func warn(_ warning: String, to filePath: String, at lineNumber: Int) { inlineWarningExecutor(warning, filePath, lineNumber) } - + func warn(_ warning: String) { normalWarningExecutor(warning) } - + func fail(_ failure: String, to filePath: String, at lineNumber: Int) { inlineFailureExecutor(failure, filePath, lineNumber) } - + func fail(_ failure: String) { normalFailureExecutor(failure) } - } - - extension Kantoku { - private func postIssuesIfNeeded(from resultFile: XCResultFile, configuration: XCResultParsingConfiguration) { - if configuration.needsIssues { - guard let issues = resultFile.getInvocationRecord()?.issues else { warn("Failed to get invocation record from \(resultFile.url.absoluteString)") return } if configuration.parseBuildWarnings { - let filteredSummaries = summaries(of: issues.warningSummaries, filteredBy: configuration.reportingFileType) + let filteredSummaries = summaries(of: issues.warningSummaries, filteredBy: configuration.reportingFileType) post(filteredSummaries, as: .warning) } - + if configuration.parseBuildErrors { post(issues.errorSummaries, as: .failure) } - + if configuration.parseAnalyzerWarnings { post(issues.analyzerWarningSummaries, as: .warning) } - + if configuration.parseTestFailures { post(issues.testFailureSummaries, as: .failure) } - } - } - + private func postCoverageIfNeeded(from resultFile: XCResultFile, configuration: XCResultParsingConfiguration) { - if let coverageAcceptanceDecision = configuration.codeCoverageRequirement.acceptanceDecision { - guard let coverage = resultFile.getCodeCoverage() else { - warn("Failed to get coverage from \(resultFile.url.absoluteString)") + if configuration.failIfCoverageUnavailable { + fail("Failed to get coverage from \(resultFile.url.absoluteString)") + } else { + warn("Failed to get coverage from \(resultFile.url.absoluteString)") + } + return } - - post(coverage, as: coverageAcceptanceDecision) - + let excludeCoverageTarget = configuration.excludeCoverageTarget + [.regex("*Tests$")] + var relaventTestCoverage = coverage.filterTargets(excludedTargets: excludeCoverageTarget) + relaventTestCoverage = coverage.filterTarget(excludeFiles: configuration.excludeCoverageForFiles) + let files: [XCResultParsingConfiguration.RelativeFilePath] + if configuration.showCoverageForChangedFiles { + files = (createdFiles + modifiedFiles) + + } else { + files = [] + } + post(relaventTestCoverage, for: files, as: coverageAcceptanceDecision) } - } - + public func parseXCResultFile(at filePath: String, configuration: XCResultParsingConfiguration) { - let resultFile = XCResultFile(url: .init(fileURLWithPath: filePath)) - + postIssuesIfNeeded(from: resultFile, configuration: configuration) postCoverageIfNeeded(from: resultFile, configuration: configuration) - } - } extension XCResultParsingConfiguration.CodeCoverageRequirement { - var acceptanceDecision: ((Double) -> Kantoku.CoverageAcceptance)? { switch self { case .none: return nil - + case .required(let threshold): return { coverage in if coverage >= threshold.recommended { @@ -162,13 +157,10 @@ extension XCResultParsingConfiguration.CodeCoverageRequirement { } } } - } extension Kantoku { - private func summaries(of summaries: [T], filteredBy fileType: XCResultParsingConfiguration.ReportingFileType) -> [T] { - let filteringPredicate: (XCResultParsingConfiguration.RelativeFilePath) -> Bool switch fileType { @@ -188,7 +180,5 @@ extension Kantoku { } return filteringPredicate(relativePath.filePath) } - } - } diff --git a/Sources/DangerSwiftKantoku/XCResultParsingConfiguration.swift b/Sources/DangerSwiftKantoku/XCResultParsingConfiguration.swift index 3af2be7..4e1382b 100644 --- a/Sources/DangerSwiftKantoku/XCResultParsingConfiguration.swift +++ b/Sources/DangerSwiftKantoku/XCResultParsingConfiguration.swift @@ -7,6 +7,20 @@ import Foundation +public enum ExcludedTarget: Equatable { + case exact(String) + case regex(String) + + func matches(string: String) -> Bool { + switch self { + case let .exact(needle): + return string == needle + case let .regex(regex): + return string.range(of: regex, options: .regularExpression) != nil + } + } +} + public struct XCResultParsingConfiguration { public typealias RelativeFilePath = String @@ -34,24 +48,37 @@ public struct XCResultParsingConfiguration { public var parseBuildErrors: Bool public var parseAnalyzerWarnings: Bool public var parseTestFailures: Bool - - public var codeCoverageRequirement: CodeCoverageRequirement public var reportingFileType: ReportingFileType - + + // code coverage + public var codeCoverageRequirement: CodeCoverageRequirement + public var excludeCoverageTarget: [ExcludedTarget] + public var excludeCoverageForFiles: ((RelativeFilePath) -> Bool) + public var failIfCoverageUnavailable: Bool + public var showCoverageForChangedFiles: Bool + public init( parseBuildWarnings: Bool = true, parseBuildErrors: Bool = true, parseAnalyzerWarnings: Bool = true, parseTestFailures: Bool = true, + reportingFileType: ReportingFileType = .all, + shouldFailIfCoverageUnavailable: Bool = false, codeCoverageRequirement: CodeCoverageRequirement = .required(.init(acceptable: 0, recommended: 0.6)), - reportingFileType: ReportingFileType = .all + excludeCoverageTarget: [ExcludedTarget] = [], + showCoverageForChangedFiles: Bool = true, + excludeCoverageForFiles: @escaping ((RelativeFilePath) -> Bool) = { _ in return false } ) { self.parseBuildWarnings = parseBuildWarnings self.parseBuildErrors = parseBuildErrors self.parseAnalyzerWarnings = parseAnalyzerWarnings self.parseTestFailures = parseTestFailures - self.codeCoverageRequirement = codeCoverageRequirement self.reportingFileType = reportingFileType + self.codeCoverageRequirement = codeCoverageRequirement + self.failIfCoverageUnavailable = shouldFailIfCoverageUnavailable + self.excludeCoverageTarget = excludeCoverageTarget + self.showCoverageForChangedFiles = showCoverageForChangedFiles + self.excludeCoverageForFiles = excludeCoverageForFiles } }