From fda98d33df3000a5bb809906bf2f71131f960fa8 Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Tue, 14 Jul 2026 00:10:19 -0400 Subject: [PATCH 1/9] Enable embedded SQLite for Android builds Android has no system libsqlite3, so force the SQLiteSwiftCSQLite trait instead of relying on SQLite.swift's os(Linux)-only default. --- Package.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 08f219d..756b161 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 6.0 +// swift-tools-version: 6.1 import PackageDescription let package = Package( @@ -22,7 +22,8 @@ let package = Package( ), .package( url: "https://github.com/stephencelis/SQLite.swift.git", - from: "0.16.0" + from: "0.16.0", + traits: ["SQLiteSwiftCSQLite"] ) ], targets: [ From 6890be21529cd5300a8b711fda18cbdddcfd9f9c Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Tue, 14 Jul 2026 00:10:24 -0400 Subject: [PATCH 2/9] Pin toolchain to Swift 6.3.2 for Android SDK compatibility The published Android Swift SDK artifact bundle is built against 6.3.2; a newer host compiler can't import its precompiled modules. --- .swift-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .swift-version diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..f9da12e --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +6.3.2 \ No newline at end of file From ef94dab7129c7e8be784efcc0dbc91f07e7c9d3b Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Tue, 14 Jul 2026 00:10:31 -0400 Subject: [PATCH 3/9] Add Android build job to CI Installs the matching NDK and Swift Android SDK artifact bundle on a macOS runner, then builds debug and release for aarch64-android. --- .github/workflows/swift.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 46783f5..0abfaac 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -37,3 +37,32 @@ jobs: run: swift build -c ${{ matrix.config }} - name: Test run: swift test -c ${{ matrix.config }} + + android: + name: Android + runs-on: macos-15 + strategy: + fail-fast: false + matrix: + config: ["debug", "release"] + env: + SWIFT_VERSION: "6.3.2" + ANDROID_NDK_VERSION: "27.2.12479018" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install Swift + uses: swift-actions/setup-swift@v2 + with: + swift-version: ${{ env.SWIFT_VERSION }} + - name: Install Android NDK + run: $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --install "ndk;${{ env.ANDROID_NDK_VERSION }}" + - name: Install Swift SDK for Android + run: | + curl -L -o android-sdk.artifactbundle.tar.gz "https://download.swift.org/swift-${{ env.SWIFT_VERSION }}-release/android-sdk/swift-${{ env.SWIFT_VERSION }}-RELEASE/swift-${{ env.SWIFT_VERSION }}-RELEASE_android.artifactbundle.tar.gz" + CHECKSUM=$(swift package compute-checksum android-sdk.artifactbundle.tar.gz) + swift sdk install android-sdk.artifactbundle.tar.gz --checksum "$CHECKSUM" + ANDROID_NDK_HOME="$ANDROID_HOME/ndk/${{ env.ANDROID_NDK_VERSION }}" \ + bash "$HOME/Library/org.swift.swiftpm/swift-sdks/swift-${{ env.SWIFT_VERSION }}-RELEASE_android.artifactbundle/swift-android/scripts/setup-android-sdk.sh" + - name: Build + run: swift build --swift-sdk aarch64-unknown-linux-android28 -c ${{ matrix.config }} From d9ae10aca8d84079e54d38b283ed2df2b7737ce3 Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Tue, 14 Jul 2026 00:25:35 -0400 Subject: [PATCH 4/9] Run unit tests on an Android emulator in CI Nested virtualization for the emulator isn't available on the macOS runner used for the build job, so this runs on ubuntu-latest via the swift-android-action, pinned to the same SDK artifact bundle already used for building. --- .github/workflows/swift.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 0abfaac..3779cbb 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -66,3 +66,24 @@ jobs: bash "$HOME/Library/org.swift.swiftpm/swift-sdks/swift-${{ env.SWIFT_VERSION }}-RELEASE_android.artifactbundle/swift-android/scripts/setup-android-sdk.sh" - name: Build run: swift build --swift-sdk aarch64-unknown-linux-android28 -c ${{ matrix.config }} + + android-test: + name: Android Test + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + config: ["debug", "release"] + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Test on Android emulator + uses: skiptools/swift-android-action@v2 + with: + swift-version: "6.3.2" + custom-sdk-id: swift-6.3.2-RELEASE_android + custom-sdk-url: https://download.swift.org/swift-6.3.2-release/android-sdk/swift-6.3.2-RELEASE/swift-6.3.2-RELEASE_android.artifactbundle.tar.gz + android-api-level: 28 + swift-configuration: ${{ matrix.config }} + free-disk-space: true + run-tests: true From 95db37e45738fcb96bf52196e2a9c06265e6c4f7 Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Tue, 14 Jul 2026 00:36:38 -0400 Subject: [PATCH 5/9] Fix Android CI: install Swift via swiftly, drop invalid custom SDK inputs swift-actions/setup-swift doesn't yet recognize 6.3.2 on macOS, so install it directly with swiftly instead. Also drop custom-sdk-url without installed-sdk on the emulator test job, which the action rejects; its default resolution already fetches the same official 6.3.2 android-sdk artifact bundle. --- .github/workflows/swift.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 3779cbb..cdca3f1 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -52,9 +52,15 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Install Swift - uses: swift-actions/setup-swift@v2 - with: - swift-version: ${{ env.SWIFT_VERSION }} + run: | + curl -O https://download.swift.org/swiftly/darwin/swiftly.pkg + installer -pkg swiftly.pkg -target CurrentUserHomeDirectory + ~/.swiftly/bin/swiftly init --assume-yes --skip-install + echo "$HOME/.swiftly/bin" >> "$GITHUB_PATH" + source ~/.swiftly/env.sh + swiftly install ${{ env.SWIFT_VERSION }} + swiftly use ${{ env.SWIFT_VERSION }} + echo "$(swiftly use --print-location)/usr/bin" >> "$GITHUB_PATH" - name: Install Android NDK run: $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --install "ndk;${{ env.ANDROID_NDK_VERSION }}" - name: Install Swift SDK for Android @@ -81,8 +87,6 @@ jobs: uses: skiptools/swift-android-action@v2 with: swift-version: "6.3.2" - custom-sdk-id: swift-6.3.2-RELEASE_android - custom-sdk-url: https://download.swift.org/swift-6.3.2-release/android-sdk/swift-6.3.2-RELEASE/swift-6.3.2-RELEASE_android.artifactbundle.tar.gz android-api-level: 28 swift-configuration: ${{ matrix.config }} free-disk-space: true From 414ad099e8fb72ca2bba0322f409fd1d374f10fd Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Tue, 14 Jul 2026 00:42:47 -0400 Subject: [PATCH 6/9] Only run Android emulator tests in debug configuration The action builds tests with plain 'swift build', which doesn't enable testability for release builds, breaking the @testable imports in CoreModelSQLiteTests. Debug-only matches how swift test is normally used for @testable suites. --- .github/workflows/swift.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index cdca3f1..c93f157 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -76,10 +76,6 @@ jobs: android-test: name: Android Test runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - config: ["debug", "release"] steps: - name: Checkout uses: actions/checkout@v4 @@ -88,6 +84,6 @@ jobs: with: swift-version: "6.3.2" android-api-level: 28 - swift-configuration: ${{ matrix.config }} + swift-configuration: debug free-disk-space: true run-tests: true From 006445729b91a6c88aee3b47d13548e2759e336f Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Tue, 14 Jul 2026 00:56:47 -0400 Subject: [PATCH 7/9] Only force embedded SQLite for Android macOS and Linux keep SQLite.swift's own default trait for the platform (system SQLite on Apple, embedded on Linux); Android is the only target that needs the embedded copy forced, detected via the TARGET_OS_ANDROID env var set when cross-compiling. --- Package.swift | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Package.swift b/Package.swift index 756b161..691e1b2 100644 --- a/Package.swift +++ b/Package.swift @@ -1,5 +1,21 @@ // swift-tools-version: 6.1 import PackageDescription +import Foundation + +// Android has no system libsqlite3, so it needs SQLite.swift's embedded +// copy. macOS and Linux keep SQLite.swift's own default for the platform. +let isAndroid = ProcessInfo.processInfo.environment["TARGET_OS_ANDROID"] == "1" + +let sqliteDependency: Package.Dependency = isAndroid + ? .package( + url: "https://github.com/stephencelis/SQLite.swift.git", + from: "0.16.0", + traits: ["SQLiteSwiftCSQLite"] + ) + : .package( + url: "https://github.com/stephencelis/SQLite.swift.git", + from: "0.16.0" + ) let package = Package( name: "CoreModel-SQLite", @@ -20,11 +36,7 @@ let package = Package( url: "https://github.com/PureSwift/CoreModel", from: "2.6.3" ), - .package( - url: "https://github.com/stephencelis/SQLite.swift.git", - from: "0.16.0", - traits: ["SQLiteSwiftCSQLite"] - ) + sqliteDependency ], targets: [ .target( From 889117d132918bc47d9e3fb91f8cd42fa6cff2a7 Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Tue, 14 Jul 2026 00:56:52 -0400 Subject: [PATCH 8/9] Add iOS build/test CI job and set TARGET_OS_ANDROID for the Android build The iOS job builds for the simulator platform and runs the test suite against a dynamically selected available iPhone simulator, so it doesn't depend on any particular simulator name existing on the runner image. The Android job now exports TARGET_OS_ANDROID=1 so Package.swift picks the embedded SQLite trait. --- .github/workflows/swift.yml | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index c93f157..45fd676 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -71,7 +71,34 @@ jobs: ANDROID_NDK_HOME="$ANDROID_HOME/ndk/${{ env.ANDROID_NDK_VERSION }}" \ bash "$HOME/Library/org.swift.swiftpm/swift-sdks/swift-${{ env.SWIFT_VERSION }}-RELEASE_android.artifactbundle/swift-android/scripts/setup-android-sdk.sh" - name: Build - run: swift build --swift-sdk aarch64-unknown-linux-android28 -c ${{ matrix.config }} + run: TARGET_OS_ANDROID=1 swift build --swift-sdk aarch64-unknown-linux-android28 -c ${{ matrix.config }} + + ios: + name: iOS + runs-on: macos-26 + strategy: + fail-fast: false + matrix: + config: ["debug", "release"] + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Select Simulator + run: | + DEVICE_ID=$(xcrun simctl list devices available -j | python3 -c "import json,sys; d=json.load(sys.stdin)['devices']; devices=[v for vs in d.values() for v in vs if 'iPhone' in v['name']]; print(devices[0]['udid'])") + echo "DEVICE_ID=${DEVICE_ID}" >> "$GITHUB_ENV" + - name: Build + run: > + xcodebuild build -scheme CoreModel-SQLite + -destination "generic/platform=iOS Simulator" + -configuration ${{ matrix.config == 'release' && 'Release' || 'Debug' }} + -skipMacroValidation -skipPackagePluginValidation + - name: Test + run: > + xcodebuild test -scheme CoreModel-SQLite + -destination "id=${{ env.DEVICE_ID }}" + -configuration ${{ matrix.config == 'release' && 'Release' || 'Debug' }} + -skipMacroValidation -skipPackagePluginValidation android-test: name: Android Test From c8c3b8921df62e217ce5059989a3139a6510bab4 Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Tue, 14 Jul 2026 01:11:56 -0400 Subject: [PATCH 9/9] Fix iOS Release testing and separate build/test destinations Xcode's explicit-module build system was caching the Release CoreModelSQLite module without testability even on a clean DerivedData, breaking @testable import; ENABLE_TESTABILITY=YES forces it regardless of configuration. Also point the plain Build step at the device platform instead of the simulator so it can't collide with the Test step's simulator DerivedData. --- .github/workflows/swift.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 45fd676..443c6fc 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -90,7 +90,7 @@ jobs: - name: Build run: > xcodebuild build -scheme CoreModel-SQLite - -destination "generic/platform=iOS Simulator" + -destination "generic/platform=iOS" -configuration ${{ matrix.config == 'release' && 'Release' || 'Debug' }} -skipMacroValidation -skipPackagePluginValidation - name: Test @@ -99,6 +99,7 @@ jobs: -destination "id=${{ env.DEVICE_ID }}" -configuration ${{ matrix.config == 'release' && 'Release' || 'Debug' }} -skipMacroValidation -skipPackagePluginValidation + ENABLE_TESTABILITY=YES android-test: name: Android Test