-
Notifications
You must be signed in to change notification settings - Fork 34
Add CI for example projects #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b9b0d7f
41f902a
040c718
0c20f0b
37bf3da
6466620
49da231
0fbc79f
e10dd0d
270fef1
63f4b89
7db51f6
eb07553
5b2f022
571da46
cfecb38
f8ab14d
9b4ba79
6a59d5f
e0258fa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,236 @@ | ||
| name: ci | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
| workflow_dispatch: | ||
| inputs: | ||
| swift_versions: | ||
| description: 'JSON array of Swift versions to test (e.g. ["6.3"], ["6.3", "nightly-main"])' | ||
| required: false | ||
| default: '["6.3"]' | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: ci-${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | ||
|
|
||
| jobs: | ||
| build-examples: | ||
| name: Build ${{ matrix.os }} ${{ matrix.swift_version }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| swift_version: ${{ fromJSON(inputs.swift_versions || '["6.3"]') }} | ||
| sdk_triple: ['aarch64-unknown-linux-android28'] | ||
| ndk_version: ['r27d'] | ||
| os: ['ubuntu-latest', 'macos-latest'] | ||
| runs-on: ${{ matrix.os }} | ||
| env: | ||
| SDK_TRIPLE: ${{ matrix.sdk_triple }} | ||
| NDK_VERSION: ${{ matrix.ndk_version }} | ||
| SWIFT_VERSION: ${{ matrix.swift_version }} | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Set up JDK 25 | ||
| uses: actions/setup-java@v5 | ||
| with: | ||
| distribution: temurin | ||
| java-version: '25' | ||
|
|
||
| - name: Install swiftly | ||
| run: | | ||
| set -euxo pipefail | ||
| if [[ "${RUNNER_OS}" == "Linux" ]]; then | ||
| sudo apt-get -yq install curl jq gpg unzip libcurl4-openssl-dev | ||
| ARCH="$(uname -m)" | ||
| curl -L -O --retry 3 "https://download.swift.org/swiftly/linux/swiftly-${ARCH}.tar.gz" | ||
| tar -xzf "swiftly-${ARCH}.tar.gz" | ||
| ./swiftly init \ | ||
| --assume-yes \ | ||
| --skip-install \ | ||
| --no-modify-profile \ | ||
| --quiet-shell-followup | ||
| rm -f "swiftly-${ARCH}.tar.gz" swiftly | ||
| # The example projects' Gradle scripts look for swiftly under | ||
| # $HOME/.local/share/swiftly/bin, which is also where the official | ||
| # installer puts it. Add it to PATH for subsequent steps. | ||
| echo "$HOME/.local/share/swiftly/bin" >> "$GITHUB_PATH" | ||
| "$HOME/.local/share/swiftly/bin/swiftly" --version | ||
| elif [[ "${RUNNER_OS}" == "macOS" ]]; then | ||
| curl -O https://download.swift.org/swiftly/darwin/swiftly.pkg | ||
| installer -pkg swiftly.pkg -target CurrentUserHomeDirectory | ||
| ~/.swiftly/bin/swiftly init --quiet-shell-followup | ||
| . "${SWIFTLY_HOME_DIR:-$HOME/.swiftly}/env.sh" | ||
| hash -r | ||
| echo "$HOME/.swiftly/bin" >> "$GITHUB_PATH" | ||
| "$HOME/.swiftly/bin/swiftly" --version | ||
| else | ||
| echo "Unknown OS: ${RUNNER_OS}" | ||
| exit 1 | ||
| fi | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: quoting on |
||
| - name: Install Android NDK | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no caching = every run re-downloads the NDK (~1GB) and the android swift SDK. that's a lot of bytes off download.swift.org and a couple of minutes off every CI run across both OSes. |
||
| run: | | ||
| set -euxo pipefail | ||
| OS="$(uname -s | tr '[A-Z]' '[a-z]')" | ||
| curl -L -o ndk.zip --retry 3 "https://dl.google.com/android/repository/android-ndk-${NDK_VERSION}-${OS}.zip" | ||
| unzip -q ndk.zip -d "$HOME" | ||
| rm ndk.zip | ||
| echo "ANDROID_NDK_HOME=$HOME/android-ndk-${NDK_VERSION}" >> "$GITHUB_ENV" | ||
|
|
||
| - name: Install Android Swift SDK and matching host toolchain | ||
| # Looks up the Android Swift SDK URL and checksum from the swift.org | ||
| # install API and installs it via `swift sdk install`. | ||
| run: | | ||
| set -euxo pipefail | ||
| case "$SWIFT_VERSION" in | ||
| nightly-*) | ||
| nightly_version="${SWIFT_VERSION#nightly-}" | ||
| sdk_json=$(curl -fsSL "https://www.swift.org/api/v1/install/dev/${nightly_version}/android-sdk.json") | ||
| snapshot_tag=$(echo "$sdk_json" | jq -r '.[0].dir') | ||
| sdk_checksum=$(echo "$sdk_json" | jq -r '.[0].checksum') | ||
| if [ "$nightly_version" = "main" ]; then | ||
| branch="development" | ||
| else | ||
| branch="swift-${nightly_version}-branch" | ||
| fi | ||
| sdk_url="https://download.swift.org/${branch}/android-sdk/${snapshot_tag}/${snapshot_tag}_android.artifactbundle.tar.gz" | ||
| ;; | ||
| *) | ||
| releases_json=$(curl -fsSL "https://www.swift.org/api/v1/install/releases.json") | ||
| # Pick the highest patch release whose name starts with the | ||
| # requested version (e.g. "6.3" -> "6.3.1" if it exists). | ||
| latest_version=$(echo "$releases_json" | jq -r --arg v "$SWIFT_VERSION" \ | ||
| '[.[] | select(.name | startswith($v))] | ||
| | sort_by(.name | split(".") | map(tonumber? // 0)) | ||
| | last | ||
| | .name') | ||
| if [ -z "$latest_version" ] || [ "$latest_version" = "null" ]; then | ||
| echo "Error: no Swift release matching '$SWIFT_VERSION' found in releases.json" >&2 | ||
| exit 1 | ||
| fi | ||
| sdk_checksum=$(echo "$releases_json" | jq -r --arg v "$latest_version" \ | ||
| '.[] | select(.name == $v) | .platforms[] | select(.platform == "android-sdk") | .checksum') | ||
| snapshot_tag="swift-${latest_version}-RELEASE" | ||
| sdk_url="https://download.swift.org/swift-${latest_version}-release/android-sdk/${snapshot_tag}/${snapshot_tag}_android.artifactbundle.tar.gz" | ||
| ;; | ||
| esac | ||
|
|
||
| swift_install=${snapshot_tag} | ||
| # trim leading "swift-" and trailing "-RELEASE" | ||
| swift_install=${swift_install#swift-} | ||
| swift_install=${swift_install/-RELEASE/} | ||
|
|
||
| echo "Installing Android Swift SDK and host toolchain" | ||
| echo " tag: $swift_install" | ||
| echo " url: $sdk_url" | ||
| echo " checksum: $sdk_checksum" | ||
| swiftly install "${swift_install}" | ||
| swift sdk install "$sdk_url" --checksum "$sdk_checksum" | ||
| swift sdk list | ||
|
|
||
| # Override the matrix-supplied SWIFT_VERSION (e.g. "6.3") with the | ||
| # resolved patch version (e.g. "6.3.1") so the gradle scripts pick up | ||
| # the actual artifactbundle directory name produced by `swift sdk | ||
| # install`. SWIFT_ANDROID_SDK_VERSION pins the bundle suffix for the | ||
| # same reason. | ||
| echo "SWIFT_VERSION=${swift_install}" >> "$GITHUB_ENV" | ||
| echo "SWIFT_ANDROID_SDK_VERSION=${snapshot_tag#swift-}_android" >> "$GITHUB_ENV" | ||
|
|
||
| - name: Configure Swift Android SDK | ||
| run: | | ||
| set -euo pipefail | ||
| # Locate the installed Android SDK artifactbundle. Its parent | ||
| # directory varies by OS / swiftpm version, so try the known | ||
| # candidates and pick the first one that actually matches. | ||
| shopt -s nullglob | ||
| candidates=( | ||
| "$HOME"/.swiftpm/swift-sdks/*android*.artifactbundle | ||
| "$HOME"/.config/swiftpm/swift-sdks/*android*.artifactbundle | ||
| "$HOME"/Library/org.swift.swiftpm/swift-sdks/*android*.artifactbundle | ||
| ) | ||
| if [[ ${#candidates[@]} -eq 0 ]]; then | ||
| echo "No android SDK artifactbundle found in any known location" >&2 | ||
| exit 1 | ||
| fi | ||
| cd "${candidates[0]}" | ||
| # Link the SDK against the NDK we installed in the previous step. | ||
| # Someday we might not need this script, so gracefully skip it | ||
| # if it does not exist. | ||
| if [[ -x "./swift-android/scripts/setup-android-sdk.sh" ]]; then | ||
| "./swift-android/scripts/setup-android-sdk.sh" | ||
| fi | ||
|
|
||
| - name: Publish swift-java packages to local Maven | ||
| # The hashing-lib, weather-lib, and hello-cpp-swift/swift-lib modules | ||
| # depend on org.swift.swiftkit:swiftkit-core:1.0-SNAPSHOT, which is not | ||
| # published to a public Maven repo. The hashing-lib README documents | ||
| # publishing it to mavenLocal from the swift-java checkout that | ||
| # SwiftPM resolves into .build/checkouts/swift-java. | ||
| working-directory: hello-swift-java/hashing-lib | ||
| run: | | ||
| set -euxo pipefail | ||
| swift package resolve | ||
| ./.build/checkouts/swift-java/gradlew \ | ||
| --project-dir .build/checkouts/swift-java \ | ||
| :SwiftKitCore:publishToMavenLocal | ||
|
|
||
| - name: Build hello-swift-raw-jni APK | ||
| run: ./gradlew :hello-swift-raw-jni:assembleDebug --stacktrace | ||
|
|
||
| - name: Build hello-swift-raw-jni-callback APK | ||
| run: ./gradlew :hello-swift-raw-jni-callback:assembleDebug --stacktrace | ||
|
|
||
| - name: Build hello-swift-raw-jni-library | ||
| run: ./gradlew :hello-swift-raw-jni-library:assembleDebug --stacktrace | ||
|
|
||
| - name: Build native-activity APK | ||
| run: ./gradlew :native-activity:assembleDebug --stacktrace | ||
|
|
||
| - name: Build hello-swift-java APK | ||
| run: ./gradlew :hello-swift-java-hashing-app:assembleDebug --stacktrace | ||
|
|
||
| - name: Build swift-java-weather-app APK | ||
| run: ./gradlew :swift-java-weather-app-weather-app:assembleDebug --stacktrace | ||
|
|
||
| - name: Build hello-cpp-swift cpp-lib | ||
| working-directory: hello-cpp-swift/cpp-lib | ||
| run: ./build-android-static.sh | ||
|
|
||
| - name: Build hello-cpp-swift APK | ||
| run: ./gradlew :hello-cpp-swift:app:assembleDebug --stacktrace | ||
|
|
||
| - name: Summarize APK artifacts | ||
| if: always() | ||
| run: | | ||
| echo "## APK Artifacts (${{ matrix.os }} / swift:${{ matrix.swift_version }} / ${{ matrix.sdk_triple }})" >> "$GITHUB_STEP_SUMMARY" | ||
| echo "" >> "$GITHUB_STEP_SUMMARY" | ||
| echo "| Project | APK | Size |" >> "$GITHUB_STEP_SUMMARY" | ||
| echo "|---------|-----|------|" >> "$GITHUB_STEP_SUMMARY" | ||
| found=0 | ||
| while IFS= read -r apk; do | ||
| found=1 | ||
| # Derive a human-readable project name from the path | ||
| project=$(echo "$apk" | sed -E 's#^\./##; s#/build/outputs/.*##') | ||
| name=$(basename "$apk") | ||
| # Human-readable size (du -h works on both Linux and macOS) | ||
| size=$(du -h "$apk" | cut -f1 | tr -d '[:space:]') | ||
| echo "| \`$project\` | \`$name\` | $size |" >> "$GITHUB_STEP_SUMMARY" | ||
| done < <(find . -path '*/build/outputs/apk/*.apk' -type f | sort) | ||
| if [ "$found" -eq 0 ]; then | ||
| echo "| _(none)_ | — | — |" >> "$GITHUB_STEP_SUMMARY" | ||
| fi | ||
|
|
||
| - name: Upload APK artifacts | ||
| if: always() | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: apks-${{ matrix.os }}-${{ matrix.swift_version }}-${{ matrix.sdk_triple }}-${{ matrix.ndk_version }} | ||
| path: '**/build/outputs/apk/**/*.apk' | ||
| if-no-files-found: warn | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -99,8 +99,15 @@ def swiftRuntimeLibs = [ | |
| "swiftSynchronization" | ||
| ] | ||
|
|
||
| def sdkName = "swift-6.3-RELEASE_android.artifactbundle" | ||
| def swiftVersion = "6.3" | ||
| // Swift toolchain version passed to swiftly (e.g. "6.3", "main-snapshot"). | ||
| // Can be overridden via the SWIFT_VERSION environment variable, which is | ||
| // useful for CI matrices that test multiple toolchains. | ||
| def swiftVersion = System.getenv("SWIFT_VERSION") ?: "6.3" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not your fault, but worth calling out: this exact 6-line block is now duplicated across three |
||
| // Android Swift SDK artifactbundle suffix. Substituted into the bundle | ||
| // directory name as "swift-${androidSdkVersion}.artifactbundle". Can be | ||
| // overridden via the SWIFT_ANDROID_SDK_VERSION environment variable. | ||
| def androidSdkVersion = System.getenv("SWIFT_ANDROID_SDK_VERSION") ?: "${swiftVersion}-RELEASE_android" | ||
| def sdkName = "swift-${androidSdkVersion}.artifactbundle" | ||
| def minSdk = android.defaultConfig.minSdkVersion.apiLevel | ||
| /** | ||
| * Android ABIs and their Swift triple mappings | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,8 +14,14 @@ data class SwiftConfig( | |
| var releaseExtraBuildFlags: List<String> = emptyList(), | ||
| var swiftlyPath: String? = null, // Optional custom swiftly path | ||
| var swiftSDKPath: String? = null, // Optional custom Swift SDK path | ||
| var swiftVersion: String = "6.3", // Swift version | ||
| var androidSdkVersion: String = "6.3-RELEASE_android" // SDK version | ||
| // Swift toolchain version passed to swiftly (e.g. "6.3", "main-snapshot"). | ||
| // Can be overridden via the SWIFT_VERSION environment variable, which is | ||
| // useful for CI matrices that test multiple toolchains. | ||
| var swiftVersion: String = System.getenv("SWIFT_VERSION")?.takeIf { it.isNotEmpty() } ?: "6.3", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. subtle behavior mismatch with the three groovy files: here you do |
||
| // Android Swift SDK artifactbundle suffix. Substituted into the bundle | ||
| // directory name as "swift-${androidSdkVersion}.artifactbundle". Can be | ||
| // overridden via the SWIFT_ANDROID_SDK_VERSION environment variable. | ||
| var androidSdkVersion: String = System.getenv("SWIFT_ANDROID_SDK_VERSION")?.takeIf { it.isNotEmpty() } ?: "${swiftVersion}-RELEASE_android" | ||
| ) | ||
|
|
||
| // Architecture definitions | ||
|
|
@@ -296,4 +302,4 @@ project.afterEvaluate { | |
| } else { | ||
| throw GradleException("Android extension not found. Make sure to apply this script after the Android plugin.") | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no
concurrency:group means rapid pushes to a PR branch queue up N redundant matrix runs. usual pattern for this repo would be something like:at the top of the workflow