Skip to content

Commit

Permalink
Show logs in error (#1)
Browse files Browse the repository at this point in the history
* first draft

* unwritable file tests

* add swift 5.7 tests

* update pattern match for cross platform

* update swift install action

* fix tests

* linux error

Co-authored-by: Full Queue Developer <[email protected]>
  • Loading branch information
DanielSincere and Full Queue Developer authored Nov 4, 2022
1 parent 2a434c7 commit fc6bfa4
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 8 deletions.
10 changes: 7 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,22 @@ jobs:
swift: "5.5"
- os: macos-11.0
swift: "5.6"
- os: macos-11.0
swift: "5.7"
# difficult to get a macos 12 runner on GitHub
# - os: macos-12.0
# swift: "5.5"
# - os: macos-12.0
# swift: "5.6"
- os: ubuntu-20.04
- os: ubuntu-latest
swift: "5.5"
- os: ubuntu-20.04
- os: ubuntu-latest
swift: "5.6"
- os: ubuntu-latest
swift: "5.7"

steps:
- uses: fwal/setup-swift@v1.14.0
- uses: swift-actions/setup-swift@v1
with:
swift-version: ${{ matrix.swift }}
- run: swift --version
Expand Down
18 changes: 17 additions & 1 deletion Sources/Sh/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,27 @@ import Foundation

public enum Errors: Error, LocalizedError {
case unexpectedNilDataError

case errorWithLogInfo(String, underlyingError: Error)
case openingLogError(Error, underlyingError: Error)

public var errorDescription: String? {
switch self {
case .unexpectedNilDataError:
return "Expected data, but there wasn't any"
case .errorWithLogInfo(let logInfo, underlyingError: let underlyingError):
return """
An error occurred: \(underlyingError.localizedDescription)
Here is the contents of the log file:
\(logInfo)
"""
case .openingLogError(let error, underlyingError: let underlyingError):
return """
An error occurred: \(underlyingError.localizedDescription)
Also, an error occurred while attempting to open the log file: \(error.localizedDescription)
"""
}
}
}
30 changes: 26 additions & 4 deletions Sources/Sh/sh.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,35 @@ public func sh(_ sink: Sink,
switch sink {
case .terminal:
announce("Running `\(cmd)`")
case .file(let path):
announce("Running `\(cmd)`, logging to `\(path.blue)`")

try shq(sink, cmd, environment: environment, workingDirectory: workingDirectory)

case .null:
announce("Running `\(cmd)`, discarding output")

try shq(sink, cmd, environment: environment, workingDirectory: workingDirectory)


case .file(let path):
announce("Running `\(cmd)`, logging to `\(path.blue)`")
do {
try shq(sink, cmd, environment: environment, workingDirectory: workingDirectory)
} catch {
let underlyingError = error

let logResult = Result {
try String(contentsOfFile: path)
.trimmingCharacters(in: .whitespacesAndNewlines)
}

switch logResult {
case .success(let success):
throw Errors.errorWithLogInfo(success, underlyingError: underlyingError)
case .failure(let failure):
throw Errors.openingLogError(failure, underlyingError: underlyingError)
}
}
}

try shq(sink, cmd, environment: environment, workingDirectory: workingDirectory)
}

/// `Async`/`await` version
Expand Down
41 changes: 41 additions & 0 deletions Tests/ShTests/LogFileTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import XCTest
@testable import Sh

final class LogFileTests: XCTestCase {

func testSimple() throws {

do {
try sh(.file("/tmp/sh-test.log"), #"echo "simple" > /unknown/path/name"#)
XCTFail("Expected the above to throw an `Errors.errorWithLogInfo`")
} catch Errors.errorWithLogInfo(let logInfo, underlyingError: let underlyingError) {

XCTAssertTrue(logInfo.contains("/unknown/path/name"))

let terminationError = try XCTUnwrap(underlyingError as? TerminationError)

XCTAssertNotEqual(terminationError.status, 0)
XCTAssertEqual(terminationError.reason, "`regular exit`")
} catch {
XCTFail("Expected the above to throw an `Errors.errorWithLogInfo`, instead got an \(error)")
}
}

func testUnwritableLogfile() throws {
do {
try sh(.file("/missing/path/sh-test.log"), #"echo "simple" > /unknown/path/name"#)
} catch Errors.openingLogError(let logError, underlyingError: let underlyingError) {

#if os(Linux)
XCTAssertEqual(logError.localizedDescription, "The operation could not be completed. No such file or directory")
#else
XCTAssertEqual(logError.localizedDescription, "The file “sh-test.log” couldn’t be opened because there is no such file.")
#endif

XCTAssertTrue(underlyingError.localizedDescription.contains("CouldNotCreateFile error"))

} catch {
XCTFail("Expected an opening log error, but got \(error)")
}
}
}

0 comments on commit fc6bfa4

Please sign in to comment.