【问题标题】:How to get Xcode server Code coverage api JSON response如何获取 Xcode 服务器代码覆盖率 API JSON 响应
【发布时间】:2017-07-19 09:20:07
【问题描述】:

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

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

【问题讨论】:

    标签: ios code-coverage xcode-server


    【解决方案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 框架。我将使用这个确切的解决方案添加代码覆盖率端点。

    【讨论】:

    • 我正在尝试在基于角度/离子的 Web 应用程序中使用此代码覆盖率 API 以将其显示在仪表板中。我需要这个 JSON 数据,而不是在我的 iOS 应用程序中。在这种情况下我应该怎么做?我是否应该让我的网络开发人员下载这个 .bz2 并将其转换为 JSON 以显示数据?
    • 您可以使用 CompressJS (github.com/cscott/compressjs) 之类的东西在 javascript 中进行解压缩。解压缩数据后,您应该拥有可以与之交互的有效 JSON。请记住,代码覆盖率 API 将为任何没有数据的集成返回 404 状态代码。
    猜你喜欢
    • 2016-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多