diff --git a/CHANGELOG.md b/CHANGELOG.md index dd226fa69..6a37a4b56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ ##### Enhancements +* Add Junit reporter. + [Matthew Ellis](https://github.com/matthewellis) + * LeadingWhitespaceRule is now auto correctable. [masters3d](https://github.com/masters3d) diff --git a/README.md b/README.md index 177009caf..46e7c8df4 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,7 @@ variable_name: - id - URL - GlobalAPIKey -reporter: "xcode" # reporter type (xcode, json, csv, checkstyle) +reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit) ``` #### Defining Custom Rules diff --git a/Source/SwiftLintFramework/Protocols/Reporter.swift b/Source/SwiftLintFramework/Protocols/Reporter.swift index f5aab87e7..8c055c77d 100644 --- a/Source/SwiftLintFramework/Protocols/Reporter.swift +++ b/Source/SwiftLintFramework/Protocols/Reporter.swift @@ -22,6 +22,8 @@ public func reporterFromString(string: String) -> Reporter.Type { return CSVReporter.self case CheckstyleReporter.identifier: return CheckstyleReporter.self + case JUnitReporter.identifier: + return JUnitReporter.self default: fatalError("no reporter with identifier '\(string)' available.") } diff --git a/Source/SwiftLintFramework/Reporters/JUnitReporter.swift b/Source/SwiftLintFramework/Reporters/JUnitReporter.swift new file mode 100644 index 000000000..c26d196e7 --- /dev/null +++ b/Source/SwiftLintFramework/Reporters/JUnitReporter.swift @@ -0,0 +1,30 @@ +// +// JUnitReporter.swift +// SwiftLint +// +// Created by Matthew Ellis on 25/05/2016. +// Copyright © 2016 Realm. All rights reserved. +// + +import Foundation + +public struct JUnitReporter: Reporter { + public static let identifier = "junit" + public static let isRealtime = false + + public var description: String { + return "Reports violations as JUnit XML." + } + + public static func generateReport(violations: [StyleViolation]) -> String { + return "\n" + + violations.map({ violation in + let fileName = violation.location.file ?? "" + let severity = violation.severity.rawValue.lowercaseString + ":\n" + let message = severity + "Line:" + String(violation.location.line ?? 0) + " " + return ["\n\t\n", + "" + message + "", + "\t"].joinWithSeparator("") + }).joinWithSeparator("") + "\n" + } +} diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index aae05b4ab..f86fcd2db 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -37,6 +37,7 @@ 3BDB224B1C345B4900473680 /* ProjectMock in Resources */ = {isa = PBXBuildFile; fileRef = 3BDB224A1C345B4900473680 /* ProjectMock */; }; 4DB7815E1CAD72BA00BC4723 /* LegacyCGGeometryFunctionsRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DB7815C1CAD690100BC4723 /* LegacyCGGeometryFunctionsRule.swift */; }; 4DCB8E7F1CBE494E0070FCF0 /* RegexHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCB8E7D1CBE43640070FCF0 /* RegexHelpers.swift */; }; + 57ED827B1CF656E3002B3513 /* JUnitReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57ED82791CF65183002B3513 /* JUnitReporter.swift */; }; 69F88BF71BDA38A6005E7CAE /* OpeningBraceRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692B1EB11BD7E00F00EAABFF /* OpeningBraceRule.swift */; }; 6C7045441C6ADA450003F15A /* SourceKitCrashTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C7045431C6ADA450003F15A /* SourceKitCrashTests.swift */; }; 6CB514E91C760C6900FA02C4 /* Structure+SwiftLint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CB514E81C760C6900FA02C4 /* Structure+SwiftLint.swift */; }; @@ -202,6 +203,7 @@ 4DCB8E7D1CBE43640070FCF0 /* RegexHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegexHelpers.swift; sourceTree = ""; }; 5499CA961A2394B700783309 /* Components.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Components.plist; sourceTree = ""; }; 5499CA971A2394B700783309 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 57ED82791CF65183002B3513 /* JUnitReporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JUnitReporter.swift; sourceTree = ""; }; 65454F451B14D73800319A6C /* ControlStatementRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControlStatementRule.swift; sourceTree = ""; }; 692B1EB11BD7E00F00EAABFF /* OpeningBraceRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpeningBraceRule.swift; sourceTree = ""; }; 692B60AB1BD8F2E700C7AA22 /* StatementPositionRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatementPositionRule.swift; sourceTree = ""; }; @@ -563,6 +565,7 @@ isa = PBXGroup; children = ( E8EA41161C2D1DBE004F9930 /* CheckstyleReporter.swift */, + 57ED82791CF65183002B3513 /* JUnitReporter.swift */, E86396CA1BADB519002C9E88 /* CSVReporter.swift */, E86396C81BADB2B9002C9E88 /* JSONReporter.swift */, E86396C41BADAC15002C9E88 /* XcodeReporter.swift */, @@ -899,6 +902,7 @@ 006ECFC41C44E99E00EF6364 /* LegacyConstantRule.swift in Sources */, E88DEA731B0984C400A66CB0 /* String+SwiftLint.swift in Sources */, E88198591BEA95F100333A11 /* LeadingWhitespaceRule.swift in Sources */, + 57ED827B1CF656E3002B3513 /* JUnitReporter.swift in Sources */, 24E17F721B14BB3F008195BE /* File+Cache.swift in Sources */, E80E018F1B92C1350078EB70 /* Region.swift in Sources */, E88198581BEA956C00333A11 /* FunctionBodyLengthRule.swift in Sources */, diff --git a/Tests/SwiftLintFramework/ReporterTests.swift b/Tests/SwiftLintFramework/ReporterTests.swift index 108ee355e..c11484270 100644 --- a/Tests/SwiftLintFramework/ReporterTests.swift +++ b/Tests/SwiftLintFramework/ReporterTests.swift @@ -78,4 +78,17 @@ class ReporterTests: XCTestCase { "" ) } + + func testJunitReporter() { + XCTAssertEqual( + JUnitReporter.generateReport(generateViolations()), + "\n\n" + + "\t\n" + + "warning:\nLine:1 " + + "\t\n" + + "\t\n" + + "error:\nLine:1 " + + "\t\n" + ) + } }