diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 72aaa6e1..bbf3333d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -71,7 +71,7 @@ cd platforms/swift && ./Scripts/lint fix Open a pull request with the following changes: 1. Bump the package version in `platforms/swift/Sources/ShopifyCheckoutKit/ShopifyCheckoutKit.swift`. -2. Bump the podspec version in `platforms/swift/ShopifyCheckoutKit.podspec`. +2. Bump the podspec version in `ShopifyCheckoutKit.podspec` (at the repo root). 3. Add an entry to the top of `platforms/swift/CHANGELOG.md`. Once merged, draft a release on GitHub: diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 6c0d6122..6653d625 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -22,7 +22,7 @@
Releasing a new Swift version? -- [ ] I have bumped the version in `platforms/swift/ShopifyCheckoutKit.podspec` +- [ ] I have bumped the version in `ShopifyCheckoutKit.podspec` - [ ] I have bumped the version in `platforms/swift/Sources/ShopifyCheckoutKit/ShopifyCheckoutKit.swift` - [ ] I have updated `platforms/swift/CHANGELOG.md` - [ ] I have updated the SwiftPM/CocoaPods version snippets in `platforms/swift/README.md` (major version only) diff --git a/.github/workflows/swift-lint.yml b/.github/workflows/swift-lint.yml index 5e97449a..4007eb8f 100644 --- a/.github/workflows/swift-lint.yml +++ b/.github/workflows/swift-lint.yml @@ -63,12 +63,14 @@ jobs: runs-on: ${{ vars.MACOS_RUNNER }} env: BUNDLE_GEMFILE: ${{ github.workspace }}/platforms/swift/Gemfile - defaults: - run: - working-directory: platforms/swift steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0 with: bundler-cache: true - - run: bundle exec pod lib lint --allow-warnings + working-directory: platforms/swift + # The podspec lives at the repo root so it can glob source files in + # both platforms/swift/ and protocol/languages/swift/. Lint runs from + # the repo root; the Gemfile under platforms/swift/ is still used via + # BUNDLE_GEMFILE above. + - run: bundle exec pod lib lint ShopifyCheckoutKit.podspec --allow-warnings diff --git a/.github/workflows/swift-publish.yml b/.github/workflows/swift-publish.yml index c1dacbc1..c3ae2b26 100644 --- a/.github/workflows/swift-publish.yml +++ b/.github/workflows/swift-publish.yml @@ -14,9 +14,6 @@ jobs: runs-on: ${{ vars.MACOS_RUNNER }} env: BUNDLE_GEMFILE: ${{ github.workspace }}/platforms/swift/Gemfile - defaults: - run: - working-directory: platforms/swift steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -27,9 +24,10 @@ jobs: working-directory: platforms/swift - name: Deploy to Cocoapods + # Podspec lives at the repo root; lint and trunk push run from there. run: | set -eo pipefail - bundle exec pod lib lint --allow-warnings --verbose - bundle exec pod trunk push --allow-warnings --verbose + bundle exec pod lib lint ShopifyCheckoutKit.podspec --allow-warnings --verbose + bundle exec pod trunk push ShopifyCheckoutKit.podspec --allow-warnings --verbose env: COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} diff --git a/.swiftlint.yml b/.swiftlint.yml index 96a0b2b2..01492d9c 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -15,7 +15,7 @@ included: excluded: - platforms/swift/Samples - platforms/swift/Sources/ShopifyCheckoutKit/Models.swift - - platforms/swift/Sources/ShopifyCheckoutProtocol/Generated + - protocol/languages/swift/Sources/ShopifyCheckoutProtocol/Generated opt_in_rules: - array_init diff --git a/Package.swift b/Package.swift index 12ed9643..53a6abf6 100644 --- a/Package.swift +++ b/Package.swift @@ -33,7 +33,7 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "ShopifyCheckoutProtocol", - path: "platforms/swift/Sources/ShopifyCheckoutProtocol" + path: "protocol/languages/swift/Sources/ShopifyCheckoutProtocol" ), .target( name: "ShopifyCheckoutKit", @@ -50,7 +50,7 @@ let package = Package( .testTarget( name: "ShopifyCheckoutProtocolTests", dependencies: ["ShopifyCheckoutProtocol"], - path: "platforms/swift/Tests/ShopifyCheckoutProtocolTests", + path: "protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests", resources: [.copy("Fixtures")] ), .testTarget( diff --git a/platforms/swift/ShopifyCheckoutKit.podspec b/ShopifyCheckoutKit.podspec similarity index 62% rename from platforms/swift/ShopifyCheckoutKit.podspec rename to ShopifyCheckoutKit.podspec index eb679dac..d14aca9f 100644 --- a/platforms/swift/ShopifyCheckoutKit.podspec +++ b/ShopifyCheckoutKit.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.homepage = "https://github.com/Shopify/checkout-kit" s.readme = "https://github.com/Shopify/checkout-kit/blob/main/README.md" s.changelog = "https://github.com/Shopify/checkout-kit/releases" - s.license = { :type => "MIT", :file => "../../LICENSE" } + s.license = { :type => "MIT", :file => "LICENSE" } s.source = { :git => "https://github.com/Shopify/checkout-kit.git", :tag => s.version.to_s @@ -26,19 +26,22 @@ Pod::Spec.new do |s| s.subspec 'Core' do |core| core.source_files = [ - 'Sources/ShopifyCheckoutKit/**/*.swift', - 'Sources/ShopifyCheckoutProtocol/**/*.swift', + 'platforms/swift/Sources/ShopifyCheckoutKit/**/*.swift', + 'protocol/languages/swift/Sources/ShopifyCheckoutProtocol/**/*.swift', ] core.resource_bundles = { - 'ShopifyCheckoutKit' => ['Sources/ShopifyCheckoutKit/Assets.xcassets'] + 'ShopifyCheckoutKit' => ['platforms/swift/Sources/ShopifyCheckoutKit/Assets.xcassets'] } end s.subspec 'AcceleratedCheckouts' do |accelerated| - accelerated.source_files = 'Sources/ShopifyAcceleratedCheckouts/**/*.swift' + accelerated.source_files = 'platforms/swift/Sources/ShopifyAcceleratedCheckouts/**/*.swift' accelerated.dependency 'ShopifyCheckoutKit/Core' accelerated.resource_bundles = { - 'ShopifyAcceleratedCheckouts' => ['Sources/ShopifyAcceleratedCheckouts/Localizable.xcstrings', 'Sources/ShopifyAcceleratedCheckouts/Media.xcassets'] + 'ShopifyAcceleratedCheckouts' => [ + 'platforms/swift/Sources/ShopifyAcceleratedCheckouts/Localizable.xcstrings', + 'platforms/swift/Sources/ShopifyAcceleratedCheckouts/Media.xcassets', + ] } end end diff --git a/platforms/swift/Scripts/lint b/platforms/swift/Scripts/lint index 20443533..b8ef5f63 100755 --- a/platforms/swift/Scripts/lint +++ b/platforms/swift/Scripts/lint @@ -165,12 +165,16 @@ fi if [[ "$MODE" == "check" && "$SKIP_POD" == "false" ]]; then echo "🔍 Running CocoaPods lint..." + # Podspec lives at the repo root so it can glob source files in both + # platforms/swift/ and protocol/languages/swift/. Run lint from the + # repo root. + REPO_ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel)" POD_LOG="" if [[ "$VERBOSE" == "true" ]]; then - bundle exec pod lib lint --allow-warnings + (cd "$REPO_ROOT" && bundle exec pod lib lint ShopifyCheckoutKit.podspec --allow-warnings) else POD_LOG="$(mktemp "${TMPDIR:-/tmp}/checkout-kit-pod-lint.XXXXXX")" - bundle exec pod lib lint --allow-warnings >"$POD_LOG" 2>&1 + (cd "$REPO_ROOT" && bundle exec pod lib lint ShopifyCheckoutKit.podspec --allow-warnings) >"$POD_LOG" 2>&1 fi POD_STATUS=$? @@ -184,7 +188,7 @@ if [[ "$MODE" == "check" && "$SKIP_POD" == "false" ]]; then echo "❌ CocoaPods lint exit status: $POD_STATUS" echo "❌ CocoaPods detected issues that need to be fixed." - echo "🔧 Run 'bundle exec pod lib lint --allow-warnings --verbose' for details" + echo "🔧 Run 'bundle exec pod lib lint ShopifyCheckoutKit.podspec --allow-warnings --verbose' from the repo root for details" exit 1 fi diff --git a/protocol/languages/swift/.gitignore b/protocol/languages/swift/.gitignore new file mode 100644 index 00000000..3552f2b4 --- /dev/null +++ b/protocol/languages/swift/.gitignore @@ -0,0 +1 @@ +.swiftpm diff --git a/protocol/languages/swift/Package.swift b/protocol/languages/swift/Package.swift new file mode 100644 index 00000000..8c953f0b --- /dev/null +++ b/protocol/languages/swift/Package.swift @@ -0,0 +1,31 @@ +// swift-tools-version: 5.9 + +import PackageDescription + +let package = Package( + name: "ShopifyCheckoutProtocol", + platforms: [ + .iOS(.v13), + .macOS(.v10_15), + ], + products: [ + .library( + name: "ShopifyCheckoutProtocol", + targets: ["ShopifyCheckoutProtocol"] + ), + ], + targets: [ + .target( + name: "ShopifyCheckoutProtocol", + path: "Sources/ShopifyCheckoutProtocol" + ), + .testTarget( + name: "ShopifyCheckoutProtocolTests", + dependencies: ["ShopifyCheckoutProtocol"], + path: "Tests/ShopifyCheckoutProtocolTests", + resources: [ + .copy("Fixtures"), + ] + ), + ] +) diff --git a/protocol/languages/swift/README.md b/protocol/languages/swift/README.md new file mode 100644 index 00000000..8eb936c8 --- /dev/null +++ b/protocol/languages/swift/README.md @@ -0,0 +1,86 @@ +# ShopifyCheckoutProtocol — Swift SDK + +Swift library for the Universal Commerce Protocol (UCP) embedded checkout specification. + +## Requirements + +- Swift 6.0+ + +## Installation + +### Swift Package Manager (Package.swift) + +Add the dependency to your `Package.swift`: + +```swift +dependencies: [ + .package(url: "", from: "1.0.0") +] +``` + +Then add `ShopifyCheckoutProtocol` to your target's dependencies: + +```swift +.target( + name: "YourTarget", + dependencies: ["ShopifyCheckoutProtocol"] +) +``` + +### Xcode + +1. Open your project in Xcode +2. Go to **File > Add Package Dependencies...** +3. Enter the repository URL: `` +4. Click **Add Package** + +## Usage + +```swift +import ShopifyCheckoutProtocol +``` + +### Bridging with checkout-sheet-kit-swift + +If you use [`checkout-sheet-kit-swift`](https://github.com/Shopify/checkout-sheet-kit-swift), add a retroactive conformance to bridge `CheckoutProtocol.Client` with the kit's `CheckoutCommunicationProtocol`: + +```swift +extension CheckoutProtocol.Client: @retroactive CheckoutCommunicationProtocol {} +``` + +### Creating a Client + +`CheckoutProtocol.Client` uses a fluent API to register event handlers: + +```swift +private let client = CheckoutProtocol.Client() + .on(CheckoutProtocol.start) { checkout in + print("Checkout started: \(checkout.id)") + } + .on(CheckoutProtocol.complete) { checkout in + print("Checkout completed: \(checkout.order?.id ?? "unknown")") + } +``` + +### Connecting to Accelerated Checkout Buttons + +Pass the client to `AcceleratedCheckoutButtons` using the `.connect()` modifier. Note that some event handlers like `.onFail` and `.onCancel` remain on the button view itself: + +```swift +AcceleratedCheckoutButtons(cartID: cartID) + .onFail { error in + print("SDK error: \(error)") + } + .onCancel { + print("Sheet cancelled") + } + .connect(client) +``` + +### Presenting with ShopifyCheckoutSheetKit + +Pass the client when presenting a checkout sheet: + +```swift +ShopifyCheckoutSheetKit.present(checkout: checkoutURL, delegate: client) +``` diff --git a/platforms/swift/Sources/ShopifyCheckoutProtocol/CheckoutProtocol+URL.swift b/protocol/languages/swift/Sources/ShopifyCheckoutProtocol/CheckoutProtocol+URL.swift similarity index 100% rename from platforms/swift/Sources/ShopifyCheckoutProtocol/CheckoutProtocol+URL.swift rename to protocol/languages/swift/Sources/ShopifyCheckoutProtocol/CheckoutProtocol+URL.swift diff --git a/platforms/swift/Sources/ShopifyCheckoutProtocol/CheckoutProtocol.swift b/protocol/languages/swift/Sources/ShopifyCheckoutProtocol/CheckoutProtocol.swift similarity index 100% rename from platforms/swift/Sources/ShopifyCheckoutProtocol/CheckoutProtocol.swift rename to protocol/languages/swift/Sources/ShopifyCheckoutProtocol/CheckoutProtocol.swift diff --git a/platforms/swift/Sources/ShopifyCheckoutProtocol/Client.swift b/protocol/languages/swift/Sources/ShopifyCheckoutProtocol/Client.swift similarity index 100% rename from platforms/swift/Sources/ShopifyCheckoutProtocol/Client.swift rename to protocol/languages/swift/Sources/ShopifyCheckoutProtocol/Client.swift diff --git a/platforms/swift/Sources/ShopifyCheckoutProtocol/Codec.swift b/protocol/languages/swift/Sources/ShopifyCheckoutProtocol/Codec.swift similarity index 100% rename from platforms/swift/Sources/ShopifyCheckoutProtocol/Codec.swift rename to protocol/languages/swift/Sources/ShopifyCheckoutProtocol/Codec.swift diff --git a/platforms/swift/Sources/ShopifyCheckoutProtocol/Descriptors.swift b/protocol/languages/swift/Sources/ShopifyCheckoutProtocol/Descriptors.swift similarity index 100% rename from platforms/swift/Sources/ShopifyCheckoutProtocol/Descriptors.swift rename to protocol/languages/swift/Sources/ShopifyCheckoutProtocol/Descriptors.swift diff --git a/platforms/swift/Sources/ShopifyCheckoutProtocol/Generated/Models.swift b/protocol/languages/swift/Sources/ShopifyCheckoutProtocol/Generated/Models.swift similarity index 100% rename from platforms/swift/Sources/ShopifyCheckoutProtocol/Generated/Models.swift rename to protocol/languages/swift/Sources/ShopifyCheckoutProtocol/Generated/Models.swift diff --git a/platforms/swift/Sources/ShopifyCheckoutProtocol/JSONRPCMessage.swift b/protocol/languages/swift/Sources/ShopifyCheckoutProtocol/JSONRPCMessage.swift similarity index 100% rename from platforms/swift/Sources/ShopifyCheckoutProtocol/JSONRPCMessage.swift rename to protocol/languages/swift/Sources/ShopifyCheckoutProtocol/JSONRPCMessage.swift diff --git a/platforms/swift/Sources/ShopifyCheckoutProtocol/MutableCopyable.swift b/protocol/languages/swift/Sources/ShopifyCheckoutProtocol/MutableCopyable.swift similarity index 100% rename from platforms/swift/Sources/ShopifyCheckoutProtocol/MutableCopyable.swift rename to protocol/languages/swift/Sources/ShopifyCheckoutProtocol/MutableCopyable.swift diff --git a/platforms/swift/Sources/ShopifyCheckoutProtocol/UCPMessage.swift b/protocol/languages/swift/Sources/ShopifyCheckoutProtocol/UCPMessage.swift similarity index 100% rename from platforms/swift/Sources/ShopifyCheckoutProtocol/UCPMessage.swift rename to protocol/languages/swift/Sources/ShopifyCheckoutProtocol/UCPMessage.swift diff --git a/platforms/swift/Tests/ShopifyCheckoutProtocolTests/ClientTests.swift b/protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/ClientTests.swift similarity index 100% rename from platforms/swift/Tests/ShopifyCheckoutProtocolTests/ClientTests.swift rename to protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/ClientTests.swift diff --git a/platforms/swift/Tests/ShopifyCheckoutProtocolTests/CodecDecodeTests.swift b/protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/CodecDecodeTests.swift similarity index 100% rename from platforms/swift/Tests/ShopifyCheckoutProtocolTests/CodecDecodeTests.swift rename to protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/CodecDecodeTests.swift diff --git a/platforms/swift/Tests/ShopifyCheckoutProtocolTests/CodecEncodeTests.swift b/protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/CodecEncodeTests.swift similarity index 100% rename from platforms/swift/Tests/ShopifyCheckoutProtocolTests/CodecEncodeTests.swift rename to protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/CodecEncodeTests.swift diff --git a/platforms/swift/Tests/ShopifyCheckoutProtocolTests/DescriptorTests.swift b/protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/DescriptorTests.swift similarity index 100% rename from platforms/swift/Tests/ShopifyCheckoutProtocolTests/DescriptorTests.swift rename to protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/DescriptorTests.swift diff --git a/platforms/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/.gitkeep b/protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/.gitkeep similarity index 100% rename from platforms/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/.gitkeep rename to protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/.gitkeep diff --git a/platforms/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/notification.json b/protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/notification.json similarity index 100% rename from platforms/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/notification.json rename to protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/notification.json diff --git a/platforms/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/ready_response.json b/protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/ready_response.json similarity index 100% rename from platforms/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/ready_response.json rename to protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/ready_response.json diff --git a/platforms/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/request.json b/protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/request.json similarity index 100% rename from platforms/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/request.json rename to protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/Fixtures/request.json diff --git a/platforms/swift/Tests/ShopifyCheckoutProtocolTests/ModelDecodingTests.swift b/protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/ModelDecodingTests.swift similarity index 100% rename from platforms/swift/Tests/ShopifyCheckoutProtocolTests/ModelDecodingTests.swift rename to protocol/languages/swift/Tests/ShopifyCheckoutProtocolTests/ModelDecodingTests.swift diff --git a/protocol/scripts/generate_models.sh b/protocol/scripts/generate_models.sh index 4815b01a..3dd6d539 100755 --- a/protocol/scripts/generate_models.sh +++ b/protocol/scripts/generate_models.sh @@ -210,7 +210,7 @@ case "$LANG" in ;; swift) - OUTPUT="${REPO_ROOT}/platforms/swift/Sources/ShopifyCheckoutProtocol/Generated/Models.swift" + OUTPUT="${REPO_ROOT}/protocol/languages/swift/Sources/ShopifyCheckoutProtocol/Generated/Models.swift" quicktype \ --lang swift \ --swift-5-support \