Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/actions/swift-packages/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Swift packages
description: >
Resolves the Swift packages into $SOURCE_PACKAGES and caches them. Pass
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES" -disableAutomaticPackageResolution
-skipPackageUpdates to every later xcodebuild call, or it resolves and clones everything again.

# SwiftPM keeps a full bare clone of every package and looks each one up on every resolve, so
# the clones have to be cached too. bitkit-core's history alone is over 13 GB, past the
# repository cache limit, so on a miss the clones are cut down to the pinned commits first.
runs:
using: composite
steps:
- name: Locate Swift packages
id: locate
shell: bash
run: |
echo "SOURCE_PACKAGES=$GITHUB_WORKSPACE/SourcePackages" >> "$GITHUB_ENV"
echo "xcode=$(xcodebuild -version | head -1 | cut -d' ' -f2)" >> "$GITHUB_OUTPUT"

- name: Restore Swift packages
id: cache
uses: actions/cache/restore@v6
with:
path: ${{ github.workspace }}/SourcePackages
key: ${{ runner.os }}-xcode-${{ steps.locate.outputs.xcode }}-source-packages-v2-${{ hashFiles('Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}

- name: Resolve Swift packages
shell: bash
run: |
echo "⏱️ Starting dependency resolution at $(date)"
set -o pipefail && xcodebuild -resolvePackageDependencies \
-scheme Bitkit \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES" \
-disablePackageRepositoryCache \
-onlyUsePackageVersionsFromResolvedFile \
-skipPackageUpdates \
| xcbeautify
echo "✅ Dependencies resolved at $(date)"

- name: Shrink package clones
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: |
"$GITHUB_WORKSPACE/scripts/shallow-source-packages.sh" "$SOURCE_PACKAGES"
du -sh "$SOURCE_PACKAGES"

# Saved right after resolving so a failing job still warms the cache.
- name: Save Swift packages
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v6
with:
path: ${{ github.workspace }}/SourcePackages
key: ${{ steps.cache.outputs.cache-primary-key }}
20 changes: 6 additions & 14 deletions .github/workflows/e2e-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,8 @@ jobs:
run: |
brew install xcbeautify

- name: Cache Swift Package Manager
uses: actions/cache@v6
with:
path: |
~/Library/Caches/org.swift.swiftpm
~/Library/org.swift.swiftpm
Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}

- name: Install dependencies
run: |
echo "⏱️ Starting dependency resolution at $(date)"
xcodebuild -resolvePackageDependencies -onlyUsePackageVersionsFromResolvedFile | xcbeautify
echo "✅ Dependencies resolved at $(date)"
- name: Swift packages
uses: ./.github/actions/swift-packages

- name: Pre-start simulator
run: |
Expand Down Expand Up @@ -96,6 +84,10 @@ jobs:
-configuration Debug \
-destination "platform=iOS Simulator,name=${{ env.SIMULATOR_NAME }},OS=${{ env.IOS_VERSION }}" \
-derivedDataPath DerivedData \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES" \
-disablePackageRepositoryCache \
-disableAutomaticPackageResolution \
-skipPackageUpdates \
SWIFT_ACTIVE_COMPILATION_CONDITIONS='DEBUG E2E_BUILD' \
-allowProvisioningUpdates \
build
Expand Down
20 changes: 6 additions & 14 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,8 @@ jobs:
run: |
brew install xcbeautify

- name: Cache Swift Package Manager
uses: actions/cache@v6
with:
path: |
~/Library/Caches/org.swift.swiftpm
~/Library/org.swift.swiftpm
Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}

- name: Install dependencies
run: |
echo "⏱️ Starting dependency resolution at $(date)"
xcodebuild -resolvePackageDependencies -onlyUsePackageVersionsFromResolvedFile | xcbeautify
echo "✅ Dependencies resolved at $(date)"
- name: Swift packages
uses: ./.github/actions/swift-packages

- name: Pre-start simulator
run: |
Expand Down Expand Up @@ -122,6 +110,10 @@ jobs:
-configuration Debug \
-destination "platform=iOS Simulator,name=$SIMULATOR_NAME,OS=$OS_VERSION" \
-derivedDataPath DerivedData \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES" \
-disablePackageRepositoryCache \
-disableAutomaticPackageResolution \
-skipPackageUpdates \
SWIFT_ACTIVE_COMPILATION_CONDITIONS='DEBUG E2E_BUILD' \
TREZOR_BRIDGE=true \
TREZOR_BRIDGE_URL=http://127.0.0.1:21325 \
Expand Down
20 changes: 6 additions & 14 deletions .github/workflows/e2e_migration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,8 @@ jobs:
run: |
brew install xcbeautify

- name: Cache Swift Package Manager
uses: actions/cache@v6
with:
path: |
~/Library/Caches/org.swift.swiftpm
~/Library/org.swift.swiftpm
Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}

- name: Install dependencies
run: |
echo "⏱️ Starting dependency resolution at $(date)"
xcodebuild -resolvePackageDependencies -onlyUsePackageVersionsFromResolvedFile | xcbeautify
echo "✅ Dependencies resolved at $(date)"
- name: Swift packages
uses: ./.github/actions/swift-packages

- name: Pre-start simulator
run: |
Expand Down Expand Up @@ -108,6 +96,10 @@ jobs:
-configuration Debug \
-destination "platform=iOS Simulator,name=${{ env.SIMULATOR_NAME }},OS=${{ env.IOS_VERSION }}" \
-derivedDataPath DerivedData \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES" \
-disablePackageRepositoryCache \
-disableAutomaticPackageResolution \
-skipPackageUpdates \
SWIFT_ACTIVE_COMPILATION_CONDITIONS='$(inherited) E2E_BUILD' \
-allowProvisioningUpdates \
build
Expand Down
129 changes: 68 additions & 61 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ jobs:
name: Run Integration Tests
runs-on: macos-15
timeout-minutes: 60
env:
DERIVED_DATA: ${{ github.workspace }}/DerivedData
RESULT_BUNDLE: ${{ github.workspace }}/IntegrationTests.xcresult

steps:
- name: Checkout repository
Expand All @@ -32,81 +35,85 @@ jobs:
with:
xcode-version: '16.4'

# A fresh simulator takes over 10 minutes to boot on the runner. Booting it now lets that
# overlap with resolving and building instead of stalling the test step.
- name: Boot simulator
run: |
udid=$(xcrun simctl list devices available -j | python3 -c '
import json, sys
runtimes = json.load(sys.stdin)["devices"]
version = lambda runtime: [int(part) for part in runtime.rsplit(".", 1)[-1].split("-")[1:]]
ios = sorted((r for r in runtimes if ".iOS-" in r and any(d["name"] == "iPhone 16" for d in runtimes[r])), key=version)
print(next(d["udid"] for d in runtimes[ios[-1]] if d["name"] == "iPhone 16"))
')
echo "SIMULATOR_UDID=$udid" >> "$GITHUB_ENV"
echo "DESTINATION=platform=iOS Simulator,id=$udid" >> "$GITHUB_ENV"
xcrun simctl boot "$udid"

- name: Install xcbeautify
run: |
brew install xcbeautify

- name: Cache Swift Package Manager
uses: actions/cache@v6
with:
path: |
~/Library/Caches/org.swift.swiftpm
~/Library/org.swift.swiftpm
Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}

- name: Install dependencies
run: |
echo "⏱️ Starting dependency resolution at $(date)"
xcodebuild -resolvePackageDependencies -onlyUsePackageVersionsFromResolvedFile | xcbeautify
echo "✅ Dependencies resolved at $(date)"
- name: Swift packages
uses: ./.github/actions/swift-packages

- name: Clean build
- name: Build for testing
run: |
echo "⏱️ Cleaning build at $(date)"
xcodebuild clean -scheme Bitkit | xcbeautify
echo "✅ Build cleaned at $(date)"
echo "⏱️ Starting build at $(date)"
set -o pipefail && xcodebuild build-for-testing \
-scheme Bitkit \
-destination "$DESTINATION" \
-derivedDataPath "$DERIVED_DATA" \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES" \
-disablePackageRepositoryCache \
-disableAutomaticPackageResolution \
-skipPackageUpdates \
-enableCodeCoverage NO \
| xcbeautify
echo "✅ Build finished at $(date)"

- name: Run integration tests
timeout-minutes: 25
run: |
xcrun simctl bootstatus "$SIMULATOR_UDID" -b
echo "⏱️ Starting integration tests at $(date)"

run_tests() {
# RNMigrationCleanupTests deletes the real ~/Documents/mmkv and ~/Documents/ldk, so it
# skips itself unless this is set. This lane runs on a simulator it erases between
# attempts; the unit lane does not, and must not run it.
#
# The TEST_RUNNER_ prefix is required: xcodebuild does not pass the invoking shell's
# environment to the simulator-hosted runner, only variables named TEST_RUNNER_<VAR>,
# which it forwards with the prefix stripped. Without it the guard never sees the
# variable, every test in the suite skips, and the lane still reports green.
set -o pipefail && TEST_RUNNER_BITKIT_DESTRUCTIVE_TESTS=1 xcodebuild test \
-scheme Bitkit \
-destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' \
-enableCodeCoverage NO \
-parallel-testing-enabled NO \
-only-testing:BitkitTests/UtxoSelectionTests \
-only-testing:BitkitTests/BlocktankTests \
-only-testing:BitkitTests/PaymentFlowTests \
-only-testing:BitkitTests/BlocktankRefundAddressLiveIntegrationTests \
-only-testing:BitkitTests/AddressTypeIntegrationTests \
-only-testing:BitkitTests/RNMigrationCleanupTests \
| xcbeautify --report junit
}

# Try up to 3 times with simulator reset between failures
for attempt in 1 2 3; do
echo "🔄 Test attempt $attempt of 3"
if run_tests; then
echo "✅ Integration tests completed at $(date)"
exit 0
fi

if [ $attempt -lt 3 ]; then
echo "⚠️ Test attempt $attempt failed, resetting simulator..."
xcrun simctl shutdown all || true
xcrun simctl erase "iPhone 16" || true
xcrun simctl boot "iPhone 16"
sleep 5
fi
done

echo "❌ All test attempts failed"
exit 1
# RNMigrationCleanupTests deletes the real ~/Documents/mmkv and ~/Documents/ldk, so it
# skips itself unless this is set. This lane runs on a throwaway CI simulator; the unit
# lane does not, and must not run it.
#
# The TEST_RUNNER_ prefix is required: xcodebuild does not pass the invoking shell's
# environment to the simulator-hosted runner, only variables named TEST_RUNNER_<VAR>,
# which it forwards with the prefix stripped. Without it the guard never sees the
# variable, every test in the suite skips, and the lane still reports green.
#
# The live regtest suites are flaky on CI runners, so a failed test is retried once on
# its own instead of rebuilding and rerunning the whole suite.
set -o pipefail && TEST_RUNNER_BITKIT_DESTRUCTIVE_TESTS=1 xcodebuild test-without-building \
-scheme Bitkit \
-destination "$DESTINATION" \
-derivedDataPath "$DERIVED_DATA" \
-resultBundlePath "$RESULT_BUNDLE" \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES" \
-disablePackageRepositoryCache \
-disableAutomaticPackageResolution \
-skipPackageUpdates \
-enableCodeCoverage NO \
-parallel-testing-enabled NO \
-retry-tests-on-failure \
-test-iterations 2 \
-only-testing:BitkitTests/UtxoSelectionTests \
-only-testing:BitkitTests/BlocktankTests \
-only-testing:BitkitTests/PaymentFlowTests \
-only-testing:BitkitTests/BlocktankRefundAddressLiveIntegrationTests \
-only-testing:BitkitTests/AddressTypeIntegrationTests \
-only-testing:BitkitTests/RNMigrationCleanupTests \
| xcbeautify --report junit
echo "✅ Integration tests completed at $(date)"

- name: Upload test results
uses: actions/upload-artifact@v7
if: success() || failure()
with:
name: integration-test-results
path: ~/Library/Developer/Xcode/DerivedData/**/Logs/Test/*.xcresult
path: ${{ env.RESULT_BUNDLE }}
26 changes: 6 additions & 20 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,39 +35,25 @@ jobs:
run: |
brew install xcbeautify

- name: Cache Swift Package Manager
uses: actions/cache@v6
with:
path: |
~/Library/Caches/org.swift.swiftpm
~/Library/org.swift.swiftpm
Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}

- name: Install dependencies
run: |
echo "⏱️ Starting dependency resolution at $(date)"
xcodebuild -resolvePackageDependencies -onlyUsePackageVersionsFromResolvedFile | xcbeautify
echo "✅ Dependencies resolved at $(date)"
- name: Swift packages
uses: ./.github/actions/swift-packages

- name: Pre-start simulator
run: |
echo "⏱️ Starting simulator at $(date)"
xcrun simctl boot "iPhone 16" || true
echo "✅ Simulator started at $(date)"

- name: Clean build
run: |
echo "⏱️ Cleaning build at $(date)"
xcodebuild clean -scheme Bitkit | xcbeautify
echo "✅ Build cleaned at $(date)"

- name: Run unit tests
run: |
echo "⏱️ Starting unit tests at $(date)"
set -o pipefail && xcodebuild test \
-scheme Bitkit \
-destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES" \
-disablePackageRepositoryCache \
-disableAutomaticPackageResolution \
-skipPackageUpdates \
-enableCodeCoverage NO \
-parallel-testing-enabled NO \
-skip-testing:BitkitTests/UtxoSelectionTests \
Expand Down
Loading
Loading