From 6b038679108f76d156417c89280e7521ecec9991 Mon Sep 17 00:00:00 2001 From: Coen ten Thije Boonkkamp Date: Sun, 2 Aug 2026 13:00:08 +0200 Subject: [PATCH 1/2] Converge traversal errors to C5 leaves --- Package.swift | 16 +++++++ ...Organization.Repositories.Client+all.swift | 23 +++++----- ...Hub.Organization.Repositories.Client.swift | 6 +-- ...Organization.Repositories.Page.Error.swift | 6 +++ ...tHub.Organization.Repositories.Page.swift} | 2 +- ...ization.Repositories.Traversal.Error.swift | 8 ++-- ...Hub.Repository.Stargazers.Client+all.swift | 21 ++++++---- .../GitHub.Repository.Stargazers.Client.swift | 6 +-- ...Hub.Repository.Stargazers.Page.Error.swift | 7 ++++ ...> GitHub.Repository.Stargazers.Page.swift} | 2 +- ...epository.Stargazers.Traversal.Error.swift | 8 ++-- .../GitHub.User.Repositories.Client+all.swift | 21 ++++++---- .../GitHub.User.Repositories.Client.swift | 6 +-- .../GitHub.User.Repositories.Page.Error.swift | 9 ++++ ...ft => GitHub.User.Repositories.Page.swift} | 2 +- ...ub.User.Repositories.Traversal.Error.swift | 8 ++-- Sources/GitHub/exports.swift | 2 + ...ganization.Repositories.Client Tests.swift | 27 +++++++----- ...b.Repository.Stargazers.Client Tests.swift | 42 ++++++++----------- ...itHub.User.Repositories.Client Tests.swift | 42 ++++++++----------- 20 files changed, 150 insertions(+), 114 deletions(-) create mode 100644 Sources/GitHub/GitHub.Organization.Repositories.Page.Error.swift rename Sources/GitHub/{GitHub.Organization.Repositories.Client.Page.swift => GitHub.Organization.Repositories.Page.swift} (89%) create mode 100644 Sources/GitHub/GitHub.Repository.Stargazers.Page.Error.swift rename Sources/GitHub/{GitHub.Repository.Stargazers.Client.Page.swift => GitHub.Repository.Stargazers.Page.swift} (89%) create mode 100644 Sources/GitHub/GitHub.User.Repositories.Page.Error.swift rename Sources/GitHub/{GitHub.User.Repositories.Client.Page.swift => GitHub.User.Repositories.Page.swift} (89%) diff --git a/Package.swift b/Package.swift index 5a76209..d80bb07 100644 --- a/Package.swift +++ b/Package.swift @@ -18,6 +18,14 @@ let package = Package( ) ], dependencies: [ + .package( + url: "https://github.com/swift-primitives/swift-async-primitives.git", + branch: "main" + ), + .package( + url: "https://github.com/swift-primitives/swift-either-primitives.git", + branch: "main" + ), .package( url: "https://github.com/swift-standards/swift-github-standard.git", branch: "main" @@ -27,6 +35,14 @@ let package = Package( .target( name: "GitHub", dependencies: [ + .product( + name: "Async Lifecycle Primitives", + package: "swift-async-primitives" + ), + .product( + name: "Either Primitives", + package: "swift-either-primitives" + ), .product( name: "GitHub Standard", package: "swift-github-standard" diff --git a/Sources/GitHub/GitHub.Organization.Repositories.Client+all.swift b/Sources/GitHub/GitHub.Organization.Repositories.Client+all.swift index 4318486..a56bb1e 100644 --- a/Sources/GitHub/GitHub.Organization.Repositories.Client+all.swift +++ b/Sources/GitHub/GitHub.Organization.Repositories.Client+all.swift @@ -4,7 +4,7 @@ extension GitHub.Organization.Repositories.Client { limit: GitHub.Organization.Repositories.Traversal.Limit, duplicate: GitHub.Organization.Repositories.Traversal.Duplicate, order: GitHub.Organization.Repositories.Traversal.Order - ) async throws(GitHub.Organization.Repositories.Traversal.Error) -> [GitHub.Repository + ) async throws(Either) -> [GitHub.Repository .Summary] { var repositories: [GitHub.Repository.Summary] = [] @@ -14,21 +14,24 @@ extension GitHub.Organization.Repositories.Client { var pages: UInt = 0 while let request = current { - guard !Task.isCancelled else { throw .cancellation } + guard !Task.isCancelled else { throw .left(.cancelled) } // swift-linter:disable:next raw value access // REASON: same-package implementation comparing against the // Traversal.Limit boundary type's own raw page count. - guard pages < limit.pages.rawValue else { throw .pages } - guard requests.insert(request).inserted else { throw .cycle } + guard pages < limit.pages.rawValue else { throw .right(.pages) } + guard requests.insert(request).inserted else { throw .right(.cycle) } - let page: Page - do throws(Failure) { + let page: GitHub.Organization.Repositories.Page + do throws(Either) { page = try await self.page(request) } catch { - throw .client(error) + switch error { + case .left(let error): throw .left(error) + case .right(let error): throw .right(.page(error)) + } } - guard !Task.isCancelled else { throw .cancellation } + guard !Task.isCancelled else { throw .left(.cancelled) } pages += 1 for repository in page.response.repositories { @@ -51,7 +54,7 @@ extension GitHub.Organization.Repositories.Client { case .reject: guard positions[repository.id] == nil else { - throw .duplicate(repository.id) + throw .right(.duplicate(repository.id)) } positions[repository.id] = repositories.endIndex repositories.append(repository) @@ -61,7 +64,7 @@ extension GitHub.Organization.Repositories.Client { // REASON: same-package implementation comparing against the // Traversal.Limit boundary type's own raw item count. guard UInt(repositories.count) <= limit.items.rawValue else { - throw .items + throw .right(.items) } } diff --git a/Sources/GitHub/GitHub.Organization.Repositories.Client.swift b/Sources/GitHub/GitHub.Organization.Repositories.Client.swift index 4ff1462..65c0b78 100644 --- a/Sources/GitHub/GitHub.Organization.Repositories.Client.swift +++ b/Sources/GitHub/GitHub.Organization.Repositories.Client.swift @@ -1,9 +1,9 @@ extension GitHub.Organization.Repositories { - public struct Client: Sendable { - public var page: @Sendable (Request) async throws(Failure) -> Page + public struct Client: Sendable { + public var page: @Sendable (Request) async throws(Either) -> Page public init( - page: @escaping @Sendable (Request) async throws(Failure) -> Page + page: @escaping @Sendable (Request) async throws(Either) -> Page ) { self.page = page } diff --git a/Sources/GitHub/GitHub.Organization.Repositories.Page.Error.swift b/Sources/GitHub/GitHub.Organization.Repositories.Page.Error.swift new file mode 100644 index 0000000..d3d0ecb --- /dev/null +++ b/Sources/GitHub/GitHub.Organization.Repositories.Page.Error.swift @@ -0,0 +1,6 @@ +extension GitHub.Organization.Repositories.Page { + public enum Error: Swift.Error, Sendable, Equatable, Hashable { + case transport + case malformedResponse + } +} diff --git a/Sources/GitHub/GitHub.Organization.Repositories.Client.Page.swift b/Sources/GitHub/GitHub.Organization.Repositories.Page.swift similarity index 89% rename from Sources/GitHub/GitHub.Organization.Repositories.Client.Page.swift rename to Sources/GitHub/GitHub.Organization.Repositories.Page.swift index 6104a5e..43837b5 100644 --- a/Sources/GitHub/GitHub.Organization.Repositories.Client.Page.swift +++ b/Sources/GitHub/GitHub.Organization.Repositories.Page.swift @@ -1,4 +1,4 @@ -extension GitHub.Organization.Repositories.Client { +extension GitHub.Organization.Repositories { public struct Page: Equatable, Sendable { public let response: GitHub.Organization.Repositories.Response public let next: GitHub.Organization.Repositories.Request? diff --git a/Sources/GitHub/GitHub.Organization.Repositories.Traversal.Error.swift b/Sources/GitHub/GitHub.Organization.Repositories.Traversal.Error.swift index 0ee25d3..bc37ada 100644 --- a/Sources/GitHub/GitHub.Organization.Repositories.Traversal.Error.swift +++ b/Sources/GitHub/GitHub.Organization.Repositories.Traversal.Error.swift @@ -1,13 +1,11 @@ extension GitHub.Organization.Repositories.Traversal { - public enum Error: Swift.Error, Sendable { - case cancellation - case client(Failure) + public enum Error: Swift.Error, Sendable { case cycle case duplicate(GitHub.Repository.ID) case items + case page(GitHub.Organization.Repositories.Page.Error) case pages } } -extension GitHub.Organization.Repositories.Traversal.Error: Equatable -where Failure: Equatable {} +extension GitHub.Organization.Repositories.Traversal.Error: Equatable {} diff --git a/Sources/GitHub/GitHub.Repository.Stargazers.Client+all.swift b/Sources/GitHub/GitHub.Repository.Stargazers.Client+all.swift index eaaf2c9..165b3be 100644 --- a/Sources/GitHub/GitHub.Repository.Stargazers.Client+all.swift +++ b/Sources/GitHub/GitHub.Repository.Stargazers.Client+all.swift @@ -2,7 +2,7 @@ extension GitHub.Repository.Stargazers.Client { public func all( _ request: GitHub.Repository.Stargazers.Request, limit: GitHub.Repository.Stargazers.Traversal.Limit - ) async throws(GitHub.Repository.Stargazers.Traversal.Error) + ) async throws(Either) -> [GitHub.Repository.Stargazers.Stargazer] { var stargazers: [GitHub.Repository.Stargazers.Stargazer] = [] @@ -11,21 +11,24 @@ extension GitHub.Repository.Stargazers.Client { var pages: UInt = 0 while let request = current { - guard !Task.isCancelled else { throw .cancellation } + guard !Task.isCancelled else { throw .left(.cancelled) } // swift-linter:disable:next raw value access // REASON: same-package traversal-limit boundary — the page counter // is compared against the limit newtype's own raw magnitude. - guard pages < limit.pages.rawValue else { throw .pages } - guard requests.insert(request).inserted else { throw .cycle } + guard pages < limit.pages.rawValue else { throw .right(.pages) } + guard requests.insert(request).inserted else { throw .right(.cycle) } - let page: Page - do throws(Failure) { + let page: GitHub.Repository.Stargazers.Page + do throws(Either) { page = try await self.page(request) } catch { - throw .client(error) + switch error { + case .left(let error): throw .left(error) + case .right(let error): throw .right(.page(error)) + } } - guard !Task.isCancelled else { throw .cancellation } + guard !Task.isCancelled else { throw .left(.cancelled) } pages += 1 stargazers.append(contentsOf: page.response.stargazers) @@ -33,7 +36,7 @@ extension GitHub.Repository.Stargazers.Client { // REASON: same-package traversal-limit boundary — the accumulated // item count is compared against the limit newtype's raw magnitude. guard UInt(stargazers.count) <= limit.items.rawValue else { - throw .items + throw .right(.items) } current = page.next } diff --git a/Sources/GitHub/GitHub.Repository.Stargazers.Client.swift b/Sources/GitHub/GitHub.Repository.Stargazers.Client.swift index 563edec..d75c0ef 100644 --- a/Sources/GitHub/GitHub.Repository.Stargazers.Client.swift +++ b/Sources/GitHub/GitHub.Repository.Stargazers.Client.swift @@ -1,9 +1,9 @@ extension GitHub.Repository.Stargazers { - public struct Client: Sendable { - public var page: @Sendable (Request) async throws(Failure) -> Page + public struct Client: Sendable { + public var page: @Sendable (Request) async throws(Either) -> Page public init( - page: @escaping @Sendable (Request) async throws(Failure) -> Page + page: @escaping @Sendable (Request) async throws(Either) -> Page ) { self.page = page } diff --git a/Sources/GitHub/GitHub.Repository.Stargazers.Page.Error.swift b/Sources/GitHub/GitHub.Repository.Stargazers.Page.Error.swift new file mode 100644 index 0000000..51cadbe --- /dev/null +++ b/Sources/GitHub/GitHub.Repository.Stargazers.Page.Error.swift @@ -0,0 +1,7 @@ +extension GitHub.Repository.Stargazers.Page { + public enum Error: Swift.Error, Sendable, Equatable, Hashable { + case transport + case rejected + case malformedResponse + } +} diff --git a/Sources/GitHub/GitHub.Repository.Stargazers.Client.Page.swift b/Sources/GitHub/GitHub.Repository.Stargazers.Page.swift similarity index 89% rename from Sources/GitHub/GitHub.Repository.Stargazers.Client.Page.swift rename to Sources/GitHub/GitHub.Repository.Stargazers.Page.swift index 6b92fb1..8bb1f80 100644 --- a/Sources/GitHub/GitHub.Repository.Stargazers.Client.Page.swift +++ b/Sources/GitHub/GitHub.Repository.Stargazers.Page.swift @@ -1,4 +1,4 @@ -extension GitHub.Repository.Stargazers.Client { +extension GitHub.Repository.Stargazers { public struct Page: Equatable, Sendable { public let response: GitHub.Repository.Stargazers.Response public let next: GitHub.Repository.Stargazers.Request? diff --git a/Sources/GitHub/GitHub.Repository.Stargazers.Traversal.Error.swift b/Sources/GitHub/GitHub.Repository.Stargazers.Traversal.Error.swift index 6367c94..7e5a99c 100644 --- a/Sources/GitHub/GitHub.Repository.Stargazers.Traversal.Error.swift +++ b/Sources/GitHub/GitHub.Repository.Stargazers.Traversal.Error.swift @@ -1,12 +1,10 @@ extension GitHub.Repository.Stargazers.Traversal { - public enum Error: Swift.Error, Sendable { - case cancellation - case client(Failure) + public enum Error: Swift.Error, Sendable { case cycle case items + case page(GitHub.Repository.Stargazers.Page.Error) case pages } } -extension GitHub.Repository.Stargazers.Traversal.Error: Equatable -where Failure: Equatable {} +extension GitHub.Repository.Stargazers.Traversal.Error: Equatable {} diff --git a/Sources/GitHub/GitHub.User.Repositories.Client+all.swift b/Sources/GitHub/GitHub.User.Repositories.Client+all.swift index 3db5a3f..6ef8d61 100644 --- a/Sources/GitHub/GitHub.User.Repositories.Client+all.swift +++ b/Sources/GitHub/GitHub.User.Repositories.Client+all.swift @@ -2,7 +2,7 @@ extension GitHub.User.Repositories.Client { public func all( _ request: GitHub.User.Repositories.Request, limit: GitHub.User.Repositories.Traversal.Limit - ) async throws(GitHub.User.Repositories.Traversal.Error) + ) async throws(Either) -> [GitHub.Repository.Metadata] { var repositories: [GitHub.Repository.Metadata] = [] @@ -11,21 +11,24 @@ extension GitHub.User.Repositories.Client { var pages: UInt = 0 while let request = current { - guard !Task.isCancelled else { throw .cancellation } + guard !Task.isCancelled else { throw .left(.cancelled) } // swift-linter:disable:next raw value access // REASON: same-package traversal-limit boundary — the page counter // is compared against the limit newtype's own raw magnitude. - guard pages < limit.pages.rawValue else { throw .pages } - guard requests.insert(request).inserted else { throw .cycle } + guard pages < limit.pages.rawValue else { throw .right(.pages) } + guard requests.insert(request).inserted else { throw .right(.cycle) } - let page: Page - do throws(Failure) { + let page: GitHub.User.Repositories.Page + do throws(Either) { page = try await self.page(request) } catch { - throw .client(error) + switch error { + case .left(let error): throw .left(error) + case .right(let error): throw .right(.page(error)) + } } - guard !Task.isCancelled else { throw .cancellation } + guard !Task.isCancelled else { throw .left(.cancelled) } pages += 1 repositories.append(contentsOf: page.response.repositories) @@ -33,7 +36,7 @@ extension GitHub.User.Repositories.Client { // REASON: same-package traversal-limit boundary — the accumulated // item count is compared against the limit newtype's raw magnitude. guard UInt(repositories.count) <= limit.items.rawValue else { - throw .items + throw .right(.items) } current = page.next } diff --git a/Sources/GitHub/GitHub.User.Repositories.Client.swift b/Sources/GitHub/GitHub.User.Repositories.Client.swift index 61702d6..1453edb 100644 --- a/Sources/GitHub/GitHub.User.Repositories.Client.swift +++ b/Sources/GitHub/GitHub.User.Repositories.Client.swift @@ -1,9 +1,9 @@ extension GitHub.User.Repositories { - public struct Client: Sendable { - public var page: @Sendable (Request) async throws(Failure) -> Page + public struct Client: Sendable { + public var page: @Sendable (Request) async throws(Either) -> Page public init( - page: @escaping @Sendable (Request) async throws(Failure) -> Page + page: @escaping @Sendable (Request) async throws(Either) -> Page ) { self.page = page } diff --git a/Sources/GitHub/GitHub.User.Repositories.Page.Error.swift b/Sources/GitHub/GitHub.User.Repositories.Page.Error.swift new file mode 100644 index 0000000..51c4536 --- /dev/null +++ b/Sources/GitHub/GitHub.User.Repositories.Page.Error.swift @@ -0,0 +1,9 @@ +extension GitHub.User.Repositories.Page { + public enum Error: Swift.Error, Sendable, Equatable, Hashable { + case transport + case authentication + case forbidden + case rejected + case malformedResponse + } +} diff --git a/Sources/GitHub/GitHub.User.Repositories.Client.Page.swift b/Sources/GitHub/GitHub.User.Repositories.Page.swift similarity index 89% rename from Sources/GitHub/GitHub.User.Repositories.Client.Page.swift rename to Sources/GitHub/GitHub.User.Repositories.Page.swift index ae6738e..29a3154 100644 --- a/Sources/GitHub/GitHub.User.Repositories.Client.Page.swift +++ b/Sources/GitHub/GitHub.User.Repositories.Page.swift @@ -1,4 +1,4 @@ -extension GitHub.User.Repositories.Client { +extension GitHub.User.Repositories { public struct Page: Equatable, Sendable { public let response: GitHub.User.Repositories.Response public let next: GitHub.User.Repositories.Request? diff --git a/Sources/GitHub/GitHub.User.Repositories.Traversal.Error.swift b/Sources/GitHub/GitHub.User.Repositories.Traversal.Error.swift index 5f1ab7f..8090bfc 100644 --- a/Sources/GitHub/GitHub.User.Repositories.Traversal.Error.swift +++ b/Sources/GitHub/GitHub.User.Repositories.Traversal.Error.swift @@ -1,12 +1,10 @@ extension GitHub.User.Repositories.Traversal { - public enum Error: Swift.Error, Sendable { - case cancellation - case client(Failure) + public enum Error: Swift.Error, Sendable { case cycle case items + case page(GitHub.User.Repositories.Page.Error) case pages } } -extension GitHub.User.Repositories.Traversal.Error: Equatable -where Failure: Equatable {} +extension GitHub.User.Repositories.Traversal.Error: Equatable {} diff --git a/Sources/GitHub/exports.swift b/Sources/GitHub/exports.swift index a24ac5e..0a13c58 100644 --- a/Sources/GitHub/exports.swift +++ b/Sources/GitHub/exports.swift @@ -1 +1,3 @@ +@_exported public import Async_Lifecycle_Primitives +@_exported public import Either_Primitives @_exported public import GitHub_Standard diff --git a/Tests/GitHub Core Tests/GitHub.Organization.Repositories.Client Tests.swift b/Tests/GitHub Core Tests/GitHub.Organization.Repositories.Client Tests.swift index 83c5471..c5a3179 100644 --- a/Tests/GitHub Core Tests/GitHub.Organization.Repositories.Client Tests.swift +++ b/Tests/GitHub Core Tests/GitHub.Organization.Repositories.Client Tests.swift @@ -37,9 +37,9 @@ extension GitHub.Organization.Repositories { #expect(repositories.map(\.id.underlying) == [2, 1, 3]) await #expect( - throws: GitHub.Organization.Repositories.Traversal.Error.duplicate( - .init(1) - ) + throws: + Either + .right(.duplicate(.init(1))) ) { try await client.all( request, @@ -54,7 +54,9 @@ extension GitHub.Organization.Repositories { func limit() async throws { let client = try self.client() await #expect( - throws: GitHub.Organization.Repositories.Traversal.Error.pages + throws: + Either + .right(.pages) ) { try await client.all( request(page: .first), @@ -79,23 +81,26 @@ extension GitHub.Organization.Repositories { task.cancel() await #expect( - throws: GitHub.Organization.Repositories.Traversal.Error - .cancellation + throws: + Either + .left(.cancelled) ) { try await task.value } } - private func client() throws(Fixture.Failure) -> Client { + private func client() throws(Fixture.Failure) -> Client { let second = try self.page(2) return Client { - (request: GitHub.Organization.Repositories.Request) async throws(Fixture.Failure) in + (request: GitHub.Organization.Repositories.Request) async throws( + Either + ) in // swift-linter:disable:next raw value access // REASON: test-only fixture switching on the request's raw // page number to script per-page responses. switch request.page.rawValue { case 1: - return Client.Page( + return Page( response: .init( repositories: [ repository(id: 2, name: "beta"), @@ -106,7 +111,7 @@ extension GitHub.Organization.Repositories { ) case 2: - return Client.Page( + return Page( response: .init( repositories: [ repository(id: 1, name: "alpha-later"), @@ -117,7 +122,7 @@ extension GitHub.Organization.Repositories { ) default: - throw .unexpected + throw .right(.transport) } } } diff --git a/Tests/GitHub Core Tests/GitHub.Repository.Stargazers.Client Tests.swift b/Tests/GitHub Core Tests/GitHub.Repository.Stargazers.Client Tests.swift index 0715466..c6ada30 100644 --- a/Tests/GitHub Core Tests/GitHub.Repository.Stargazers.Client Tests.swift +++ b/Tests/GitHub Core Tests/GitHub.Repository.Stargazers.Client Tests.swift @@ -6,16 +6,16 @@ extension GitHub.Repository.Stargazers { @Suite("GitHub.Repository.Stargazers.Client.Unit") struct Core { @Test("Traversal follows stargazer pages") - func traversal() async throws(Traversal.Error) { + func traversal() async throws { guard let second = GitHub.Page.Number(rawValue: 2) else { Issue.record("invalid page fixture") return } let owner = GitHub.Owner.Login("swiftlang") let repository = GitHub.Repository.Name("swift") - let client = Client { - (request: Request) async throws(GitHub.Repository.Fixture.Failure) - -> Client.Page in + let client = Client { + (request: Request) async throws(Either) + -> Page in // swift-linter:disable:next raw value access // REASON: the fixture pages by the newtype's raw wire number — // the test's purpose is the paging boundary itself. @@ -35,7 +35,7 @@ extension GitHub.Repository.Stargazers { return .init(response: .init(stargazers: []), next: nil) default: - throw .unexpected + throw .right(.transport) } } @@ -64,16 +64,14 @@ extension GitHub.Repository.Stargazers { page: .first, size: .maximum ) - let failing = Client { - (_: Request) async throws(GitHub.Repository.Fixture.Failure) - -> Client.Page in - throw .expected + let failing = Client { + (_: Request) async throws(Either) -> Page in + throw .right(.transport) } await #expect( throws: - GitHub.Repository.Stargazers.Traversal.Error< - GitHub.Repository.Fixture.Failure - >.client(.expected) + Either + .right(.page(.transport)) ) { try await failing.all( request, @@ -81,16 +79,14 @@ extension GitHub.Repository.Stargazers { ) } - let cycling = Client { - (_: Request) async throws(GitHub.Repository.Fixture.Failure) - -> Client.Page in + let cycling = Client { + (_: Request) async throws(Either) -> Page in .init(response: .init(stargazers: []), next: request) } await #expect( throws: - GitHub.Repository.Stargazers.Traversal.Error< - GitHub.Repository.Fixture.Failure - >.cycle + Either + .right(.cycle) ) { try await cycling.all( request, @@ -99,9 +95,8 @@ extension GitHub.Repository.Stargazers { } await #expect( throws: - GitHub.Repository.Stargazers.Traversal.Error< - GitHub.Repository.Fixture.Failure - >.pages + Either + .right(.pages) ) { try await cycling.all( request, @@ -118,9 +113,8 @@ extension GitHub.Repository.Stargazers { task.cancel() await #expect( throws: - GitHub.Repository.Stargazers.Traversal.Error< - GitHub.Repository.Fixture.Failure - >.cancellation + Either + .left(.cancelled) ) { try await task.value } diff --git a/Tests/GitHub Core Tests/GitHub.User.Repositories.Client Tests.swift b/Tests/GitHub Core Tests/GitHub.User.Repositories.Client Tests.swift index 7ae7779..08872fa 100644 --- a/Tests/GitHub Core Tests/GitHub.User.Repositories.Client Tests.swift +++ b/Tests/GitHub Core Tests/GitHub.User.Repositories.Client Tests.swift @@ -6,14 +6,14 @@ extension GitHub.User.Repositories { @Suite("GitHub.User.Repositories.Client.Unit") struct Core { @Test("Traversal follows authenticated-user repository pages") - func traversal() async throws(Traversal.Error) { + func traversal() async throws { guard let second = GitHub.Page.Number(rawValue: 2) else { Issue.record("invalid page fixture") return } - let client = Client { - (request: Request) async throws(GitHub.Repository.Fixture.Failure) - -> Client.Page in + let client = Client { + (request: Request) async throws(Either) + -> Page in // swift-linter:disable:next raw value access // REASON: the fixture pages by the newtype's raw wire number — // the test's purpose is the paging boundary itself. @@ -28,7 +28,7 @@ extension GitHub.User.Repositories { return .init(response: .init(repositories: []), next: nil) default: - throw .unexpected + throw .right(.transport) } } @@ -50,16 +50,14 @@ extension GitHub.User.Repositories { page: .first, size: .maximum ) - let failing = Client { - (_: Request) async throws(GitHub.Repository.Fixture.Failure) - -> Client.Page in - throw .expected + let failing = Client { + (_: Request) async throws(Either) -> Page in + throw .right(.transport) } await #expect( throws: - GitHub.User.Repositories.Traversal.Error< - GitHub.Repository.Fixture.Failure - >.client(.expected) + Either + .right(.page(.transport)) ) { try await failing.all( request, @@ -67,16 +65,14 @@ extension GitHub.User.Repositories { ) } - let cycling = Client { - (_: Request) async throws(GitHub.Repository.Fixture.Failure) - -> Client.Page in + let cycling = Client { + (_: Request) async throws(Either) -> Page in .init(response: .init(repositories: []), next: request) } await #expect( throws: - GitHub.User.Repositories.Traversal.Error< - GitHub.Repository.Fixture.Failure - >.cycle + Either + .right(.cycle) ) { try await cycling.all( request, @@ -85,9 +81,8 @@ extension GitHub.User.Repositories { } await #expect( throws: - GitHub.User.Repositories.Traversal.Error< - GitHub.Repository.Fixture.Failure - >.pages + Either + .right(.pages) ) { try await cycling.all( request, @@ -104,9 +99,8 @@ extension GitHub.User.Repositories { task.cancel() await #expect( throws: - GitHub.User.Repositories.Traversal.Error< - GitHub.Repository.Fixture.Failure - >.cancellation + Either + .left(.cancelled) ) { try await task.value } From 0f49fa7f4a4ca30cde29d81f5c7b7522574cddac Mon Sep 17 00:00:00 2001 From: Coen ten Thije Boonkkamp Date: Sun, 2 Aug 2026 13:16:24 +0200 Subject: [PATCH 2/2] Apply Swift 6.3.3 formatting --- .../GitHub.Organization.Repositories.Client+all.swift | 3 ++- .../GitHub/GitHub.Organization.Repositories.Client.swift | 8 ++++++-- Sources/GitHub/GitHub.Repository.Stargazers.Client.swift | 8 ++++++-- Sources/GitHub/GitHub.User.Repositories.Client.swift | 8 ++++++-- .../GitHub.Organization.Repositories.Client Tests.swift | 6 +++--- .../GitHub.Repository.Stargazers.Client Tests.swift | 8 ++++---- .../GitHub.User.Repositories.Client Tests.swift | 8 ++++---- 7 files changed, 31 insertions(+), 18 deletions(-) diff --git a/Sources/GitHub/GitHub.Organization.Repositories.Client+all.swift b/Sources/GitHub/GitHub.Organization.Repositories.Client+all.swift index a56bb1e..4d950b1 100644 --- a/Sources/GitHub/GitHub.Organization.Repositories.Client+all.swift +++ b/Sources/GitHub/GitHub.Organization.Repositories.Client+all.swift @@ -4,7 +4,8 @@ extension GitHub.Organization.Repositories.Client { limit: GitHub.Organization.Repositories.Traversal.Limit, duplicate: GitHub.Organization.Repositories.Traversal.Duplicate, order: GitHub.Organization.Repositories.Traversal.Order - ) async throws(Either) -> [GitHub.Repository + ) async throws(Either) + -> [GitHub.Repository .Summary] { var repositories: [GitHub.Repository.Summary] = [] diff --git a/Sources/GitHub/GitHub.Organization.Repositories.Client.swift b/Sources/GitHub/GitHub.Organization.Repositories.Client.swift index 65c0b78..14e0dcd 100644 --- a/Sources/GitHub/GitHub.Organization.Repositories.Client.swift +++ b/Sources/GitHub/GitHub.Organization.Repositories.Client.swift @@ -1,9 +1,13 @@ extension GitHub.Organization.Repositories { public struct Client: Sendable { - public var page: @Sendable (Request) async throws(Either) -> Page + public var page: + @Sendable (Request) async throws(Either) -> Page public init( - page: @escaping @Sendable (Request) async throws(Either) -> Page + page: + @escaping @Sendable (Request) async throws(Either< + Async.Lifecycle.Error, Page.Error + >) -> Page ) { self.page = page } diff --git a/Sources/GitHub/GitHub.Repository.Stargazers.Client.swift b/Sources/GitHub/GitHub.Repository.Stargazers.Client.swift index d75c0ef..45afe9d 100644 --- a/Sources/GitHub/GitHub.Repository.Stargazers.Client.swift +++ b/Sources/GitHub/GitHub.Repository.Stargazers.Client.swift @@ -1,9 +1,13 @@ extension GitHub.Repository.Stargazers { public struct Client: Sendable { - public var page: @Sendable (Request) async throws(Either) -> Page + public var page: + @Sendable (Request) async throws(Either) -> Page public init( - page: @escaping @Sendable (Request) async throws(Either) -> Page + page: + @escaping @Sendable (Request) async throws(Either< + Async.Lifecycle.Error, Page.Error + >) -> Page ) { self.page = page } diff --git a/Sources/GitHub/GitHub.User.Repositories.Client.swift b/Sources/GitHub/GitHub.User.Repositories.Client.swift index 1453edb..98fda49 100644 --- a/Sources/GitHub/GitHub.User.Repositories.Client.swift +++ b/Sources/GitHub/GitHub.User.Repositories.Client.swift @@ -1,9 +1,13 @@ extension GitHub.User.Repositories { public struct Client: Sendable { - public var page: @Sendable (Request) async throws(Either) -> Page + public var page: + @Sendable (Request) async throws(Either) -> Page public init( - page: @escaping @Sendable (Request) async throws(Either) -> Page + page: + @escaping @Sendable (Request) async throws(Either< + Async.Lifecycle.Error, Page.Error + >) -> Page ) { self.page = page } diff --git a/Tests/GitHub Core Tests/GitHub.Organization.Repositories.Client Tests.swift b/Tests/GitHub Core Tests/GitHub.Organization.Repositories.Client Tests.swift index c5a3179..719ebdd 100644 --- a/Tests/GitHub Core Tests/GitHub.Organization.Repositories.Client Tests.swift +++ b/Tests/GitHub Core Tests/GitHub.Organization.Repositories.Client Tests.swift @@ -92,9 +92,9 @@ extension GitHub.Organization.Repositories { private func client() throws(Fixture.Failure) -> Client { let second = try self.page(2) return Client { - (request: GitHub.Organization.Repositories.Request) async throws( - Either - ) in + (request: GitHub.Organization.Repositories.Request) async throws(Either< + Async.Lifecycle.Error, Page.Error + >) in // swift-linter:disable:next raw value access // REASON: test-only fixture switching on the request's raw // page number to script per-page responses. diff --git a/Tests/GitHub Core Tests/GitHub.Repository.Stargazers.Client Tests.swift b/Tests/GitHub Core Tests/GitHub.Repository.Stargazers.Client Tests.swift index c6ada30..7347c5d 100644 --- a/Tests/GitHub Core Tests/GitHub.Repository.Stargazers.Client Tests.swift +++ b/Tests/GitHub Core Tests/GitHub.Repository.Stargazers.Client Tests.swift @@ -71,7 +71,7 @@ extension GitHub.Repository.Stargazers { await #expect( throws: Either - .right(.page(.transport)) + .right(.page(.transport)) ) { try await failing.all( request, @@ -86,7 +86,7 @@ extension GitHub.Repository.Stargazers { await #expect( throws: Either - .right(.cycle) + .right(.cycle) ) { try await cycling.all( request, @@ -96,7 +96,7 @@ extension GitHub.Repository.Stargazers { await #expect( throws: Either - .right(.pages) + .right(.pages) ) { try await cycling.all( request, @@ -114,7 +114,7 @@ extension GitHub.Repository.Stargazers { await #expect( throws: Either - .left(.cancelled) + .left(.cancelled) ) { try await task.value } diff --git a/Tests/GitHub Core Tests/GitHub.User.Repositories.Client Tests.swift b/Tests/GitHub Core Tests/GitHub.User.Repositories.Client Tests.swift index 08872fa..e2116c8 100644 --- a/Tests/GitHub Core Tests/GitHub.User.Repositories.Client Tests.swift +++ b/Tests/GitHub Core Tests/GitHub.User.Repositories.Client Tests.swift @@ -57,7 +57,7 @@ extension GitHub.User.Repositories { await #expect( throws: Either - .right(.page(.transport)) + .right(.page(.transport)) ) { try await failing.all( request, @@ -72,7 +72,7 @@ extension GitHub.User.Repositories { await #expect( throws: Either - .right(.cycle) + .right(.cycle) ) { try await cycling.all( request, @@ -82,7 +82,7 @@ extension GitHub.User.Repositories { await #expect( throws: Either - .right(.pages) + .right(.pages) ) { try await cycling.all( request, @@ -100,7 +100,7 @@ extension GitHub.User.Repositories { await #expect( throws: Either - .left(.cancelled) + .left(.cancelled) ) { try await task.value }