Skip to content

Commit

Permalink
Add withErrorReporting (#143)
Browse files Browse the repository at this point in the history
* Add `withErrorReporting`

It's common to write the following boilerplate when working with code
that can throw errors:

```swift
do {
  try work()
} catch {
  reportIssue(error)
}
```

Let's extract this pattern to a helper that can save at least some
boilerplate:

```swift
withErrorReporting {
  try work()
}
```

Or even make it a 1-liner in some cases:

```swift
withErrorReporting(catching: work)
```

* Bump Wasm CI

* wip

* add test

* wip

* Disable Wasm tests for now

* wip

---------

Co-authored-by: Brandon Williams <[email protected]>
  • Loading branch information
stephencelis and mbrandonw authored Jan 29, 2025
1 parent d502282 commit adadb00
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 18 deletions.
30 changes: 12 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,28 +95,22 @@ jobs:
run: make CONFIG=${{ matrix.config }} build-for-static-stdlib

wasm:
name: SwiftWasm
name: Wasm
runs-on: ubuntu-latest
strategy:
matrix:
toolchain:
- wasm-5.9.2-RELEASE
- wasm-5.10.0-RELEASE
steps:
- name: Cache toolchains
uses: actions/cache@v3
with:
path: ~/Library/Developer/Toolchains
key: ${{ matrix.toolchain }}
- uses: actions/checkout@v4
- uses: bytecodealliance/actions/wasmtime/setup@v1
- uses: swiftwasm/setup-swiftwasm@v1
with:
swift-version: ${{ matrix.toolchain }}
- name: Build tests
run: swift build --triple wasm32-unknown-wasi --build-tests -Xlinker -z -Xlinker stack-size=$((1024 * 1024))
- name: Run tests
run: wasmtime .build/debug/xctest-dynamic-overlayPackageTests.wasm
- name: Install Swift and Swift SDK for WebAssembly
run: |
PREFIX=/opt/swift
set -ex
curl -f -o /tmp/swift.tar.gz "https://download.swift.org/swift-6.0.2-release/ubuntu2204/swift-6.0.2-RELEASE/swift-6.0.2-RELEASE-ubuntu22.04.tar.gz"
sudo mkdir -p $PREFIX; sudo tar -xzf /tmp/swift.tar.gz -C $PREFIX --strip-component 1
$PREFIX/usr/bin/swift sdk install https://github.com/swiftwasm/swift/releases/download/swift-wasm-6.0.2-RELEASE/swift-wasm-6.0.2-RELEASE-wasm32-unknown-wasi.artifactbundle.zip --checksum 6ffedb055cb9956395d9f435d03d53ebe9f6a8d45106b979d1b7f53358e1dcb4
echo "$PREFIX/usr/bin" >> $GITHUB_PATH
- name: Build
run: swift build --swift-sdk wasm32-unknown-wasi --build-tests -Xlinker -z -Xlinker stack-size=$((1024 * 1024))

windows:
name: Windows
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ``IssueReporting/withErrorReporting(_:to:fileID:filePath:line:column:catching:)-89omf``

## Topics

### Overloads

- ``withErrorReporting(_:to:fileID:filePath:line:column:catching:)-3dh1h``
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ that ship in the same target as the library itself.

- ``reportIssue(_:fileID:filePath:line:column:)``
- ``withExpectedIssue(_:isIntermittent:fileID:filePath:line:column:_:)-9pinm``
- ``withErrorReporting(_:to:fileID:filePath:line:column:catching:)-89omf``

### Issue reporters

Expand Down
93 changes: 93 additions & 0 deletions Sources/IssueReporting/ErrorReporting.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/// Evaluates a throwing closure and automatically catches and reports any error thrown.
///
/// - Parameters:
/// - message: A message describing the expectation.
/// - reporters: Issue reporters to notify during the operation.
/// - fileID: The source `#fileID` associated with the error reporting.
/// - filePath: The source `#filePath` associated with the error reporting.
/// - line: The source `#line` associated with the error reporting.
/// - column: The source `#column` associated with the error reporting.
/// - body: A synchronous operation.
/// - Returns: The optional result of the operation, or `nil` if an error was thrown.
@_transparent
public func withErrorReporting<R>(
_ message: @autoclosure () -> String? = nil,
to reporters: [any IssueReporter]? = nil,
fileID: StaticString = #fileID,
filePath: StaticString = #filePath,
line: UInt = #line,
column: UInt = #column,
catching body: () throws -> R
) -> R? {
if let reporters {
return withIssueReporters(reporters) {
do {
return try body()
} catch {
reportIssue(
error,
message(),
fileID: fileID,
filePath: filePath,
line: line,
column: column
)
return nil
}
}
} else {
do {
return try body()
} catch {
reportIssue(
error,
message(),
fileID: fileID,
filePath: filePath,
line: line,
column: column
)
return nil
}
}
}

/// Evaluates a throwing closure and automatically catches and reports any error thrown.
///
/// - Parameters:
/// - message: A message describing the expectation.
/// - reporters: Issue reporters to notify during the operation.
/// - fileID: The source `#fileID` associated with the error reporting.
/// - filePath: The source `#filePath` associated with the error reporting.
/// - line: The source `#line` associated with the error reporting.
/// - column: The source `#column` associated with the error reporting.
/// - body: An asynchronous operation.
/// - Returns: The optional result of the operation, or `nil` if an error was thrown.
@_transparent
public func withErrorReporting<R>(
_ message: @autoclosure () -> String? = nil,
to reporters: [any IssueReporter]? = nil,
fileID: StaticString = #fileID,
filePath: StaticString = #filePath,
line: UInt = #line,
column: UInt = #column,
catching body: () async throws -> R
) async -> R? {
if let reporters {
return await withIssueReporters(reporters) {
do {
return try await body()
} catch {
reportIssue(error, fileID: fileID, filePath: filePath, line: line, column: column)
return nil
}
}
} else {
do {
return try await body()
} catch {
reportIssue(error, fileID: fileID, filePath: filePath, line: line, column: column)
return nil
}
}
}
27 changes: 27 additions & 0 deletions Tests/IssueReportingTests/WithErrorReportingTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#if canImport(Testing)
import Testing
import IssueReporting

@Suite
struct WithErrorReportingTests {
@Test func basics() {
withKnownIssue {
withErrorReporting {
throw SomeError()
}
} matching: { issue in
issue.description == "Caught error: SomeError()"
}

withKnownIssue {
withErrorReporting("Failed") {
throw SomeError()
}
} matching: { issue in
issue.description == "Caught error: SomeError(): Failed"
}
}
}

private struct SomeError: Error {}
#endif

0 comments on commit adadb00

Please sign in to comment.