Skip to content

ci(swift): add pipeline with BrowserStack integration - #152

Merged
Teodor Ciuraru (teodorciuraru) merged 136 commits into
mainfrom
teodor/add-swift-browserstack-pipeline
Sep 8, 2025
Merged

Teodor Ciuraru (teodorciuraru) merged 136 commits into
mainfrom
teodor/add-swift-browserstack-pipeline

Conversation

@teodorciuraru

@teodorciuraru Teodor Ciuraru (teodorciuraru) commented Sep 2, 2025 •

Copy link
Copy Markdown
Contributor

Summary

This PR adds comprehensive Swift CI with efficient parallel builds and BrowserStack real device testing. The architecture follows: lint → build macOS & iOS in parallel → move iOS artifacts to BrowserStack → test Ditto cloud sync → report results. We chose this approach to eliminate redundant builds, maximize CI speed with parallel execution, and provide real device validation through BrowserStack integration that tests actual Ditto cloud synchronization.

Key Features

  • Parallel Efficiency: macOS and iOS builds run simultaneously after linting passes
  • Artifact Reuse: iOS .ipa built once, shared with BrowserStack (no rebuilding)
  • Real Device Testing: BrowserStack iPhone 15 Pro testing with XCUITest bundles
  • Ditto Cloud Integration: Tests actual sync by seeding documents via API, validating on device
  • Inverted Timestamp: GitHub-seeded documents appear at top of list for reliable detection

Technical Implementation

  • Clean Dependencies: lint → [build-macos + build-ios] → browserstack → summary
  • No Redundant Steps: Each job runs once, production credentials generated per job
  • XCUITest Integration: Real UI tests on BrowserStack with environment variable injection
  • Document Seeding: HTTP API v4 creates test documents, XCUITest verifies sync on device
  • Efficient Workflow: BrowserStack only runs if iOS build succeeds, uses shared artifacts

Test Plan

  • Parallel builds working (macOS + iOS simultaneously)
  • iOS artifact properly shared with BrowserStack job
  • XCUITest bundles created and uploaded successfully
  • Document seeding and sync validation working end-to-end
  • BrowserStack real device testing passes
  • Clean scheme configuration (removed hardcoded test values)
  • No redundant files (removed unused TasksUITests.xcscheme)

Architecture Benefits

  • Speed: Parallel builds reduce total CI time
  • Efficiency: Zero duplicate builds or credential generation
  • Reliability: Real device testing catches platform-specific issues
  • Maintainability: Clean workflow structure with clear job dependencies

🤖 Generated with Claude Code

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- Add Swift CI pipeline with lint, build iOS/macOS, and real integration tests
- Add Swift BrowserStack pipeline for real device testing on iPhone/iPad
- Integration tests verify actual Ditto cloud sync functionality
- Tests include API document insertion and CRUD operations with cloud backend
- BrowserStack uploads unsigned .app bundles for real device validation
- Follows same naming conventions as other platform pipelines

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

This comment was marked as outdated.

Teodor Ciuraru and others added 4 commits September 2, 2025 13:01
- Enable cloud sync in integration tests (enableDittoCloudSync: true)
- Add missing TestRunner.swift file referenced by CI
- Create proper Appium test files instead of dynamic generation
- Clean up misleading API insertion comments
- Fix failing CI integration test step

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Fix macOS head command compatibility (head -n-1 -> head -n -1)
- Fix BrowserStack upload path resolution (swift/build vs build)
- Improve BrowserStack upload format (zip instead of tar.gz)
- Add better debugging for path resolution issues
- Remove .brs file requirement (not needed for iOS .app bundles)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Change 'Swift CI Enhanced' to 'Swift CI' to match naming convention
- Keeps consistency with other platform pipelines (React Native CI, etc.)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Fix iOS build destination from simulator to real device (generic/platform=iOS)
- Package unsigned .ipa in proper Payload format for BrowserStack
- Update upload step to use .ipa file directly instead of zipped .app bundle
- Addresses BrowserStack iOS real device testing requirements

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

This comment was marked as outdated.

Teodor Ciuraru and others added 7 commits September 2, 2025 13:39
- Remove curl API call that duplicates SDK functionality
- Integration tests already use Ditto SDK with DQL for cloud sync testing
- Simplifies workflow and removes dependency on DITTO_API_KEY secret

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
… API

- Add export-options.plist for unsigned ad-hoc distribution
- Replace manual .ipa creation with xcodebuild -exportArchive
- Use BrowserStack Maestro v2 endpoint (/maestro/v2/app) for iOS uploads
- This ensures proper device .ipa format that BrowserStack can re-sign and install

Addresses the 500 errors caused by uploading zipped .app bundles instead of proper .ipa files to BrowserStack real device testing.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Change export method from 'ad-hoc' to 'none' for completely unsigned distribution
- Remove team-related signing options that were causing export failures
- This allows xcodebuild -exportArchive to work without requiring team/certificate

Fixes: error: exportArchive No Team Found in Archive

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
The exportArchive command expects valid methods: app-store-connect, release-testing, enterprise, debugging, or validation. Using 'debugging' for unsigned development builds that BrowserStack can re-sign.

Fixes: exportArchive exportOptionsPlist error for key "method"

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove xcodebuild -exportArchive which requires signing team/method
- Return to manual Payload zip approach: archive -> extract .app -> zip to IPA
- Use standard /app-automate/upload endpoint (BrowserStack will re-sign)
- Remove unused export-options.plist file

This avoids "No Team Found in Archive" errors while creating proper unsigned IPA that BrowserStack can re-sign for real device testing.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
The IPA is created at swift/build/Tasks-unsigned.ipa but validation was looking in swift/build/ipa/. Fix validation to look in correct location.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

This comment was marked as outdated.

Comment thread .github/workflows/swift-browserstack.yml Outdated
- Remove unused Appium iOS Testing job from BrowserStack workflow
- Remove experimental test files (LocalTestRunner, BasicConnectivityTest, AppiumTests)
- Clean up experimental comments and debug code
- Keep only production-ready components: real integration tests and CI workflows

Pipeline is now pristine and ready for production use.
@teodorciuraru
Teodor Ciuraru (teodorciuraru) changed the base branch from main to nr/swift-ci-build September 2, 2025 11:55
Teodor Ciuraru and others added 13 commits September 4, 2025 17:51
…single pipeline

BREAKING CHANGE: Replaced swift-ci.yml and swift-browserstack.yml with unified swift.yml

New workflow structure:
- lint → build-ios + build-macos (parallel)
- browserstack-test (only if iOS build succeeds)
- summary (comprehensive results)

Key improvements:
- ✅ No duplicate builds - reuse artifacts efficiently
- ✅ Smart dependency chain - BrowserStack only runs if iOS build succeeds
- ✅ Proper test credentials vs production credentials separation
- ✅ Comprehensive summary with detailed status reporting
- ✅ Fixed intentionally broken test (removed 'abc' suffix)
- ✅ Enhanced logging maintained for debugging

Pipeline flow:
1. Lint code quality
2. Build iOS (simulator) + Build macOS (parallel, after lint)
3. IF iOS build succeeds → Build iOS device + XCUITest + BrowserStack testing
4. Summary with detailed results and status

This creates a production-ready, efficient CI/CD pipeline for Swift apps.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
…line

Major efficiency improvements:
- ✅ Single environment setup job generates test credentials once
- ✅ Reuse Env.swift via artifacts instead of regenerating 4 times
- ✅ Build iOS device .ipa once in build-ios job, reuse in BrowserStack
- ✅ No more duplicate iOS builds between CI and BrowserStack stages
- ✅ BrowserStack only generates production credentials (not test ones)

New flow:
setup-test-env (once) → lint + build-ios + build-macos (reuse env) → browserstack-test (reuse .ipa)

Performance benefits:
- ~3-4 minutes saved by not rebuilding iOS device archive
- Faster job startup with cached artifacts
- Reduced GitHub Actions compute usage
- Cleaner dependency chain

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Reverted consolidation that caused compilation errors
- Restored separate swift-ci.yml and swift-browserstack.yml workflows
- Fixed test to remove intentionally broken logic (removed 'abc' suffix)
- Ready to test working BrowserStack pipeline

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Modified BrowserStack workflow to seed documents with inverted timestamp prefix
- Updated XCUITest to search by suffix pattern instead of exact match
- Document ID format: {inverted_timestamp}_ci_test_{run_id}_{run_number}
- Inverted timestamp = 9999999999 - current_timestamp ensures top position
- Enhanced logging to show timestamp conversion and improved match detection

This guarantees the GitHub-seeded document will always be the first item in the
sorted list, making tests more reliable and faster to execute.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
The previous commit only included the test file changes but missed the
workflow file that implements the inverted timestamp logic.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Merged swift-ci.yml and swift-browserstack.yml into single efficient pipeline
- Build iOS once and share .ipa artifact with BrowserStack job
- Share Env.swift artifact across all jobs to avoid regeneration
- Flow: setup-env → lint + build → browserstack → summary
- BrowserStack job only runs if iOS build succeeds
- Eliminated duplicate builds and credential generation
- Added proper job dependencies and conditional execution
- Enhanced summary reporting with artifact reuse confirmation

This reduces CI time and resource usage while maintaining all functionality.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
The previous version was using test credentials from the setup-env artifact,
which created an Env.swift file with 'test_app_id' values that caused compilation
errors. Now the build job generates its own Env.swift with production secrets.

- Build job now uses production credentials for compilation
- BrowserStack job still generates its own Env.swift for XCUITest builds
- Eliminates Env.swift artifact dependency that was causing the compilation failure
- Maintains artifact reuse for iOS .ipa file between build and BrowserStack jobs

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Maintains the same naming pattern as other workflows in the repository.
The consolidated workflow remains efficient with artifact reuse while
following established naming conventions.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Restructured to eliminate redundant steps and achieve optimal flow:
- lint → build macOS & iOS in parallel → BrowserStack with artifacts → report
- Removed setup-env job (was creating unused test artifacts)
- Removed redundant credential generation across multiple jobs
- macOS and iOS builds now run simultaneously after lint passes
- BrowserStack downloads iOS .ipa artifact (no rebuilding)
- Clean dependency chain with no repeated steps
- macOS can fail independently without affecting iOS→BrowserStack flow

This achieves maximum efficiency while maintaining full functionality.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Removed unnecessary files from PR:
- TasksUITests.xcscheme: Redundant scheme (workflow uses only Tasks scheme)
- browserstack-test.py: Wrong platform (JavaScript/Selenium instead of Swift/XCUITest)
- .github/scripts/ directory: Now empty after removing Python script
- Hardcoded environment variables from Tasks.xcscheme (workflow passes these dynamically)

This eliminates confusion and keeps only the files actually used by the Swift workflow.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
The JavaScript/Selenium testing script removal was out of scope for this
Swift CI PR. Restoring it to keep the PR focused only on Swift changes.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@teodorciuraru
Teodor Ciuraru (teodorciuraru) marked this pull request as ready for review September 4, 2025 16:38
- GitHub Actions now passes exact GITHUB_TEST_DOC_TITLE via BrowserStack setEnvVariables
- Swift test uses exact string matching instead of suffix matching
- Eliminates ambiguity and ensures precise document detection
- Test fails fast if environment variable is missing
- More reliable and deterministic testing approach

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

This comment was marked as outdated.

- Make timeout configurable via SYNC_MAX_WAIT_SECONDS environment variable
- Replace blocking sleep(1) with XCTest waitForExistence() for better async handling
- Reduce BrowserStack timeout from 20 to 15 minutes to fail faster on stuck tests
- Addresses Copilot AI code review suggestions for more robust CI testing

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@teodorciuraru Teodor Ciuraru (teodorciuraru) changed the title ci(swift): add pipelines with BrowserStack integration ci(swift): add pipeline with BrowserStack integration Sep 4, 2025

This comment was marked as outdated.

Comment thread swift/TasksUITests/TasksUITests.swift Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The signing info should not be hardcoded as pointed out by Co-Pilot.

- Remove hardcoded DEVELOPMENT_TEAM = 3T2VMFZPPQ from project.pbxproj
- Use empty string to allow local developer configuration
- Fix Swift variable naming: githubRunId -> githubRunID (proper acronym capitalization)
- Addresses code review feedback from konstantinbe and Copilot AI

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a comprehensive Swift CI pipeline with BrowserStack integration for real device testing. The solution implements parallel builds for efficiency and includes cloud-based document synchronization validation.

  • Parallel CI architecture: lint → [build-macos + build-ios] → browserstack → summary
  • BrowserStack real device testing with XCUITest bundles and cloud sync validation
  • Document seeding via Ditto API with inverted timestamps for reliable test detection

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
.github/workflows/swift-ci.yml Comprehensive CI workflow with parallel builds, BrowserStack integration, and cloud sync testing
swift/TasksUITests/TasksUITests.swift XCUITest implementation for validating GitHub-seeded documents on real devices
swift/Tasks/TasksListScreen.swift Added ORDER BY clause and navigation style for consistent UI testing
swift/Tasks.xcodeproj/xcshareddata/xcschemes/Tasks.xcscheme Xcode scheme configuration for UI testing target
swift/Tasks.xcodeproj/project.pbxproj Project file updates to include TasksUITests target
Comments suppressed due to low confidence (1)

.github/workflows/swift-ci.yml:1

  • The device specification should be configurable or documented. Hardcoding "iPhone 15 Pro-17" makes the pipeline brittle if this specific device becomes unavailable on BrowserStack. Consider using a more generic device specification or making this configurable via environment variables.
name: Swift

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread swift/TasksUITests/TasksUITests.swift
Comment thread swift/TasksUITests/TasksUITests.swift
Comment thread .github/workflows/swift-ci.yml
Comment thread .github/workflows/swift-ci.yml
Comment thread swift/Tasks/TasksListScreen.swift
@teodorciuraru
Teodor Ciuraru (teodorciuraru) merged commit 5ce7318 into main Sep 8, 2025
13 checks passed
@teodorciuraru
Teodor Ciuraru (teodorciuraru) deleted the teodor/add-swift-browserstack-pipeline branch September 8, 2025 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants