From eb14925efbc728a0b04d62970c615c2d13a231fd Mon Sep 17 00:00:00 2001 From: Ben Yohay Date: Mon, 10 Jan 2022 13:49:08 +0200 Subject: [PATCH] XCMetrics client: Support for sending only the log of the current build. If the flag is set, Logs found in the logs directory other than the log of the current build will be ignored. Previously Cached requests are still uploaded. --- .../MetricsUploaderControllerFactory.swift | 5 +++-- .../Mobius/Domain/MetricsUploaderLoopTypes.swift | 11 +++++++++-- .../Effect Handlers/CacheLogsEffectHandler.swift | 11 ++++++++--- .../Utils/MetricsUploaderModel+Utils.swift | 3 ++- Sources/XCMetricsClient/XCMetrics.swift | 8 +++++++- .../CacheLogsEffectHandlerTests.swift | 16 +++++++++++++++- .../MetricsUploaderLogicTests.swift | 3 ++- 7 files changed, 46 insertions(+), 11 deletions(-) diff --git a/Sources/XCMetricsClient/Mobius/Domain/MetricsUploaderControllerFactory.swift b/Sources/XCMetricsClient/Mobius/Domain/MetricsUploaderControllerFactory.swift index d51f0ca..d01dc70 100644 --- a/Sources/XCMetricsClient/Mobius/Domain/MetricsUploaderControllerFactory.swift +++ b/Sources/XCMetricsClient/Mobius/Domain/MetricsUploaderControllerFactory.swift @@ -37,14 +37,15 @@ enum ControllerFactory { isCI: command.isCI, plugins: plugins, skipNotes: command.skipNotes, - truncLargeIssues: command.truncLargeIssues + truncLargeIssues: command.truncLargeIssues, + uploadCurrentLogOnly: command.uploadCurrentLogOnly ) let initEffect = MetricsUploaderEffect.findLogs(buildDirectory: model.buildDirectory, timeout: model.timeout) let logManager = LogManagerImplementation(projectName: model.projectName) let effectRouter = EffectRouter() .routeCase(MetricsUploaderEffect.findLogs).to(LogsFinderEffectHandler(logManager: logManager)) - .routeCase(MetricsUploaderEffect.cacheLogs).to(CacheLogsEffectHandler(logManager: logManager)) + .routeCase(MetricsUploaderEffect.cacheLogs).to(CacheLogsEffectHandler(logManager: logManager, uploadCurrentLogOnly: command.uploadCurrentLogOnly)) .routeCase(MetricsUploaderEffect.appendMetadata).to(AddMetadataEffectHandler()) .routeCase(MetricsUploaderEffect.executePlugins).to(ExecutePluginsEffectHandler()) .routeCase(MetricsUploaderEffect.uploadLogs).to(UploadMetricsEffectHandler()) diff --git a/Sources/XCMetricsClient/Mobius/Domain/MetricsUploaderLoopTypes.swift b/Sources/XCMetricsClient/Mobius/Domain/MetricsUploaderLoopTypes.swift index 0d37611..b54565a 100644 --- a/Sources/XCMetricsClient/Mobius/Domain/MetricsUploaderLoopTypes.swift +++ b/Sources/XCMetricsClient/Mobius/Domain/MetricsUploaderLoopTypes.swift @@ -45,7 +45,9 @@ struct MetricsUploaderModel: Equatable, Hashable { /// If true, the Notes found in the log won't be inserted into the database let skipNotes: Bool /// If true, individual tasks with more than 100 issues, will get their issues truncated to a 100 - let truncLargeIssues:Bool + let truncLargeIssues: Bool + /// If true, only the current log will be uploaded if it's found. If it isn't found no logs will be uploaded. + let uploadCurrentLogOnly: Bool init( buildDirectory: String, @@ -58,7 +60,8 @@ struct MetricsUploaderModel: Equatable, Hashable { parsedRequests: Set = Set(), awaitingParsingLogResponses: Int = 0, skipNotes: Bool = false, - truncLargeIssues: Bool + truncLargeIssues: Bool, + uploadCurrentLogOnly: Bool ) { self.buildDirectory = buildDirectory self.projectName = projectName @@ -71,6 +74,7 @@ struct MetricsUploaderModel: Equatable, Hashable { self.awaitingParsingResultsCount = awaitingParsingLogResponses self.skipNotes = skipNotes self.truncLargeIssues = truncLargeIssues + self.uploadCurrentLogOnly = uploadCurrentLogOnly } init() { @@ -85,6 +89,7 @@ struct MetricsUploaderModel: Equatable, Hashable { self.awaitingParsingResultsCount = 0 self.skipNotes = false self.truncLargeIssues = false + self.uploadCurrentLogOnly = false } } @@ -100,6 +105,8 @@ extension MetricsUploaderModel: CustomDebugStringConvertible { parsedRequests: \(parsedRequests.count), awaitingParsingLogResponses: \(awaitingParsingResultsCount) skipNotes: \(skipNotes) + truncLargeIssues: \(truncLargeIssues) + uploadCurrentLogOnly: \(uploadCurrentLogOnly) """ } } diff --git a/Sources/XCMetricsClient/Mobius/Effect Handlers/CacheLogsEffectHandler.swift b/Sources/XCMetricsClient/Mobius/Effect Handlers/CacheLogsEffectHandler.swift index 7279db1..17894bc 100644 --- a/Sources/XCMetricsClient/Mobius/Effect Handlers/CacheLogsEffectHandler.swift +++ b/Sources/XCMetricsClient/Mobius/Effect Handlers/CacheLogsEffectHandler.swift @@ -26,16 +26,21 @@ struct CacheLogsEffectHandler: EffectHandler { private let logManager: LogManager private let logCopyRetries = 5 + private let uploadCurrentLogOnly: Bool - init(logManager: LogManager) { + init(logManager: LogManager, uploadCurrentLogOnly: Bool) { self.logManager = logManager + self.uploadCurrentLogOnly = uploadCurrentLogOnly } func handle(_ effectParameters: (currentLog: URL?, previousLogs: Set, cachedLogs: Set, projectName: String), _ callback: EffectCallback) -> Disposable { do { - // Cache other logs that Xcode produced. - var cachedLogsURLs = try logManager.cacheLogs(effectParameters.previousLogs, cachedLogs: effectParameters.cachedLogs, retries: 0) + var cachedLogsURLs: Set = [] + if (!uploadCurrentLogOnly) { + // Cache other logs that Xcode produced. + cachedLogsURLs = try logManager.cacheLogs(effectParameters.previousLogs, cachedLogs: effectParameters.cachedLogs, retries: 0) + } // Cache currentLog separately, to keep track of its cached location. var cachedCurrentLogURLs: Set = [] if let currentLog = effectParameters.currentLog { diff --git a/Sources/XCMetricsClient/Utils/MetricsUploaderModel+Utils.swift b/Sources/XCMetricsClient/Utils/MetricsUploaderModel+Utils.swift index f6a4634..4b31894 100644 --- a/Sources/XCMetricsClient/Utils/MetricsUploaderModel+Utils.swift +++ b/Sources/XCMetricsClient/Utils/MetricsUploaderModel+Utils.swift @@ -36,7 +36,8 @@ extension MetricsUploaderModel { parsedRequests: parsedRequests ?? self.parsedRequests, awaitingParsingLogResponses: awaitingParsingLogResponses ?? self.awaitingParsingResultsCount, skipNotes: self.skipNotes, - truncLargeIssues: self.truncLargeIssues + truncLargeIssues: self.truncLargeIssues, + uploadCurrentLogOnly: self.uploadCurrentLogOnly ) } } diff --git a/Sources/XCMetricsClient/XCMetrics.swift b/Sources/XCMetricsClient/XCMetrics.swift index e9d0cc3..5bd053a 100644 --- a/Sources/XCMetricsClient/XCMetrics.swift +++ b/Sources/XCMetricsClient/XCMetrics.swift @@ -74,6 +74,7 @@ struct Command { let skipNotes: Bool let additionalHeaders: [String: String] let truncLargeIssues: Bool + let uploadCurrentLogOnly: Bool } @@ -124,6 +125,10 @@ public struct XCMetrics: ParsableCommand { @Option(name: [.customLong("truncateLargeIssues")], help: "If a task have more than a 100 issues (Warnings, Notes and/or Errors), the parser will truncate them to a 100") public var truncLargeIssues: Bool = false + /// If only the log of the current build should be uploaded. + @Option(name: [.customLong("uploadCurrentLogOnly")], help: "If only the log of the current build should be uploaded") + public var uploadCurrentLogOnly: Bool = false + private static let loop = XCMetricsLoop() /// The default initializer for the `XCMetrics` object. @@ -205,7 +210,8 @@ public struct XCMetrics: ParsableCommand { additionalHeaders: authorization.map { (key, value) in [key: value] } ?? [:], - truncLargeIssues: truncLargeIssues + truncLargeIssues: truncLargeIssues, + uploadCurrentLogOnly: uploadCurrentLogOnly ) return command } diff --git a/Tests/XCMetricsTests/Effect Handlers/CacheLogsEffectHandlerTests.swift b/Tests/XCMetricsTests/Effect Handlers/CacheLogsEffectHandlerTests.swift index ad24374..d659f8a 100644 --- a/Tests/XCMetricsTests/Effect Handlers/CacheLogsEffectHandlerTests.swift +++ b/Tests/XCMetricsTests/Effect Handlers/CacheLogsEffectHandlerTests.swift @@ -110,7 +110,7 @@ final class CacheLogsEffectHandlerTests: XCTestCase { override func setUp() { super.setUp() - effectHandler = CacheLogsEffectHandler(logManager: mockLogManager) + effectHandler = CacheLogsEffectHandler(logManager: mockLogManager, uploadCurrentLogOnly: false) effectCallback = EffectCallback( onSend: { event in if let send = self.send { @@ -132,6 +132,20 @@ final class CacheLogsEffectHandlerTests: XCTestCase { XCTAssertTrue(effectCallback.ended) } + func testCacheLogsNotCachesPreviousLogsIfUploadCurrentLogOnly() { + effectHandler = CacheLogsEffectHandler(logManager: mockLogManager, uploadCurrentLogOnly: true) + send = { event in + if case .logsCached(let currentLog, let previousLogs, _) = event { + XCTAssertNil(currentLog) + XCTAssertEqual(previousLogs, []) + } else { + XCTFail("Expected .logsCached, got: \(event)") + } + } + _ = effectHandler.handle((currentLog: nil, previousLogs: mockLogManager.xcodeLogsURL, cachedLogs: mockLogManager.cachedLogsURL, projectName: "Project Name"), effectCallback) + XCTAssertTrue(effectCallback.ended) + } + func testCacheLogsCachesCurrentLog() { let currentLogURL = try! TemporaryFile.newFile(prefix: "log1", suffix: ".xcactivitylog").url var receivedEvent: MetricsUploaderEvent? diff --git a/Tests/XCMetricsTests/MetricsUploaderLogicTests.swift b/Tests/XCMetricsTests/MetricsUploaderLogicTests.swift index b61f8a6..3c18ca9 100644 --- a/Tests/XCMetricsTests/MetricsUploaderLogicTests.swift +++ b/Tests/XCMetricsTests/MetricsUploaderLogicTests.swift @@ -51,7 +51,8 @@ class MetricsUploaderLogicTests: XCTestCase { isCI: false, plugins: [], skipNotes: false, - truncLargeIssues: false) + truncLargeIssues: false, + uploadCurrentLogOnly: false) func testInitiator() { let initEffect = MetricsUploaderEffect.findLogs(buildDirectory: initial.buildDirectory, timeout: 1)