1name: Apple 2 3on: 4 push: 5 branches: 6 - main 7 - release/* 8 pull_request: 9 paths: 10 - .ci/scripts/setup-ios.sh 11 - .github/workflows/apple.yml 12 - install_requirements.sh 13 - backends/apple/** 14 - build/build_apple_frameworks.sh 15 - build/build_apple_llm_demo.sh 16 - build/create_frameworks.sh 17 - build/test_ios_ci.sh 18 - examples/demo-apps/apple_ios/** 19 - extension/apple/** 20 - extension/benchmark/apple/** 21 - extension/module/** 22 workflow_dispatch: 23 schedule: 24 - cron: '0 10 * * *' # Runs daily at 2 AM PST 25 26concurrency: 27 group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ github.event_name == 'workflow_dispatch' }}-${{ github.event_name == 'schedule' }} 28 cancel-in-progress: true 29 30jobs: 31 set-version: 32 runs-on: ubuntu-22.04 33 outputs: 34 version: ${{ steps.set_version.outputs.version }} 35 steps: 36 - name: Set VERSION variable 37 id: set_version 38 shell: bash 39 run: | 40 VERSION="0.4.0.$(TZ='PST8PDT' date +%Y%m%d)" 41 echo "version=$VERSION" >> "$GITHUB_OUTPUT" 42 43 build-demo-ios: 44 name: build-demo-ios 45 uses: pytorch/test-infra/.github/workflows/macos_job.yml@release/2.5 46 secrets: inherit 47 with: 48 runner: macos-latest-xlarge 49 python-version: '3.11' 50 submodules: 'true' 51 ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} 52 timeout: 90 53 secrets-env: BUILD_CERTIFICATE_BASE64 EXECUTORCH_DEMO_BUILD_PROVISION_PROFILE_BASE64 KEYCHAIN_PASSWORD 54 upload-artifact: ios-apps 55 script: | 56 set -eux 57 58 BUILD_TOOL=cmake 59 60 .ci/scripts/setup-conda.sh 61 62 # Setup Apple certificate for iOS development 63 BUILD_PROVISION_PROFILE_BASE64="${SECRET_EXECUTORCH_DEMO_BUILD_PROVISION_PROFILE_BASE64}" \ 64 BUILD_CERTIFICATE_BASE64="${SECRET_BUILD_CERTIFICATE_BASE64}" \ 65 KEYCHAIN_PASSWORD="${SECRET_KEYCHAIN_PASSWORD}" \ 66 .ci/scripts/setup-ios.sh 67 68 # Setup MacOS dependencies as there is no Docker support on MacOS atm 69 GITHUB_RUNNER=1 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ 70 .ci/scripts/setup-macos.sh "${BUILD_TOOL}" 71 72 export ARTIFACTS_DIR_NAME=artifacts-to-be-uploaded 73 74 # Build and test iOS Demo App 75 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ 76 build/test_ios_ci.sh "${ARTIFACTS_DIR_NAME}" 77 78 # Upload the test demo app to S3 79 upload-demo-ios: 80 needs: build-demo-ios 81 runs-on: linux.2xlarge 82 steps: 83 - name: Download the artifacts from GitHub 84 uses: actions/download-artifact@v3 85 with: 86 # The name here needs to match the name of the upload-artifact parameter 87 name: ios-apps 88 path: ${{ runner.temp }}/artifacts/ 89 90 - name: Verify the artifacts 91 shell: bash 92 working-directory: ${{ runner.temp }}/artifacts/ 93 run: | 94 set -eux 95 ls -lah ./ 96 97 - name: Upload the artifacts to S3 98 uses: seemethere/upload-artifact-s3@v5 99 with: 100 s3-bucket: gha-artifacts 101 s3-prefix: | 102 ${{ github.repository }}/${{ github.run_id }}/artifact 103 retention-days: 14 104 if-no-files-found: ignore 105 path: ${{ runner.temp }}/artifacts/ 106 107 test-demo-ios: 108 # Only PR from ExecuTorch itself has permission to access AWS, forked PRs will fail to 109 # authenticate with the cloud service. So, this job will be skipped on the latter 110 if: ${{ !github.event.pull_request.head.repo.fork }} 111 needs: upload-demo-ios 112 permissions: 113 id-token: write 114 contents: read 115 uses: pytorch/test-infra/.github/workflows/mobile_job.yml@release/2.5 116 with: 117 device-type: ios 118 # For iOS testing, the runner just needs to call AWS Device Farm, so there is no need to run this on macOS 119 runner: linux.2xlarge 120 test-infra-ref: '' 121 # This is the ARN of ExecuTorch project on AWS 122 project-arn: arn:aws:devicefarm:us-west-2:308535385114:project:02a2cf0f-6d9b-45ee-ba1a-a086587469e6 123 # This is the custom device pool that only includes iOS devices 124 device-pool-arn: arn:aws:devicefarm:us-west-2:308535385114:devicepool:02a2cf0f-6d9b-45ee-ba1a-a086587469e6/3b5acd2e-92e2-4778-b651-7726bafe129d 125 # Uploaded to S3 from the previous job 126 ios-ipa-archive: https://gha-artifacts.s3.amazonaws.com/${{ github.repository }}/${{ github.run_id }}/artifact/ExecuTorchDemo.ipa 127 ios-xctestrun-zip: https://gha-artifacts.s3.amazonaws.com/${{ github.repository }}/${{ github.run_id }}/artifact/ExecuTorchDemo.xctestrun.zip 128 test-spec: https://ossci-ios.s3.amazonaws.com/executorch/default-ios-device-farm-appium-test-spec.yml 129 130 build-frameworks-ios: 131 name: build-frameworks-ios 132 needs: set-version 133 uses: pytorch/test-infra/.github/workflows/macos_job.yml@main 134 with: 135 runner: macos-latest-xlarge 136 python-version: '3.11' 137 submodules: 'true' 138 ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} 139 upload-artifact: executorch-frameworks-ios 140 timeout: 90 141 script: | 142 set -eux 143 144 BUILD_TOOL=cmake 145 VERSION="${{ needs.set-version.outputs.version }}" 146 FRAMEWORKS=( 147 "executorch" 148 "backend_coreml" 149 "backend_mps" 150 "backend_xnnpack" 151 "kernels_custom" 152 "kernels_optimized" 153 "kernels_portable" 154 "kernels_quantized" 155 ) 156 157 .ci/scripts/setup-conda.sh 158 159 # Setup MacOS dependencies as there is no Docker support on MacOS atm 160 GITHUB_RUNNER=1 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ 161 .ci/scripts/setup-macos.sh "${BUILD_TOOL}" 162 163 # Install CoreML Backend Requirements 164 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ 165 backends/apple/coreml/scripts/install_requirements.sh 166 167 # Install MPS Backend Requirements 168 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ 169 backends/apple/mps/install_requirements.sh 170 171 # Build Release iOS Frameworks 172 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ 173 build/build_apple_frameworks.sh --coreml --custom --mps --optimized --portable --quantized --xnnpack 174 175 # Bundle Release iOS Frameworks 176 for FRAMEWORK in "${FRAMEWORKS[@]}"; do ( 177 cd cmake-out && \ 178 zip -r "${RUNNER_TEMP}/artifacts/${FRAMEWORK}-${VERSION}.zip" "${FRAMEWORK}.xcframework" 179 ) done 180 181 # Build Debug iOS Frameworks 182 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ 183 build/build_apple_frameworks.sh --coreml --custom --mps --optimized --portable --quantized --xnnpack --Debug 184 185 # Bundle Debug iOS Frameworks 186 for FRAMEWORK in "${FRAMEWORKS[@]}"; do ( 187 cd cmake-out && \ 188 mv "${FRAMEWORK}.xcframework" "${FRAMEWORK}_debug.xcframework" && \ 189 zip -r "${RUNNER_TEMP}/artifacts/${FRAMEWORK}_debug-${VERSION}.zip" "${FRAMEWORK}_debug.xcframework" 190 ) done 191 192 upload-frameworks-ios: 193 runs-on: ubuntu-22.04 194 needs: [build-frameworks-ios, set-version] 195 timeout-minutes: 30 196 environment: ${{ github.ref == 'refs/heads/main' && 'cherry-pick-bot' || '' }} 197 permissions: 198 id-token: write 199 contents: write 200 steps: 201 - uses: actions/checkout@v3 202 with: 203 fetch-depth: 0 204 token: ${{ secrets.GH_PYTORCHBOT_CHERRY_PICK_TOKEN || secrets.GITHUB_TOKEN }} 205 - uses: actions/setup-python@v4 206 with: 207 python-version: '3.11' 208 cache: pip 209 - name: configure aws credentials 210 uses: aws-actions/configure-aws-credentials@v1.7.0 211 with: 212 role-to-assume: arn:aws:iam::308535385114:role/gha_executorch_upload-frameworks-ios 213 aws-region: us-east-1 214 - name: Download the artifact 215 uses: actions/download-artifact@v3 216 with: 217 # NB: The name here needs to match the upload-artifact name from build-frameworks-ios job 218 name: executorch-frameworks-ios 219 path: ${{ runner.temp }}/frameworks-ios/ 220 - name: Only push to S3 when running the workflow manually from main branch 221 if: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main' }} 222 shell: bash 223 run: | 224 echo "UPLOAD_ON_MAIN=1" >> "${GITHUB_ENV}" 225 - name: Upload the artifact to ossci-ios S3 bucket 226 shell: bash 227 run: | 228 set -eux 229 VERSION="${{ needs.set-version.outputs.version }}" 230 231 pip install awscli==1.32.18 232 233 AWS_CMD="aws s3 cp --dryrun" 234 if [[ "${UPLOAD_ON_MAIN:-0}" == "1" ]]; then 235 AWS_CMD="aws s3 cp" 236 fi 237 238 for FILENAME in "${RUNNER_TEMP}"/frameworks-ios/*.zip; do 239 [ -e "${FILENAME}" ] || continue 240 FRAMEWORK_NAME=$(basename "${FILENAME}" | sed "s/-${VERSION}.zip//") 241 CHECKSUM=$(shasum -a 256 "${FILENAME}" | cut -d ' ' -f1) 242 echo "${FRAMEWORK_NAME} ${CHECKSUM}" >> "${RUNNER_TEMP}/checksums.txt" 243 ${AWS_CMD} "${FILENAME}" s3://ossci-ios/executorch/ --acl public-read 244 done 245 - name: Update SwiftPM 246 shell: bash 247 run: | 248 set -eux 249 VERSION="${{ needs.set-version.outputs.version }}" 250 BRANCH="swiftpm-${VERSION}" 251 252 git checkout swiftpm 253 254 if git show-ref --verify --quiet refs/heads/${BRANCH}; then 255 git checkout "${BRANCH}" 256 else 257 git checkout -b "${BRANCH}" 258 fi 259 260 [[ -f Package.swift ]] || mv Package.swift.template Package.swift 261 262 sed -i "s/__VERSION__/${VERSION}/g" Package.swift 263 264 while read -r FRAMEWORK CHECKSUM; do 265 sed -i "s/__SHA256_${FRAMEWORK}__/${CHECKSUM}/g" Package.swift 266 done < "${RUNNER_TEMP}/checksums.txt" 267 268 if [[ "${UPLOAD_ON_MAIN:-0}" == "1" ]]; then 269 git config --global user.name "PyTorch Bot" 270 git config --global user.email "pytorchbot@users.noreply.github.com" 271 git add Package.swift 272 git commit -am "${VERSION}" 273 git push -f origin "${BRANCH}" 274 else 275 echo "Draft Package.swift:" 276 cat Package.swift 277 fi 278 279 build-benchmark-app: 280 name: build-benchmark-app 281 uses: pytorch/test-infra/.github/workflows/macos_job.yml@main 282 secrets: inherit 283 with: 284 runner: macos-latest-xlarge 285 python-version: '3.11' 286 submodules: 'true' 287 ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} 288 upload-artifact: ios-apps 289 secrets-env: BUILD_CERTIFICATE_BASE64 EXECUTORCH_BENCHMARK_BUILD_PROVISION_PROFILE_BASE64 KEYCHAIN_PASSWORD 290 timeout: 90 291 script: | 292 set -eux 293 294 echo "::group::Setting up CI environment" 295 .ci/scripts/setup-conda.sh 296 297 BUILD_TOOL=cmake 298 # Setup MacOS dependencies as there is no Docker support on MacOS atm 299 GITHUB_RUNNER=1 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ 300 .ci/scripts/setup-macos.sh "${BUILD_TOOL}" 301 export ARTIFACTS_DIR_NAME=artifacts-to-be-uploaded 302 303 # Setup Apple certificate for iOS development 304 BUILD_PROVISION_PROFILE_BASE64="${SECRET_EXECUTORCH_BENCHMARK_BUILD_PROVISION_PROFILE_BASE64}" \ 305 BUILD_CERTIFICATE_BASE64="${SECRET_BUILD_CERTIFICATE_BASE64}" \ 306 KEYCHAIN_PASSWORD="${SECRET_KEYCHAIN_PASSWORD}" \ 307 .ci/scripts/setup-ios.sh 308 309 # Install CoreML Backend Requirements 310 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ 311 backends/apple/coreml/scripts/install_requirements.sh 312 313 # Install MPS Backend Requirements 314 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ 315 backends/apple/mps/install_requirements.sh 316 echo "::endgroup::" 317 318 echo "::group::Build ExecuTorch iOS frameworks" 319 FRAMEWORKS=( 320 "executorch" 321 "backend_coreml" 322 "backend_mps" 323 "backend_xnnpack" 324 "kernels_custom" 325 "kernels_optimized" 326 "kernels_portable" 327 "kernels_quantized" 328 ) 329 330 # Build Release iOS Frameworks 331 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ 332 build/build_apple_frameworks.sh --coreml --custom --mps --optimized --portable --quantized --xnnpack 333 334 mkdir -p extension/benchmark/apple/Benchmark/Frameworks 335 for FRAMEWORK in "${FRAMEWORKS[@]}"; do ( 336 cp -r "cmake-out/${FRAMEWORK}.xcframework" extension/benchmark/apple/Benchmark/Frameworks/ 337 ) done 338 echo "::endgroup::" 339 340 echo "::group::Build ExecuTorch benchmark app" 341 mkdir -p extension/benchmark/apple/Benchmark/Models 342 ${CONDA_RUN} --no-capture-output \ 343 build/build_apple_llm_demo.sh "${ARTIFACTS_DIR_NAME}" 344 echo "::endgroup::" 345