-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathXCodeSummary.swift
144 lines (119 loc) · 5.55 KB
/
XCodeSummary.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import Foundation
import Danger
/// A filter that can be used to hide specific results based on certain conditions.
public typealias ResultsFilter = (Result) -> Bool
/// Danger-Swift plugin that adds build errors, warnings and unit tests results generated from xcodebuild to your Danger report
/// Requires xcpretty-json-formatter
public final class XCodeSummary {
private enum WarningKeys: String {
case warnings
case ldWarning = "ld_warnings"
case compileWarnings = "compile_warnings"
}
private enum ErrorKeys: String {
case errors
case compileErrors = "compile_errors"
case fileMissing = "file_missing_errors"
case undefinedSymbols = "undefined_symbols_errors"
case duplicatedSymbols = "duplicate_symbols_errors"
case testFailures = "tests_failures"
}
private enum MessageKeys: String {
case testSummary = "tests_summary_messages"
}
lazy var warnings: [Result] = {
let warningMessages: [String] = json[WarningKeys.warnings] ?? []
let ldWarningMessages: [String] = json[WarningKeys.ldWarning] ?? []
let compileWarnings: [[String:Any]] = json[WarningKeys.compileWarnings] ?? []
return warningMessages.map { Result(message: $0, category: .warning) } +
ldWarningMessages.map { Result(message: $0, category: .warning) } +
compileWarnings.compactMap { try? CompilerMessageParser.parseMessage(messageJSON: $0, category: .warning) }
}()
/// Number of warnings generated during the build
public var warningsCount: Int {
return warnings.count
}
lazy var errors: [Result] = {
let errors: [String] = json[ErrorKeys.errors] ?? []
let compileErrors: [[String:Any]] = json[ErrorKeys.compileErrors] ?? []
let missingFiles: [[String:Any]] = json[ErrorKeys.fileMissing] ?? []
let undefinedSymbols: [[String:Any]] = json[ErrorKeys.undefinedSymbols] ?? []
let duplicatedSymbols: [[String:Any]] = json[ErrorKeys.duplicatedSymbols] ?? []
let failedTests: [String:[[String:Any]]] = json[ErrorKeys.testFailures] ?? [:]
var result = errors.map { Result(message: $0, category: .error) }
result += compileErrors.compactMap { try? CompilerMessageParser.parseMessage(messageJSON: $0, category: .error) }
result += missingFiles.compactMap { MissingFileErrorParser.parseMissingFileError(missingFileErrorJSON: $0) }
result += undefinedSymbols.map { SymbolsErrorsParser.parseUndefinedSymbols(json: $0) }
result += duplicatedSymbols.map { SymbolsErrorsParser.parseDuplicatedSymbols(json: $0) }
result += failedTests.flatMap { (key, value) in
return value.compactMap {
try? TestFailuresParser.parseTest(testJSON: $0, testSuite: key)
}
}
return result
}()
/// Number of errors generated during the build
public var errorsCount: Int {
return errors.count
}
lazy var messages: [Result] = {
let messages: [String] = json[MessageKeys.testSummary] ?? []
return messages.map { Result(message: $0.trimmingCharacters(in: .whitespacesAndNewlines), category: .message) }
}()
private let json: [String:Any]
private let dsl: DangerDSL
private let resultsFilter: ResultsFilter?
init(json: [String:Any], dsl: DangerDSL = Danger(), resultsFilter: ResultsFilter? = nil) {
self.json = json
self.dsl = dsl
self.resultsFilter = resultsFilter
}
public convenience init(filePath: String, dsl: DangerDSL = Danger(), resultsFilter: ResultsFilter? = nil) {
guard let content = try? String(contentsOfFile: filePath),
let data = content.data(using: .utf8) else {
fatalError("Report not found")
}
guard let any = try? JSONSerialization.jsonObject(with: data, options: .allowFragments),
let json = any as? [String:Any] else {
fatalError("Report file is not a valid json")
}
self.init(json: json, dsl: dsl, resultsFilter: resultsFilter)
}
/// Shows all build errors, warnings and unit tests results generated from `xcodebuild` or `Swift Package Manager`
public func report() {
warnings.filter(using: resultsFilter).removingDuplicates().forEach {
if let file = $0.file,
let line = $0.line {
dsl.warn(message: $0.message, file: file, line: line)
} else {
dsl.warn($0.message)
}
}
errors.filter(using: resultsFilter).removingDuplicates().forEach {
if let file = $0.file,
let line = $0.line {
dsl.fail(message: $0.message, file: file, line: line)
} else {
dsl.fail($0.message)
}
}
messages.filter(using: resultsFilter).removingDuplicates().forEach { dsl.message($0.message) }
}
}
extension Dictionary {
subscript<T: RawRepresentable, R>(rawRappresentable: T) -> R? where T.RawValue == Key {
return self[rawRappresentable.rawValue] as? R
}
}
extension Array where Element == Result {
func filter(using resultsFilter: ResultsFilter?) -> [Element] {
guard let resultsFilter = resultsFilter else { return self }
return self.filter(resultsFilter)
}
func removingDuplicates() -> [Element] {
var addedDict = [Element: Bool]()
return filter {
addedDict.updateValue(true, forKey: $0) == nil
}
}
}