Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Dockerfile.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM public.ecr.aws/docker/library/swift:5.10
FROM public.ecr.aws/docker/library/swift:6.0

RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
&& apt-get update \
Expand Down
3 changes: 2 additions & 1 deletion Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.10
// swift-tools-version: 6.0

import Foundation
import PackageDescription
Expand Down Expand Up @@ -48,6 +48,9 @@ var package = Package(
path: "native/swift/Sources/wordpress-api-wrapper",
exclude: [
"README.md"
],
swiftSettings: [
.swiftLanguageMode(.v5)
]
),
libwordpressFFI,
Expand Down Expand Up @@ -99,9 +102,11 @@ enum WordPressRSVersion {
}

// Add SwiftLint to the package so that we can see linting issues directly from Xcode.
@MainActor
func enableSwiftLint() throws {
#if os(macOS)
let version = try String(contentsOf: URL(string:"./.swiftlint.yml", relativeTo: URL(filePath: #filePath))!)
let filePath = URL(string:"./.swiftlint.yml", relativeTo: URL(filePath: #filePath))!
let version = try String(contentsOf: filePath, encoding: .utf8)
.split(separator: "\n")
.first(where: { $0.starts(with: "swiftlint_version") })?
.split(separator: ":")
Expand Down
4 changes: 4 additions & 0 deletions native/swift/Sources/wordpress-api/Exports.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@
import WordPressAPIInternal

public typealias WpApiError = WordPressAPIInternal.WpApiError
public typealias RequestExecutionError = WordPressAPIInternal.RequestExecutionError
public typealias ParsedUrl = WordPressAPIInternal.ParsedUrl
public typealias WpUuid = WordPressAPIInternal.WpUuid
public typealias WpNetworkRequest = WordPressAPIInternal.WpNetworkRequest
public typealias WpNetworkResponse = WordPressAPIInternal.WpNetworkResponse
public typealias WpNetworkHeaderMap = WordPressAPIInternal.WpNetworkHeaderMap

// MARK: - Login

Expand Down
59 changes: 59 additions & 0 deletions native/swift/Sources/wordpress-api/LoginAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,65 @@ public final class WordPressLoginClient {
case invalidApplicationPasswordCallback
case cancelled
case unknown(Swift.Error)

func isAutodiscoveryError() -> Bool {
guard case let .invalidSiteAddress(urlDiscoveryError) = self else {
return false
}

guard case .UrlDiscoveryFailed = urlDiscoveryError else {
return false
}

return true
}

var isFailedToFetchApiDetails: Bool {
guard
case let .invalidSiteAddress(urlDiscoveryError) = self,
case .UrlDiscoveryFailed(let attempts) = urlDiscoveryError
else {
return false
}

return attempts.values.contains { state in
return switch state {
case .failure(let error): urlDiscoverErrorIsFetchApiDetailsFailed(error)
default: false
}
}
}

var isFailedToFetchApiRoot: Bool {
guard
case let .invalidSiteAddress(urlDiscoveryError) = self,
case .UrlDiscoveryFailed(let attempts) = urlDiscoveryError
else {
return false
}

return attempts.values.contains { state in
if case let .failure(error) = state {
return isFetchRootUrlFailedError(error)
}

return false
}
}

private func urlDiscoverErrorIsFetchApiDetailsFailed(_ error: UrlDiscoveryAttemptError) -> Bool {
return switch error {
case .fetchApiDetailsFailed: true
default: false
}
}

private func isFetchRootUrlFailedError(_ error: UrlDiscoveryAttemptError) -> Bool {
return switch error {
case .fetchApiRootUrlFailed: true
default: false
}
}
}

private let requestExecutor: SafeRequestExecutor
Expand Down
9 changes: 2 additions & 7 deletions native/swift/Sources/wordpress-api/SafeRequestExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import FoundationNetworking
#endif

public protocol SafeRequestExecutor: RequestExecutor {

func execute(_ request: WpNetworkRequest) async -> Result<WpNetworkResponse, RequestExecutionError>

}

extension SafeRequestExecutor {
Expand All @@ -22,9 +20,7 @@ extension SafeRequestExecutor {

}

#if hasFeature(RetroactiveAttribute)
extension URLSession: @retroactive RequestExecutor {}
#endif
extension URLSession: RequestExecutor {}

extension URLSession: SafeRequestExecutor {

Expand All @@ -36,9 +32,8 @@ extension URLSession: SafeRequestExecutor {
return .failure(.RequestExecutionFailed(statusCode: nil, reason: error.localizedDescription))
}

// swiftlint:disable force_cast
// swiftlint:disable:next force_cast
let urlResponse = response as! HTTPURLResponse
// swiftlint:enable force_cast

let headerMap: WpNetworkHeaderMap

Expand Down
28 changes: 0 additions & 28 deletions native/swift/Sources/wordpress-api/URLSession+Linux.swift

This file was deleted.

7 changes: 2 additions & 5 deletions native/swift/Sources/wordpress-api/WordPressAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,8 @@ public struct WordPressAPI {
}

package func perform(request: WpNetworkRequest) async throws -> WpNetworkResponse {
try await withCheckedThrowingContinuation { continuation in
self.perform(request: request) { result in
continuation.resume(with: result)
}
}
let (data, response) = try await self.urlSession.data(for: request.asURLRequest())
return try WpNetworkResponse.from(data: data, response: response)
}

package func perform(
Expand Down
14 changes: 7 additions & 7 deletions native/swift/Tests/wordpress-api/Endpoints/Users.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Foundation
import XCTest

import Testing
@testable import WordPressAPI

final class UsersTest: XCTestCase {
struct UsersTests {

@Test
func testRetrieveUser() async throws {
let response = """
{
Expand Down Expand Up @@ -34,8 +34,9 @@ final class UsersTest: XCTestCase {
}
}
"""
let stubs = HTTPStubs()
try stubs.stub(path: "/wp-json/wp/v2/users/1", with: .json(response))
let stubs = HTTPStubs(stubs: [
try HTTPStubs.stub(path: "/wp-json/wp/v2/users/1", with: .json(response))
])

let api = try WordPressAPI(
urlSession: .shared,
Expand All @@ -44,7 +45,6 @@ final class UsersTest: XCTestCase {
executor: stubs
)
let user = try await api.users.retrieveWithViewContext(userId: 1)
XCTAssertEqual(user.data.name, "User Name")
#expect(user.data.name == "User Name")
}

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import XCTest
import Foundation
import Testing
import WordPressAPI

final class FoundationExtensionsTests: XCTestCase {
class FoundationExtensionsTests {

func testWordPressDateTimeParsing() throws {
XCTAssertNotNil(Date.fromWordPressDate("2024-07-04T01:49:37"))
@Test("The Foundation Extension can parse WordPress-formatted date strings", arguments: [
"2024-07-04T01:49:37"
])
func testWordPressDateTimeParsing(_ string: String) throws {
#expect(Date.fromWordPressDate(string) != nil)
}
}
30 changes: 6 additions & 24 deletions native/swift/Tests/wordpress-api/HTTPErrorTests.swift
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
import Foundation
import XCTest

import Testing
@testable import WordPressAPI

#if canImport(WordPressAPIInternal)
import WordPressAPIInternal
#endif

class HTTPErrorTests: XCTestCase {
class HTTPErrorTests {

#if !os(Linux)
// Skip on Linux, because `XCTExpectFailure` is unavailable on Linux
@Test
func testTimeout() async throws {
let stubs = HTTPStubs()
stubs.missingStub = .failure(URLError(.timedOut))
let stubs = HTTPStubs(stubs: [], missingStub: .failure(URLError(.timedOut)))

let api = try WordPressAPI(
urlSession: .shared,
Expand All @@ -22,19 +15,8 @@ class HTTPErrorTests: XCTestCase {
executor: stubs
)

do {
await #expect(throws: WpApiError.self, performing: {
_ = try await api.users.retrieveWithViewContext(userId: 1)
XCTFail("Unexpected response")
} catch let error as URLError {
XCTAssertEqual(error.code, .timedOut)
} catch {
#if canImport(WordPressAPIInternal)
XCTAssertTrue(error is WordPressAPIInternal.WpApiError)
#else
XCTAssertTrue(error is WpApiError)
#endif
}
})
}
#endif

}
Loading