Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5eb1d13
Attempt to re-use existing Android emulator configuration
marcprux Dec 7, 2025
3dc7ff0
Setup Android environment before running sdkmanager
marcprux Dec 7, 2025
d7475f3
Update emualtor creation
marcprux Dec 7, 2025
34834be
Update emulator
marcprux Dec 7, 2025
0a127d3
Update emulator testing
marcprux Dec 7, 2025
d18035a
Update emulator testing
marcprux Dec 7, 2025
e510d6f
Update emulator testing
marcprux Dec 7, 2025
0ef5373
Update emulator testing
marcprux Dec 7, 2025
1d1e530
Update emulator testing
marcprux Dec 7, 2025
bf96182
Update emulator testing
marcprux Dec 7, 2025
128175a
Update emulator testing
marcprux Dec 7, 2025
29a890d
Update emulator testing
marcprux Dec 7, 2025
1e0dc91
Update emulator testing
marcprux Dec 7, 2025
3b018d2
Update emulator testing
marcprux Dec 7, 2025
d26f4a8
Update emulator testing
marcprux Dec 7, 2025
42f64a7
Update emulator testing
marcprux Dec 7, 2025
9635785
Update emulator testing
marcprux Dec 7, 2025
6bd429e
Update emulator testing
marcprux Dec 7, 2025
8ef4663
Update emulator testing
marcprux Dec 7, 2025
6c3b391
Update emulator testing
marcprux Dec 7, 2025
cb5179e
Update emulator testing
marcprux Dec 7, 2025
95a19e7
Update emulator testing
marcprux Dec 7, 2025
45bdff6
Update emulator testing
marcprux Dec 7, 2025
f4d38c1
Update emulator testing
marcprux Dec 7, 2025
d4d4c45
Update emulator testing
marcprux Dec 7, 2025
e509d05
Update emulator testing
marcprux Dec 7, 2025
c68dea2
Update emulator testing
marcprux Dec 7, 2025
80d788a
Update emulator testing
marcprux Dec 7, 2025
adf54ab
Update action script
marcprux Dec 7, 2025
64847ca
Add more package tests
marcprux Dec 7, 2025
984de91
Update testing packages
marcprux Dec 7, 2025
9a99d4a
Update testing packages
marcprux Dec 7, 2025
23a5cd8
Update testing packages
marcprux Dec 7, 2025
7bf8957
Update testing packages
marcprux Dec 7, 2025
0260e3a
Update testing packages
marcprux Dec 7, 2025
b7c863c
Update testing packages
marcprux Dec 7, 2025
c43bf24
Update testing packages
marcprux Dec 8, 2025
d13bf4d
Update testing packages
marcprux Dec 8, 2025
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
204 changes: 84 additions & 120 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
workflow_dispatch:
pull_request:
schedule:
- cron: '0 1,7,13,20 * * *'
- cron: '0 13 * * *'

jobs:
install-sdk:
Expand All @@ -27,6 +27,13 @@ jobs:
EMULATOR_ARCH: 'x86_64'
EMULATOR_ARCH_TRIPLE: 'x86_64'

- name: 'macOS 15 X64 API 30'
os: 'macos-15-intel'
ANDROID_API: 30
NDK_VERSION: 'r27d'
EMULATOR_ARCH: 'x86_64'
EMULATOR_ARCH_TRIPLE: 'x86_64'

- name: 'Ubuntu X64 API 35'
os: 'ubuntu-latest'
ANDROID_API: 35
Expand All @@ -50,19 +57,9 @@ jobs:
# EMULATOR_ARCH_TRIPLE: 'aarch64'

runs-on: ${{ matrix.os }}
env:
ANDROID_API: ${{ matrix.ANDROID_API }}
ANDROID_EMULATOR_ARCH: ${{ matrix.EMULATOR_ARCH }}
ANDROID_EMULATOR_ARCH_TRIPLE: ${{ matrix.EMULATOR_ARCH_TRIPLE }}
ANDROID_TARGET: 'default'
#ANDROID_BUILD_TOOLS_VERSION: 36.0.0
ANDROID_BUILD_TOOLS_VERSION: 'latest'
BUILD_TOOLS_VERSION: "35.0.0"
ANDROID_EMULATOR_NAME: 'demo'
ANDROID_PROFILE: "Nexus 10"
ANDROID_CHANNEL: "3"
ANDROID_NDK_VERSION: "${{ matrix.NDK_VERSION }}"
steps:
- uses: actions/checkout@v4

- name: Free Disk Space
if: runner.os == 'Linux'
run: |
Expand All @@ -71,6 +68,48 @@ jobs:
sudo rm -rf "/usr/local/share/boost"
sudo rm -rf "$AGENT_TOOLSDIRECTORY"

- name: Setup Android Environment
run: |
echo "$ANDROID_HOME/cmdline-tools/latest/bin" >> $GITHUB_PATH
echo "$ANDROID_HOME/platform-tools" >> $GITHUB_PATH
echo "$ANDROID_HOME/build-tools/latest" >> $GITHUB_PATH
echo "$ANDROID_HOME/tools" >> $GITHUB_PATH
echo "$ANDROID_HOME/emulator" >> $GITHUB_PATH

echo "ANDROID_API=${{ matrix.ANDROID_API }}" >> $GITHUB_ENV
echo "ANDROID_EMULATOR_ARCH=${{ matrix.EMULATOR_ARCH }}" >> $GITHUB_ENV
echo "ANDROID_EMULATOR_ARCH_TRIPLE=${{ matrix.EMULATOR_ARCH_TRIPLE }}" >> $GITHUB_ENV
echo "ANDROID_TARGET=default" >> $GITHUB_ENV
#echo "ANDROID_PROFILE=Pixel 6" >> $GITHUB_ENV
echo "ANDROID_PROFILE=Nexus 10" >> $GITHUB_ENV
echo "ANDROID_CHANNEL=3" >> $GITHUB_ENV
echo "ANDROID_NDK_VERSION=${{ matrix.NDK_VERSION }}" >> $GITHUB_ENV

if [[ "${RUNNER_OS}" == "Linux" ]]; then
# needed for Linux or else the emulator will be created in
# ~/.android/avd but it will be sought in ~/.config/.android/avd
echo "ANDROID_AVD_HOME=${XDG_CONFIG_HOME:-$HOME}/.android/avd" >> $GITHUB_ENV

# enable KVM on Linux, else error on emulator launch:
# CPU acceleration status: This user doesn't have permissions to use KVM (/dev/kvm).
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
fi

- name: Create and Launch Android Emulator
run: |
EMULATOR_SPEC="system-images;android-${ANDROID_API};default;${ANDROID_EMULATOR_ARCH}"
EMULATOR_NAME="swiftemu"
sdkmanager --list_installed
yes | sdkmanager --licenses > /dev/null
sdkmanager --install "${EMULATOR_SPEC}" "emulator" "platform-tools" "platforms;android-${ANDROID_API}"
avdmanager create avd -n "${EMULATOR_NAME}" -k "${EMULATOR_SPEC}" --device "${ANDROID_PROFILE}"
emulator -list-avds
# launch the emulator in the background; we will cat the logs at the end
nohup emulator -memory 4096 -avd "${EMULATOR_NAME}" -wipe-data -no-window -no-snapshot -noaudio -no-boot-anim 2>&1 > emulator.log &
adb logcat 2>&1 > logcat.log &

- name: Install Prerequisites
run: |
if [[ "${RUNNER_OS}" == "Linux" ]]; then
Expand Down Expand Up @@ -138,19 +177,12 @@ jobs:
# https://github.com/swiftlang/swift-driver/pull/1879
echo "ANDROID_NDK_ROOT=" >> $GITHUB_ENV

- name: Setup Android Environment
run: |
echo "$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/emulator:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/${{ env.ANDROID_BUILD_TOOLS_VERSION }}" >> $GITHUB_PATH
# needed for Linux or else the emulator will be created in
# ~/.android/avd but it will be sought in ~/.config/.android/avd
if [[ "${RUNNER_OS}" == "Linux" ]]; then
echo "ANDROID_AVD_HOME=${XDG_CONFIG_HOME:-$HOME}/.android/avd" >> $GITHUB_ENV
fi

- name: Setup Swift SDK for Android
run: |
cd ~/Library/org.swift.swiftpm || cd ${XDG_CONFIG_HOME}/swiftpm || cd ~/.local/swiftpm || cd ~/.swiftpm
./swift-sdks/${SWIFT_ANDROID_SDK_VERSION}*.artifactbundle/swift-android/scripts/setup-android-sdk.sh
cd ./swift-sdks/${SWIFT_ANDROID_SDK_VERSION}*.artifactbundle
echo "SWIFT_ANDROID_SDK_HOME=${PWD}" >> $GITHUB_ENV

- name: Build Swift Executable for Android
run: |
Expand All @@ -160,55 +192,12 @@ jobs:
swiftly run swift build --swift-sdk "${ANDROID_EMULATOR_ARCH_TRIPLE}-unknown-linux-android${ANDROID_API}" --static-swift-stdlib
file .build/debug/hello

- name: Enable KVM
if: runner.os == 'Linux'
run: |
if [[ "${RUNNER_ARCH}" == "X64" ]]; then
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
fi

- name: Android SDKs - list installed SDKs
run: sdkmanager --list_installed

- name: Android SDKs - setup environment
run: yes y | sdkmanager --licenses > /dev/null

- name: Android SKDs - setup build tools
run: sdkmanager --install "build-tools;${BUILD_TOOLS_VERSION}" platform-tools "platforms;android-${ANDROID_API}" --channel="${ANDROID_CHANNEL}"

- name: Android SKDs - setup emulator
run: sdkmanager --install emulator --channel="${ANDROID_CHANNEL}"

- name: Android Emulator - download required images
run: sdkmanager --install "system-images;android-${ANDROID_API};${ANDROID_TARGET};${ANDROID_EMULATOR_ARCH}" --channel="${ANDROID_CHANNEL}"

- name: Android Emulator - Create
run: avdmanager --verbose create avd --force -n "${ANDROID_EMULATOR_NAME}" --device "${ANDROID_PROFILE}" --abi "${ANDROID_TARGET}/${ANDROID_EMULATOR_ARCH}" --package "system-images;android-${ANDROID_API};${ANDROID_TARGET};${ANDROID_EMULATOR_ARCH}" --sdcard 512M

#- name: Android - Find AVDs
# run: find ~/ -type d -name '*.avd'

#- name: Android - List AVDs
# run: emulator -list-avds

- name: Android - Boot
run: nohup emulator -memory 4096 -avd "${ANDROID_EMULATOR_NAME}" -wipe-data -no-window -no-snapshot -noaudio -no-boot-anim 2>&1 > emulator.log &

- name: ADB Wait For Device
- name: Wait for Android Emulator
run: adb wait-for-any-device
timeout-minutes: 5

- name: Pause briefly
run: sleep 30

#- name: ADB Press Power Button
# run: adb shell input keyevent 82

- name: Check Android Emulator
run: |
adb shell 'echo Hello Android!'
run: adb shell 'echo Hello Android!'

- name: Run Swift Executable on Android Emulator
run: |
Expand All @@ -217,72 +206,47 @@ jobs:
adb push $ANDROID_NDK_HOME/toolchains/llvm/prebuilt/*/sysroot/usr/lib/${ANDROID_EMULATOR_ARCH_TRIPLE}-linux-android/libc++_shared.so /data/local/tmp/
adb shell /data/local/tmp/hello

- name: Create run-tests script
run: |
cat > run-tests.sh << "EOF"
#!/bin/bash -ex
ORG=$(echo "${1}" | cut -d '/' -f 1)
PACKAGE=$(echo "${1}" | cut -d '/' -f 2)

git clone https://github.com/${ORG}/${PACKAGE}
cd ${PACKAGE}

swiftly run swift build --swift-sdk "${ANDROID_EMULATOR_ARCH_TRIPLE}-unknown-linux-android${ANDROID_API}" --build-tests +"${SWIFT_TOOLCHAIN_VERSION}"

adb push .build/debug/${PACKAGE}PackageTests.xctest /data/local/tmp/
# copy up any test resources
adb push .build/debug/*.resources /data/local/tmp/ || true
- run: ./android-ci.sh test apple/swift-numerics

# push potential dependent libraries
adb push $ANDROID_NDK_HOME/toolchains/llvm/prebuilt/*/sysroot/usr/lib/${ANDROID_EMULATOR_ARCH_TRIPLE}-linux-android/libc++_shared.so /data/local/tmp/
- run: ./android-ci.sh test apple/swift-algorithms

# Since we are building with --static-swift-stdlib, we don't
# need to copy any of the other libraries
cd ~/Library/org.swift.swiftpm || cd ${XDG_CONFIG_HOME}/swiftpm || cd ~/.local/swiftpm || cd ~/.swiftpm
adb push swift-sdks/${SWIFT_ANDROID_SDK_VERSION}*.artifactbundle/swift-android/swift-resources/usr/lib/swift-${ANDROID_EMULATOR_ARCH_TRIPLE}/android/*.so /data/local/tmp/
cd -
- run: ./android-ci.sh test apple/swift-atomics

adb shell ls /data/local/tmp/
- run: ./android-ci.sh build swiftlang/swift-subprocess

adb shell /data/local/tmp/${PACKAGE}PackageTests.xctest
EOF
# build-only because it uses hardwired StringLiteralRepresentedLiteralValueTests.swift
- run: ./android-ci.sh build swiftlang/swift-syntax

chmod +x run-tests.sh
cat run-tests.sh
# build-only because tests crash in NetrcTests.testNoErrorMixedAccount
# and tests use abslute file paths
- run: ./android-ci.sh build swiftlang/swift-tools-support-core

- name: Run swift-collections tests
# too slow
if: false
run: ./run-tests.sh apple/swift-collections
# build-only because it tries to write to "/tmp/old.txt" and "/tmp/" does not exist
- run: ./android-ci.sh build swiftlang/swift-markdown

- name: Run swift-numerics tests
run: ./run-tests.sh apple/swift-numerics
# no tests in swift-toolchain-sqlite
- run: ./android-ci.sh build swiftlang/swift-toolchain-sqlite

- name: Run swift-algorithms tests
run: ./run-tests.sh apple/swift-algorithms
# build-only: tests work, but they take a very long time
- run: ./android-ci.sh build apple/swift-collections

- name: Run swift-atomics tests
run: ./run-tests.sh apple/swift-atomics
# build-only: https://github.com/apple/swift-system/pull/272
- run: ./android-ci.sh build apple/swift-system

- name: Run swift-system tests
run: ./run-tests.sh apple/swift-system
# build-only: tests references Tests/ file paths by absolute filename
- run: ./android-ci.sh build apple/swift-crypto

- name: Run swift-crypto tests
# needs: Tests/CryptoExtrasVectors/rfc-7914-scrypt.txt
if: false
run: ./run-tests.sh apple/swift-crypto
- run: ./android-ci.sh build apple/swift-nio

- name: Run swift-nio tests
if: false
run: ./run-tests.sh apple/swift-nio
# build-only, since tests needs local files:
# error: MathExampleTests.testMath_AddHelp : failed - No executable at '/data/local/tmp/math'.
#- run: ./android-ci.sh build apple/swift-argument-parser

- name: Run swift-argument-parser tests
# needs local files:
# error: MathExampleTests.testMath_AddHelp : failed - No executable at '/data/local/tmp/math'.
if: false
run: ./run-tests.sh apple/swift-argument-parser
- name: Show Android Emulator Log
if: always()
run: cat emulator.log

- name: Android - Show Emulator Log
- name: Show Android Logcat Output
if: always()
run: cat emulator.log || true
run: cat logcat.log

59 changes: 59 additions & 0 deletions android-ci.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash -ex

if [[ -z "${2}" ]]; then
echo "$0: Usage: $0 build/test org/package"
exit 1
fi

ACT=${1}
ORG=$(echo "${2}" | cut -d '/' -f 1)
PACKAGE=$(echo "${2}" | cut -d '/' -f 2)

git clone https://github.com/${ORG}/${PACKAGE}
cd ${PACKAGE}

TRIPLE="${ANDROID_EMULATOR_ARCH_TRIPLE}-unknown-linux-android${ANDROID_API}"
swiftly run swift build --swift-sdk "${TRIPLE}" --build-tests +"${SWIFT_TOOLCHAIN_VERSION}"

if [[ "${ACT}" == "build" ]]; then
# build-only, not test, so we are done
exit 0
fi

if [[ "${ACT}" != "test" ]]; then
# build-only, not test
echo "$0: Usage: $0 build/test org/package"
exit 1
fi

STAGING="android-test-${PACKAGE}"
rm -rf .build/"${STAGING}"
mkdir .build/"${STAGING}"

# for the common case of tests referencing their own files as hardwired resource paths
if [[ -d Tests ]]; then
cp -a Tests .build/"${STAGING}"
fi

cd .build/
cp -a debug/*.xctest "${STAGING}"
cp -a debug/*.resources "${STAGING}" || true
cp -a ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/*/sysroot/usr/lib/${ANDROID_EMULATOR_ARCH_TRIPLE}-linux-android/libc++_shared.so "${STAGING}"
cp -a ${SWIFT_ANDROID_SDK_HOME}/swift-android/swift-resources/usr/lib/swift-${ANDROID_EMULATOR_ARCH_TRIPLE}/android/*.so "${STAGING}"

adb push ${STAGING} /data/local/tmp/

cd -

TEST_CMD="./${PACKAGE}PackageTests.xctest"
TEST_SHELL="cd /data/local/tmp/${STAGING}"
TEST_SHELL="${TEST_SHELL} && ${TEST_CMD}"

# Run a second time with the Swift Testing library
# We additionally need to handle the special exit code EXIT_NO_TESTS_FOUND (69 on Android),
# which can happen when the tests link to Testing, but no tests are executed
# see: https://github.com/swiftlang/swift-package-manager/blob/1b593469e8ad3daf2cc10e798340bd2de68c402d/Sources/Commands/SwiftTestCommand.swift#L1542
TEST_SHELL="${TEST_SHELL} && ${TEST_CMD} --testing-library swift-testing && [ \$? -eq 0 ] || [ \$? -eq 69 ]"

adb shell "${TEST_SHELL}"