From 135bfbc65f49faf1d57bb3645dd43a2d93305b0d Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Fri, 27 Mar 2026 10:48:43 -0400 Subject: [PATCH 01/10] ci: add GitHub Actions workflow to run unit tests on PRs Clones sibling local packages (reticulum-swift, LXMF-swift, LXST-swift) and runs ColumbaAppTests on iOS Simulator. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/tests.yml | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..bf8d193 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,39 @@ +name: Tests + +on: + pull_request: + branches: [main] + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: macos-15 + steps: + - uses: actions/checkout@v4 + + - name: Clone sibling packages + run: | + git clone https://github.com/torlando-tech/reticulum-swift.git ../reticulum-swift + git clone https://github.com/torlando-tech/LXMF-swift.git ../LXMF-swift + git clone https://github.com/torlando-tech/LXST-swift.git ../LXST-swift + + - name: Select Xcode + run: sudo xcode-select -s /Applications/Xcode_16.2.app + + - name: Resolve packages + run: xcodebuild -resolvePackageDependencies -project ColumbaApp.xcodeproj -scheme ColumbaApp + + - name: Run tests + run: | + xcodebuild test \ + -project ColumbaApp.xcodeproj \ + -scheme ColumbaApp \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 16' \ + -only-testing:ColumbaAppTests \ + -resultBundlePath TestResults.xcresult From 3f7bbf2ebfdf596712a3e8db217004b4ddea3e7d Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Fri, 27 Mar 2026 10:55:46 -0400 Subject: [PATCH 02/10] ci: disable code signing for CI test builds The app module failed to build on CI due to missing provisioning profiles. Skip signing since we only need to run unit tests. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/tests.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bf8d193..57735c4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,4 +36,7 @@ jobs: -sdk iphonesimulator \ -destination 'platform=iOS Simulator,name=iPhone 16' \ -only-testing:ColumbaAppTests \ - -resultBundlePath TestResults.xcresult + -resultBundlePath TestResults.xcresult \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO From 0362f969a7a1046a3c464613da893d10c840ea08 Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Fri, 27 Mar 2026 10:57:30 -0400 Subject: [PATCH 03/10] ci: auto-detect Xcode version and simulator destination The runner may not have Xcode 16.2 or iPhone 16 simulator installed. Dynamically find the latest Xcode 16.x and an available iOS Simulator. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/tests.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 57735c4..dcb1c52 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,19 @@ jobs: git clone https://github.com/torlando-tech/LXST-swift.git ../LXST-swift - name: Select Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app + run: | + XCODE=$(ls -d /Applications/Xcode_16*.app 2>/dev/null | sort -V | tail -1) + echo "Using $XCODE" + sudo xcode-select -s "$XCODE" + + - name: Find simulator destination + id: dest + run: | + DEST=$(xcodebuild -showdestinations -project ColumbaApp.xcodeproj -scheme ColumbaApp 2>/dev/null \ + | grep 'iOS Simulator' | grep 'iPhone' | head -1 \ + | sed 's/.*{ //' | sed 's/ }$//') + echo "destination=$DEST" >> "$GITHUB_OUTPUT" + echo "Using destination: $DEST" - name: Resolve packages run: xcodebuild -resolvePackageDependencies -project ColumbaApp.xcodeproj -scheme ColumbaApp @@ -34,7 +46,7 @@ jobs: -project ColumbaApp.xcodeproj \ -scheme ColumbaApp \ -sdk iphonesimulator \ - -destination 'platform=iOS Simulator,name=iPhone 16' \ + -destination '${{ steps.dest.outputs.destination }}' \ -only-testing:ColumbaAppTests \ -resultBundlePath TestResults.xcresult \ CODE_SIGN_IDENTITY="" \ From 2ec54256d63770e35a63c208acf7f7b2ff885030 Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Fri, 27 Mar 2026 10:59:19 -0400 Subject: [PATCH 04/10] ci: dynamically find available iPhone simulator for test runs Use xcrun simctl to find the first available iPhone simulator by UUID instead of hardcoding a device name that may not exist on the runner. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/tests.yml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dcb1c52..8a7c8b5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,26 +27,23 @@ jobs: XCODE=$(ls -d /Applications/Xcode_16*.app 2>/dev/null | sort -V | tail -1) echo "Using $XCODE" sudo xcode-select -s "$XCODE" - - - name: Find simulator destination - id: dest - run: | - DEST=$(xcodebuild -showdestinations -project ColumbaApp.xcodeproj -scheme ColumbaApp 2>/dev/null \ - | grep 'iOS Simulator' | grep 'iPhone' | head -1 \ - | sed 's/.*{ //' | sed 's/ }$//') - echo "destination=$DEST" >> "$GITHUB_OUTPUT" - echo "Using destination: $DEST" + xcodebuild -version + xcrun simctl list devices available | grep iPhone | head -5 - name: Resolve packages run: xcodebuild -resolvePackageDependencies -project ColumbaApp.xcodeproj -scheme ColumbaApp - name: Run tests run: | + # Find first available iPhone simulator + DEVICE_ID=$(xcrun simctl list devices available -j \ + | python3 -c "import sys,json; devs=json.load(sys.stdin)['devices']; print(next(d['udid'] for rt in devs for d in devs[rt] if 'iPhone' in d['name']))") + echo "Using simulator: $DEVICE_ID" xcodebuild test \ -project ColumbaApp.xcodeproj \ -scheme ColumbaApp \ -sdk iphonesimulator \ - -destination '${{ steps.dest.outputs.destination }}' \ + -destination "id=$DEVICE_ID" \ -only-testing:ColumbaAppTests \ -resultBundlePath TestResults.xcresult \ CODE_SIGN_IDENTITY="" \ From 9cf36cfa9be8e99ae4db115b97547fe78b7ea9d3 Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Fri, 27 Mar 2026 11:02:48 -0400 Subject: [PATCH 05/10] ci: use ad-hoc signing for CI builds Use CODE_SIGN_IDENTITY=- (ad-hoc) instead of disabling signing entirely, so the app and network extension targets can still be built and linked. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/tests.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8a7c8b5..f07b35a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -46,6 +46,8 @@ jobs: -destination "id=$DEVICE_ID" \ -only-testing:ColumbaAppTests \ -resultBundlePath TestResults.xcresult \ - CODE_SIGN_IDENTITY="" \ + CODE_SIGN_IDENTITY=- \ CODE_SIGNING_REQUIRED=NO \ - CODE_SIGNING_ALLOWED=NO + CODE_SIGNING_ALLOWED=YES \ + DEVELOPMENT_TEAM="" \ + PROVISIONING_PROFILE_SPECIFIER="" From b7fd2cde61d0f58cb953b0da23d0aa67620c032c Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Fri, 27 Mar 2026 11:06:34 -0400 Subject: [PATCH 06/10] ci: split into build-for-testing and test-without-building steps Separate the build and test phases so we can see exactly where the failure occurs. The app module wasn't being compiled before the test target tried to import it. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/tests.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f07b35a..a5b74ed 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -33,21 +33,33 @@ jobs: - name: Resolve packages run: xcodebuild -resolvePackageDependencies -project ColumbaApp.xcodeproj -scheme ColumbaApp - - name: Run tests + - name: Find simulator + id: sim run: | - # Find first available iPhone simulator DEVICE_ID=$(xcrun simctl list devices available -j \ | python3 -c "import sys,json; devs=json.load(sys.stdin)['devices']; print(next(d['udid'] for rt in devs for d in devs[rt] if 'iPhone' in d['name']))") + echo "device_id=$DEVICE_ID" >> "$GITHUB_OUTPUT" echo "Using simulator: $DEVICE_ID" - xcodebuild test \ + + - name: Build for testing + run: | + xcodebuild build-for-testing \ -project ColumbaApp.xcodeproj \ -scheme ColumbaApp \ -sdk iphonesimulator \ - -destination "id=$DEVICE_ID" \ - -only-testing:ColumbaAppTests \ - -resultBundlePath TestResults.xcresult \ + -destination "id=${{ steps.sim.outputs.device_id }}" \ CODE_SIGN_IDENTITY=- \ CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=YES \ DEVELOPMENT_TEAM="" \ PROVISIONING_PROFILE_SPECIFIER="" + + - name: Run tests + run: | + xcodebuild test-without-building \ + -project ColumbaApp.xcodeproj \ + -scheme ColumbaApp \ + -sdk iphonesimulator \ + -destination "id=${{ steps.sim.outputs.device_id }}" \ + -only-testing:ColumbaAppTests \ + -resultBundlePath TestResults.xcresult From 514baaf2f798d5d748a50897842f4d910759c0ce Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Fri, 27 Mar 2026 11:09:37 -0400 Subject: [PATCH 07/10] ci: add verbose build logging to diagnose ColumbaApp compilation failure Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/tests.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a5b74ed..cf2e386 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -43,6 +43,7 @@ jobs: - name: Build for testing run: | + set -o pipefail xcodebuild build-for-testing \ -project ColumbaApp.xcodeproj \ -scheme ColumbaApp \ @@ -52,7 +53,9 @@ jobs: CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=YES \ DEVELOPMENT_TEAM="" \ - PROVISIONING_PROFILE_SPECIFIER="" + PROVISIONING_PROFILE_SPECIFIER="" 2>&1 | tee /tmp/build.log + echo "=== Build errors ===" + grep 'error:' /tmp/build.log || echo "No errors found" - name: Run tests run: | From 548553d73ec16948998a2f808db0fcd703e7a96a Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Fri, 27 Mar 2026 11:12:44 -0400 Subject: [PATCH 08/10] ci: explicitly build app target before running tests Build the ColumbaApp target first to ensure the Swift module exists before the test target tries to import it. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/tests.yml | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cf2e386..d3335b3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -41,28 +41,32 @@ jobs: echo "device_id=$DEVICE_ID" >> "$GITHUB_OUTPUT" echo "Using simulator: $DEVICE_ID" - - name: Build for testing + - name: Build app target run: | - set -o pipefail - xcodebuild build-for-testing \ + xcodebuild build \ -project ColumbaApp.xcodeproj \ -scheme ColumbaApp \ -sdk iphonesimulator \ -destination "id=${{ steps.sim.outputs.device_id }}" \ + -target ColumbaApp \ + ENABLE_TESTABILITY=YES \ CODE_SIGN_IDENTITY=- \ CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=YES \ DEVELOPMENT_TEAM="" \ - PROVISIONING_PROFILE_SPECIFIER="" 2>&1 | tee /tmp/build.log - echo "=== Build errors ===" - grep 'error:' /tmp/build.log || echo "No errors found" + PROVISIONING_PROFILE_SPECIFIER="" - - name: Run tests + - name: Build and run tests run: | - xcodebuild test-without-building \ + xcodebuild test \ -project ColumbaApp.xcodeproj \ -scheme ColumbaApp \ -sdk iphonesimulator \ -destination "id=${{ steps.sim.outputs.device_id }}" \ -only-testing:ColumbaAppTests \ - -resultBundlePath TestResults.xcresult + -resultBundlePath TestResults.xcresult \ + CODE_SIGN_IDENTITY=- \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=YES \ + DEVELOPMENT_TEAM="" \ + PROVISIONING_PROFILE_SPECIFIER="" From 308a4000afded46e314bf218f7e9ef0c65daa29d Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Fri, 27 Mar 2026 11:14:32 -0400 Subject: [PATCH 09/10] ci: fix -target and -scheme conflict in build step Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d3335b3..3dc7407 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -45,10 +45,9 @@ jobs: run: | xcodebuild build \ -project ColumbaApp.xcodeproj \ - -scheme ColumbaApp \ + -target ColumbaApp \ -sdk iphonesimulator \ -destination "id=${{ steps.sim.outputs.device_id }}" \ - -target ColumbaApp \ ENABLE_TESTABILITY=YES \ CODE_SIGN_IDENTITY=- \ CODE_SIGNING_REQUIRED=NO \ From 3c1ce4ff1fea63a0b02076e5c336817b148742ae Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Fri, 27 Mar 2026 11:18:21 -0400 Subject: [PATCH 10/10] ci: build app with scheme first, then run tests separately Use scheme-based build (which resolves SPM deps correctly) as a separate step before running tests, ensuring the ColumbaApp module is fully compiled before the test target imports it. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/tests.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3dc7407..ed2fd28 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,10 +28,6 @@ jobs: echo "Using $XCODE" sudo xcode-select -s "$XCODE" xcodebuild -version - xcrun simctl list devices available | grep iPhone | head -5 - - - name: Resolve packages - run: xcodebuild -resolvePackageDependencies -project ColumbaApp.xcodeproj -scheme ColumbaApp - name: Find simulator id: sim @@ -41,14 +37,13 @@ jobs: echo "device_id=$DEVICE_ID" >> "$GITHUB_OUTPUT" echo "Using simulator: $DEVICE_ID" - - name: Build app target + - name: Build run: | xcodebuild build \ -project ColumbaApp.xcodeproj \ - -target ColumbaApp \ + -scheme ColumbaApp \ -sdk iphonesimulator \ -destination "id=${{ steps.sim.outputs.device_id }}" \ - ENABLE_TESTABILITY=YES \ CODE_SIGN_IDENTITY=- \ CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=YES \