A type-safe Swift library for parsing Xcode .xcresult bundles and extracting build warnings, errors, and test failures in a structured format.
- Parse xcresult bundles: Extract structured data from Xcode result bundles
- Zero external dependencies: Uses only
xcrun xcresulttool(ships with Xcode) - Type-safe output: Strongly-typed Swift models with resilient decoding
- Async/await support: Modern Swift concurrency
- Forward compatible: Handles unknown enum values gracefully for future Xcode versions
- Swift 6.2+
- macOS 15+
- Xcode 16+
Add the following to your Package.swift:
dependencies: [
.package(url: "https://github.com/diogot/swift-xcresult-parser.git", from: "1.0.0")
]Then add XCResultParser to your target dependencies:
.target(name: "YourTarget", dependencies: ["XCResultParser"])import XCResultParser
let parser = XCResultParser(path: "path/to/test.xcresult")
let result = try await parser.parse()
// Access build issues
for issue in result.buildResults?.allIssues ?? [] {
print("\(issue.severity): \(issue.message)")
if let loc = issue.sourceLocation {
print(" at \(loc.file):\(loc.line)")
}
}
// Access test failures
for failure in result.testResults?.failures ?? [] {
print("FAIL: \(failure.testClass).\(failure.testName)")
print(" \(failure.message)")
}let parser = XCResultParser(path: "path/to/test.xcresult")
let buildResults = try await parser.parseBuildResults()
print("Warnings: \(buildResults.warningCount)")
print("Errors: \(buildResults.errorCount)")let parser = XCResultParser(path: "path/to/test.xcresult")
let testResults = try await parser.parseTestResults()
let summary = testResults.summary
print("Total: \(summary.totalCount)")
print("Passed: \(summary.passedCount)")
print("Failed: \(summary.failedCount)")The library normalizes source locations from two different xcresulttool formats:
// Build issues provide absolute paths
if let location = buildIssue.sourceLocation {
let relativePath = location.relativePath(from: "/path/to/repo")
print("\(relativePath):\(location.line)")
}
// Test failures provide filename and line
for failure in testResults.failures {
if let location = failure.sourceLocation {
print("\(location.file):\(location.line)")
}
}public final class XCResultParser: Sendable {
public init(path: String)
public func parse() async throws -> XCResult
public func parseBuildResults() async throws -> BuildResults
public func parseTestResults() async throws -> TestResults
}XCResult- Combined build and test resultsBuildResults- Build action results with warnings, errors, analyzer warningsBuildIssue- Individual build warning or error with source locationTestResults- Test execution results with device info and test node treeTestNode- Hierarchical test node (test plan, bundle, suite, case, etc.)TestFailure- Flattened test failure for easy reportingSourceLocation- File path, line, and optional columnTestResult- Test outcome (passed, failed, skipped, expectedFailure)TestNodeType- Node type in test hierarchySeverity- Issue severity level (notice, warning, failure)
MIT License - see LICENSE for details.