Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions Sources/XcbeautifyLib/OutputHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Foundation
package class OutputHandler {
let quiet: Bool
let quieter: Bool
let quieterAfterError: Bool
let isCI: Bool
let writer: (String) -> Void

Expand All @@ -26,31 +27,47 @@ package class OutputHandler {
/// Ref: https://github.com/cpisciotta/xcbeautify/pull/15
private var lastFormatted: String?

package init(quiet: Bool, quieter: Bool, isCI: Bool = false, _ writer: @escaping (String) -> Void) {
/// Tracks if an error has been encountered when using quieterAfterError mode
private var errorEncountered = false

package init(quiet: Bool, quieter: Bool, quieterAfterError: Bool = false, isCI: Bool = false, _ writer: @escaping (String) -> Void) {
self.quiet = quiet
self.quieter = quieter
self.quieterAfterError = quieterAfterError
self.isCI = isCI
self.writer = writer
}

package func write(_ type: OutputType, _ content: String?) {
guard let content else { return }

if !quiet, !quieter {
// Determine effective quiet/quieter mode
let effectiveQuiet = quiet || (quieterAfterError && errorEncountered)
let effectiveQuieter = quieter || (quieterAfterError && errorEncountered)

if !effectiveQuiet, !effectiveQuieter {
writer(content)
// Check after writing to activate quieter mode for next output
if quieterAfterError, type == .error {
errorEncountered = true
}
return
}

switch type {
case OutputType.warning:
if quieter { return }
if effectiveQuieter { return }
fallthrough
case OutputType.error:
if let last = lastFormatted {
writer(last)
lastFormatted = nil
}
writer(content)
// Check after writing to activate quieter mode for next output
if quieterAfterError, type == .error {
errorEncountered = true
}
case OutputType.issue:
writer(content)
case OutputType.result:
Expand Down
5 changes: 4 additions & 1 deletion Sources/xcbeautify/Xcbeautify.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ struct Xcbeautify: ParsableCommand {
@Flag(name: [.long, .customLong("qq", withSingleDash: true)], help: "Only print tasks that have errors.")
var quieter = false

@Flag(name: [.customShort("Q"), .long], help: "Switch to quieter mode after the first error is encountered.")
var quieterAfterError = false

@Flag(name: [.long], help: "Preserves unbeautified output lines.")
var preserveUnbeautified = false

Expand Down Expand Up @@ -89,7 +92,7 @@ struct Xcbeautify: ParsableCommand {
)
}

let output = OutputHandler(quiet: quiet, quieter: quieter, isCI: isCI) { print($0) }
let output = OutputHandler(quiet: quiet, quieter: quieter, quieterAfterError: quieterAfterError, isCI: isCI) { print($0) }
let junitReporter = JUnitReporter()

let parser = Parser()
Expand Down
58 changes: 58 additions & 0 deletions Tests/XcbeautifyLibTests/OutputHandlerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,62 @@ class OutputHandlerTests: XCTestCase {

XCTAssertEqual(collector, ["test started", "error", "test completed", "result"])
}

func testQuieterAfterErrorSwitchesToQuieterModeAfterFirstError() throws {
var collector: [String] = []
let sut = OutputHandler(quiet: false, quieter: false, quieterAfterError: true, isCI: false) { content in
collector.append(content)
}

// Before error, everything should be printed
sut.write(.task, "task 1")
sut.write(.warning, "warning 1")
sut.write(.result, "result 1")

XCTAssertEqual(collector, ["task 1", "warning 1", "result 1"])

// Encounter an error
sut.write(.error, "error 1")

XCTAssertEqual(collector, ["task 1", "warning 1", "result 1", "error 1"])

collector.removeAll()

// After error, should behave like quieter mode
sut.write(.task, "task 2")
sut.write(.warning, "warning 2") // Should be suppressed
sut.write(.error, "error 2") // Errors should still show (with task 2 banner)
sut.write(.result, "result 2") // Results should still show
sut.write(.undefined, "undefined") // Should be suppressed

// Note: task 2 appears because it's the banner for error 2
XCTAssertEqual(collector, ["task 2", "error 2", "result 2"])
}

func testQuieterAfterErrorDoesNotAffectNormalQuietMode() throws {
var collector: [String] = []
let sut = OutputHandler(quiet: true, quieter: false, quieterAfterError: true, isCI: false) { content in
collector.append(content)
}

// Should behave like quiet mode even before error
sut.write(.task, "task 1")
sut.write(.warning, "warning 1")
sut.write(.result, "result 1")

XCTAssertEqual(collector, ["task 1", "warning 1", "result 1"])

// After error, should still behave like quieter mode
sut.write(.error, "error 1")

collector.removeAll()

sut.write(.task, "task 2")
sut.write(.warning, "warning 2") // Should be suppressed after error
sut.write(.error, "error 2")
sut.write(.result, "result 2")

// Note: task 2 appears because it's the banner for error 2
XCTAssertEqual(collector, ["task 2", "error 2", "result 2"])
}
}