diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 99a8e1c1a..6af53a1c2 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -1,7 +1,7 @@ # Nodes with values to reuse in the pipeline. common_params: plugins: &common_plugins - - automattic/a8c-ci-toolkit#2.17.0 + - automattic/a8c-ci-toolkit#3.4.1 # Common environment values to use with the `env` key. steps: @@ -71,6 +71,14 @@ steps: plugins: *common_plugins agents: queue: mac + - label: ":swift: :cocoapods: Validate CocoaPods Support" + command: .buildkite/validate-cocoapods.sh + env: + IMAGE_ID: xcode-15.3 + depends_on: xcframework + plugins: *common_plugins + agents: + queue: mac - label: ":swift: :linux: Build and Test" command: | echo "--- :swift: Building + Testing" diff --git a/.buildkite/validate-cocoapods.sh b/.buildkite/validate-cocoapods.sh new file mode 100755 index 000000000..fe24ad8dc --- /dev/null +++ b/.buildkite/validate-cocoapods.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +set -euo pipefail + +# Commit a podspec file to the repo may give a fasle sense of CocoaPods support. +# This script validates the podspec file generated by the build script. +# We may need to tweak the podspec content if the project structure changes. +# +# Here are a few potential fixes if this script fails on CI. +# - There is no "WordPressAPIInternal" module when building using CocoaPods. +# Be sure to add `#if canImport(WordPressAPIInternal)` before `import WordPressAPIInternal`. + +echo "--- :hammer: Generating a podspec file" +cat < 'mobile@wordpress.org' } + + spec.ios.deployment_target = '13.0' + spec.osx.deployment_target = '11.0' + + # zip -r swift-source-archive.zip native/swift target/libwordpressFFI.xcframework + spec.source = { :http => "http://s3.com/WordPressAPI.zip" } + + spec.swift_version = '5.10' + spec.source_files = 'native/swift/Sources/**/*.{swift}' + spec.vendored_frameworks = 'target/libwordpressFFI.xcframework' + + spec.pod_target_xcconfig = { + 'SWIFT_PACKAGE_NAME' => 'WordPressAPI' + } + + spec.test_spec 'Tests' do |test_spec| + test_spec.source_files = 'native/swift/Tests/**/*.{swift}' + end +end +EOT + +echo "--- :arrow_down: Downloading xcframework" +buildkite-agent artifact download target/libwordpressFFI.xcframework.zip . --step "xcframework" +buildkite-agent artifact download native/swift/Sources/wordpress-api-wrapper/wp_api.swift . --step "xcframework" +unzip target/libwordpressFFI.xcframework.zip -d . +rm target/libwordpressFFI.xcframework.zip +export SKIP_PACKAGE_WP_API=true + +echo "--- :rubygems: Setting up Gems" +install_gems + +echo "--- :cocoapods: Validating Podspec" +validate_podspec --allow-warnings diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 000000000..be94e6f53 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.2.2 diff --git a/Gemfile b/Gemfile index 1b2a913da..0e779584b 100644 --- a/Gemfile +++ b/Gemfile @@ -3,3 +3,4 @@ source 'https://rubygems.org' gem 'fastlane', '~> 2.220' +gem 'cocoapods', '~> 1.15' diff --git a/Gemfile.lock b/Gemfile.lock index 5ca87b1cd..d96879094 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,8 +5,21 @@ GEM base64 nkf rexml + activesupport (7.1.3.3) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + minitest (>= 5.1) + mutex_m + tzinfo (~> 2.0) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) + algoliasearch (1.27.5) + httpclient (~> 2.8, >= 2.8.3) + json (>= 1.5.1) artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) @@ -27,17 +40,61 @@ GEM aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) base64 (0.2.0) + bigdecimal (3.1.8) claide (1.1.0) + cocoapods (1.15.2) + addressable (~> 2.8) + claide (>= 1.0.2, < 2.0) + cocoapods-core (= 1.15.2) + cocoapods-deintegrate (>= 1.0.3, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored2 (~> 3.1) + escape (~> 0.0.4) + fourflusher (>= 2.3.0, < 3.0) + gh_inspector (~> 1.0) + molinillo (~> 0.8.0) + nap (~> 1.0) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.23.0, < 2.0) + cocoapods-core (1.15.2) + activesupport (>= 5.0, < 8) + addressable (~> 2.8) + algoliasearch (~> 1.0) + concurrent-ruby (~> 1.1) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + netrc (~> 0.11) + public_suffix (~> 4.0) + typhoeus (~> 1.0) + cocoapods-deintegrate (1.0.5) + cocoapods-downloader (2.1) + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) + nap (>= 0.8, < 2.0) + netrc (~> 0.11) + cocoapods-try (1.2.0) colored (1.2) colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) + concurrent-ruby (1.2.3) + connection_pool (2.4.1) declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) domain_name (0.6.20240107) dotenv (2.8.1) + drb (2.2.1) emoji_regex (3.2.3) + escape (0.0.4) + ethon (0.16.0) + ffi (>= 1.15.0) excon (0.110.0) faraday (1.10.3) faraday-em_http (~> 1.0) @@ -109,6 +166,9 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) + ffi (1.16.3) + fourflusher (2.3.1) + fuzzy_match (2.0.4) gh_inspector (1.1.3) google-apis-androidpublisher_v3 (0.54.0) google-apis-core (>= 0.11.0, < 2.a) @@ -150,21 +210,28 @@ GEM http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) + i18n (1.14.5) + concurrent-ruby (~> 1.0) jmespath (1.6.2) json (2.7.2) jwt (2.8.1) base64 mini_magick (4.12.0) mini_mime (1.1.5) + minitest (5.23.1) + molinillo (0.8.0) multi_json (1.15.0) multipart-post (2.4.0) + mutex_m (0.2.0) nanaimo (0.3.0) + nap (1.1.0) naturally (2.2.1) + netrc (0.11.0) nkf (0.2.0) optparse (0.5.0) os (1.1.4) plist (3.7.1) - public_suffix (5.0.5) + public_suffix (4.0.7) rake (13.2.1) representable (3.2.0) declarative (< 0.1.0) @@ -173,6 +240,7 @@ GEM retriable (3.1.2) rexml (3.2.6) rouge (2.0.7) + ruby-macho (2.5.1) ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.5) @@ -192,6 +260,10 @@ GEM tty-screen (0.8.2) tty-spinner (0.9.3) tty-cursor (~> 0.7) + typhoeus (1.4.1) + ethon (>= 0.9.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) uber (0.1.0) unicode-display_width (2.5.0) word_wrap (1.0.0) @@ -211,7 +283,8 @@ PLATFORMS arm64-darwin-22 DEPENDENCIES + cocoapods (~> 1.15) fastlane (~> 2.220) BUNDLED WITH - 2.4.19 + 2.3.23 diff --git a/native/swift/Example/Example/LoginManager.swift b/native/swift/Example/Example/LoginManager.swift index 3b5045413..1873dd5f7 100644 --- a/native/swift/Example/Example/LoginManager.swift +++ b/native/swift/Example/Example/LoginManager.swift @@ -1,5 +1,7 @@ import Foundation +#if canImport(WordPressAPIInternal) import WordPressAPIInternal +#endif class LoginManager: NSObject, ObservableObject { diff --git a/native/swift/Sources/wordpress-api/Endpoints/Plugins.swift b/native/swift/Sources/wordpress-api/Endpoints/Plugins.swift index df87f66ec..bc5c4f2ac 100644 --- a/native/swift/Sources/wordpress-api/Endpoints/Plugins.swift +++ b/native/swift/Sources/wordpress-api/Endpoints/Plugins.swift @@ -1,5 +1,7 @@ import Foundation +#if canImport(WordPressAPIInternal) import WordPressAPIInternal +#endif extension WordPressAPI { public var plugins: AnyNamespace { diff --git a/native/swift/Sources/wordpress-api/Endpoints/Users.swift b/native/swift/Sources/wordpress-api/Endpoints/Users.swift index 40f4ce133..52782ef87 100644 --- a/native/swift/Sources/wordpress-api/Endpoints/Users.swift +++ b/native/swift/Sources/wordpress-api/Endpoints/Users.swift @@ -1,5 +1,7 @@ import Foundation +#if canImport(WordPressAPIInternal) import WordPressAPIInternal +#endif extension SparseUser: Contextual { public typealias ID = UserId diff --git a/native/swift/Sources/wordpress-api/Exports.swift b/native/swift/Sources/wordpress-api/Exports.swift index 24f65b125..80a9d82d4 100644 --- a/native/swift/Sources/wordpress-api/Exports.swift +++ b/native/swift/Sources/wordpress-api/Exports.swift @@ -3,6 +3,8 @@ // We could export all of them using `@_exported import`, but that probably puts // us in a position where we need to make major releases due to Rust code changes. +#if canImport(WordPressAPIInternal) + import WordPressAPIInternal public typealias WpApiError = WordPressAPIInternal.WpApiError @@ -31,3 +33,5 @@ public typealias PluginListParams = WordPressAPIInternal.PluginListParams public typealias PluginUpdateParams = WordPressAPIInternal.PluginUpdateParams public typealias PluginCreateParams = WordPressAPIInternal.PluginCreateParams public typealias PluginDeleteResponse = WordPressAPIInternal.PluginDeleteResponse + +#endif diff --git a/native/swift/Sources/wordpress-api/Login/API+Login.swift b/native/swift/Sources/wordpress-api/Login/API+Login.swift index d929eaeb4..369579f4f 100644 --- a/native/swift/Sources/wordpress-api/Login/API+Login.swift +++ b/native/swift/Sources/wordpress-api/Login/API+Login.swift @@ -1,5 +1,7 @@ import Foundation +#if canImport(WordPressAPIInternal) import WordPressAPIInternal +#endif #if canImport(FoundationNetworking) import FoundationNetworking @@ -11,11 +13,11 @@ public extension WordPressAPI { let ephemeralClient = WordPressAPI(urlSession: session, baseUrl: url, authenticationStategy: .none) let response = try await ephemeralClient.perform(request: request) - return WordPressAPIInternal.getLinkHeader(response: response, name: "https://api.w.org/")?.asUrl() + return getLinkHeader(response: response, name: "https://api.w.org/")?.asUrl() } func getRestAPICapabilities(forApiRoot url: URL, using session: URLSession) async throws -> WpapiDetails { let wpResponse = try await self.perform(request: WpNetworkRequest(method: .get, url: url, headerMap: [:])) - return try WordPressAPIInternal.parseApiDetailsResponse(response: wpResponse) + return try parseApiDetailsResponse(response: wpResponse) } } diff --git a/native/swift/Sources/wordpress-api/Namespace.swift b/native/swift/Sources/wordpress-api/Namespace.swift index d72f57213..97f8d0608 100644 --- a/native/swift/Sources/wordpress-api/Namespace.swift +++ b/native/swift/Sources/wordpress-api/Namespace.swift @@ -1,5 +1,7 @@ import Foundation +#if canImport(WordPressAPIInternal) import WordPressAPIInternal +#endif public protocol Namespace { associatedtype T @@ -51,8 +53,8 @@ public protocol ContextualNamespace: Namespace where T: Contextual { var context: WpContext { get } - func parseResponse(_ response: WordPressAPIInternal.WpNetworkResponse) throws -> R - func parseResponse(_ response: WordPressAPIInternal.WpNetworkResponse) throws -> [R] + func parseResponse(_ response: WpNetworkResponse) throws -> R + func parseResponse(_ response: WpNetworkResponse) throws -> [R] } public struct ViewNamespace: ContextualNamespace { @@ -63,11 +65,11 @@ public struct ViewNamespace: ContextualNamespace { parent.api } - public func parseResponse(_ response: WordPressAPIInternal.WpNetworkResponse) throws -> T.ViewContext { + public func parseResponse(_ response: WpNetworkResponse) throws -> T.ViewContext { try T.parseResponse(response) } - public func parseResponse(_ response: WordPressAPIInternal.WpNetworkResponse) throws -> [T.ViewContext] { + public func parseResponse(_ response: WpNetworkResponse) throws -> [T.ViewContext] { try T.parseResponse(response) } } @@ -80,11 +82,11 @@ public struct EditNamespace: ContextualNamespace { parent.api } - public func parseResponse(_ response: WordPressAPIInternal.WpNetworkResponse) throws -> T.EditContext { + public func parseResponse(_ response: WpNetworkResponse) throws -> T.EditContext { try T.parseResponse(response) } - public func parseResponse(_ response: WordPressAPIInternal.WpNetworkResponse) throws -> [T.EditContext] { + public func parseResponse(_ response: WpNetworkResponse) throws -> [T.EditContext] { try T.parseResponse(response) } } @@ -97,11 +99,11 @@ public struct EmbedNamespace: ContextualNamespace { parent.api } - public func parseResponse(_ response: WordPressAPIInternal.WpNetworkResponse) throws -> T.EmbedContext { + public func parseResponse(_ response: WpNetworkResponse) throws -> T.EmbedContext { try T.parseResponse(response) } - public func parseResponse(_ response: WordPressAPIInternal.WpNetworkResponse) throws -> [T.EmbedContext] { + public func parseResponse(_ response: WpNetworkResponse) throws -> [T.EmbedContext] { try T.parseResponse(response) } } diff --git a/native/swift/Sources/wordpress-api/WordPressAPI.swift b/native/swift/Sources/wordpress-api/WordPressAPI.swift index 64d7a8233..03cd97456 100644 --- a/native/swift/Sources/wordpress-api/WordPressAPI.swift +++ b/native/swift/Sources/wordpress-api/WordPressAPI.swift @@ -1,5 +1,7 @@ import Foundation +#if canImport(WordPressAPIInternal) import WordPressAPIInternal +#endif #if os(Linux) import FoundationNetworking @@ -71,7 +73,7 @@ public struct WordPressAPI { } public static func extractLoginDetails(from url: URL) -> WpapiApplicationPasswordDetails? { - return WordPressAPIInternal.extractLoginDetailsFromUrl(url: url.asRestUrl()) + return extractLoginDetailsFromUrl(url: url.asRestUrl()) } } diff --git a/native/swift/Tests/wordpress-api/WordPressAPITests.swift b/native/swift/Tests/wordpress-api/WordPressAPITests.swift index 073510026..a8afd9294 100644 --- a/native/swift/Tests/wordpress-api/WordPressAPITests.swift +++ b/native/swift/Tests/wordpress-api/WordPressAPITests.swift @@ -1,7 +1,9 @@ import XCTest import Foundation import WordPressAPI +#if canImport(WordPressAPIInternal) import WordPressAPIInternal +#endif final class WordPressAPITests: XCTestCase {