如何获得Xcode服务器代码覆盖api JSON响应

时间:2017-07-19 09:20:08

标签: ios code-coverage xcode-server

当我尝试通过传递集成ID而不是JSON响应来访问Xcode服务器代码覆盖API时,它直接下载.bz2文件。我想使用此API在我的自定义仪表板中显示文件明智的覆盖率报告。

有什么方法可以从这个API(https://developer.apple.com/library/content/documentation/Xcode/Conceptual/XcodeServerAPIReference/CodeCoverage.html)而不是.bz2文件中获得JSOn响应?

1 个答案:

答案 0 :(得分:1)

不幸的是,API只返回.bz2压缩的JSON文件。 即使指定了Accept = application / json。

的HTTP标头

解决此问题的唯一方法是解压缩数据以访问基础JSON。

以下是使用框架BZipCompression解压缩数据流的iOS / swift上的示例:

import Foundation
import BZipCompression

public class Coverage {
    public typealias CoverageCompletion = (_: Data?, _: Error?) -> Void

    public enum Errors: Error {
        case invalidURL
        case invalidResponse
        case invalidStatusCode
        case invalidData
    }

    static var session: URLSession {
        let session = URLSession(configuration: URLSessionConfiguration.default, delegate: LocalhostSessionDelegate.default, delegateQueue: nil)
        return session
    }

    static public func coverage(forIntegrationWithIdentifier identifier: String, completion: @escaping CoverageCompletion) {
        guard let url = URL(string: "https://localhost:20343/api/integrations/\(identifier)/coverage") else {
            completion(nil, Errors.invalidURL)
            return
        }

        let request = URLRequest(url: url)
        let task = session.dataTask(with: request) { (data, response, error) in
            guard error == nil else {
                completion(nil, error)
                return
            }

            guard let urlResponse = response as? HTTPURLResponse else {
                completion(nil, Errors.invalidResponse)
                return
            }

            guard urlResponse.statusCode == 200 else {
                completion(nil, Errors.invalidStatusCode)
                return
            }

            guard let d = data else {
                completion(nil, Errors.invalidData)
                return
            }

            var decompressedData: Data
            do {
                decompressedData = try self.decompress(data: d)
            } catch let decompressionError {
                completion(nil, decompressionError)
                return
            }

            completion(decompressedData, nil)
        }
        task.resume()
    }

    static internal func decompress(data: Data) throws -> Data {
        let decompressedData = try BZipCompression.decompressedData(with: data)

        guard let decompressedString = String(data: decompressedData, encoding: .utf8) else {
            throw Errors.invalidData
        }

        guard let firstBrace = decompressedString.range(of: "{") else {
           throw Errors.invalidData
        }

        guard let lastBrace = decompressedString.range(of: "}", options: .backwards, range: nil, locale: nil) else {
            throw Errors.invalidData
        }

        let range = decompressedString.index(firstBrace.lowerBound, offsetBy: 0)..<decompressedString.index(lastBrace.lowerBound, offsetBy: 1)
        let json = decompressedString.substring(with: range)

        guard let validData = json.data(using: .utf8) else {
            throw Errors.invalidData
        }

        return validData
    }
}

/// Class implementing the NSURLSessionDelegate which forcefully bypasses untrusted SSL Certificates.
public class LocalhostSessionDelegate: NSObject, URLSessionDelegate {
    static public var `default` = LocalhostSessionDelegate()

    // MARK: - NSURLSessionDelegate
    @objc open func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        guard challenge.previousFailureCount < 1 else {
            completionHandler(.cancelAuthenticationChallenge, nil)
            return
        }

        var credentials: URLCredential?
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            if let serverTrust = challenge.protectionSpace.serverTrust {
                credentials = URLCredential(trust: serverTrust)
            }
        }

        completionHandler(.useCredential, credentials)
    }
}

我注意到解压缩的数据通常包含无效的控制字符和有效JSON块开头和结尾的其他垃圾。 decompress()会在完成块中返回数据之前清除数据。

您可能希望在GitHub上查看我的swift XCServerAPI框架。我将使用这个精确的解决方案添加Code Coverage端点。