name: Apple on: push: branches: - main - release/* pull_request: paths: - .ci/scripts/setup-ios.sh - .github/workflows/apple.yml - install_requirements.sh - backends/apple/** - build/build_apple_frameworks.sh - build/build_apple_llm_demo.sh - build/create_frameworks.sh - build/test_ios_ci.sh - examples/demo-apps/apple_ios/** - extension/apple/** - extension/benchmark/apple/** - extension/module/** workflow_dispatch: schedule: - cron: '0 10 * * *' # Runs daily at 2 AM PST concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ github.event_name == 'workflow_dispatch' }}-${{ github.event_name == 'schedule' }} cancel-in-progress: true jobs: set-version: runs-on: ubuntu-22.04 outputs: version: ${{ steps.set_version.outputs.version }} steps: - name: Set VERSION variable id: set_version shell: bash run: | VERSION="0.4.0.$(TZ='PST8PDT' date +%Y%m%d)" echo "version=$VERSION" >> "$GITHUB_OUTPUT" build-demo-ios: name: build-demo-ios uses: pytorch/test-infra/.github/workflows/macos_job.yml@release/2.5 secrets: inherit with: runner: macos-latest-xlarge python-version: '3.11' submodules: 'true' ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} timeout: 90 secrets-env: BUILD_CERTIFICATE_BASE64 EXECUTORCH_DEMO_BUILD_PROVISION_PROFILE_BASE64 KEYCHAIN_PASSWORD upload-artifact: ios-apps script: | set -eux BUILD_TOOL=cmake .ci/scripts/setup-conda.sh # Setup Apple certificate for iOS development BUILD_PROVISION_PROFILE_BASE64="${SECRET_EXECUTORCH_DEMO_BUILD_PROVISION_PROFILE_BASE64}" \ BUILD_CERTIFICATE_BASE64="${SECRET_BUILD_CERTIFICATE_BASE64}" \ KEYCHAIN_PASSWORD="${SECRET_KEYCHAIN_PASSWORD}" \ .ci/scripts/setup-ios.sh # Setup MacOS dependencies as there is no Docker support on MacOS atm GITHUB_RUNNER=1 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ .ci/scripts/setup-macos.sh "${BUILD_TOOL}" export ARTIFACTS_DIR_NAME=artifacts-to-be-uploaded # Build and test iOS Demo App PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ build/test_ios_ci.sh "${ARTIFACTS_DIR_NAME}" # Upload the test demo app to S3 upload-demo-ios: needs: build-demo-ios runs-on: linux.2xlarge steps: - name: Download the artifacts from GitHub uses: actions/download-artifact@v3 with: # The name here needs to match the name of the upload-artifact parameter name: ios-apps path: ${{ runner.temp }}/artifacts/ - name: Verify the artifacts shell: bash working-directory: ${{ runner.temp }}/artifacts/ run: | set -eux ls -lah ./ - name: Upload the artifacts to S3 uses: seemethere/upload-artifact-s3@v5 with: s3-bucket: gha-artifacts s3-prefix: | ${{ github.repository }}/${{ github.run_id }}/artifact retention-days: 14 if-no-files-found: ignore path: ${{ runner.temp }}/artifacts/ test-demo-ios: # Only PR from ExecuTorch itself has permission to access AWS, forked PRs will fail to # authenticate with the cloud service. So, this job will be skipped on the latter if: ${{ !github.event.pull_request.head.repo.fork }} needs: upload-demo-ios permissions: id-token: write contents: read uses: pytorch/test-infra/.github/workflows/mobile_job.yml@release/2.5 with: device-type: ios # For iOS testing, the runner just needs to call AWS Device Farm, so there is no need to run this on macOS runner: linux.2xlarge test-infra-ref: '' # This is the ARN of ExecuTorch project on AWS project-arn: arn:aws:devicefarm:us-west-2:308535385114:project:02a2cf0f-6d9b-45ee-ba1a-a086587469e6 # This is the custom device pool that only includes iOS devices device-pool-arn: arn:aws:devicefarm:us-west-2:308535385114:devicepool:02a2cf0f-6d9b-45ee-ba1a-a086587469e6/3b5acd2e-92e2-4778-b651-7726bafe129d # Uploaded to S3 from the previous job ios-ipa-archive: https://gha-artifacts.s3.amazonaws.com/${{ github.repository }}/${{ github.run_id }}/artifact/ExecuTorchDemo.ipa ios-xctestrun-zip: https://gha-artifacts.s3.amazonaws.com/${{ github.repository }}/${{ github.run_id }}/artifact/ExecuTorchDemo.xctestrun.zip test-spec: https://ossci-ios.s3.amazonaws.com/executorch/default-ios-device-farm-appium-test-spec.yml build-frameworks-ios: name: build-frameworks-ios needs: set-version uses: pytorch/test-infra/.github/workflows/macos_job.yml@main with: runner: macos-latest-xlarge python-version: '3.11' submodules: 'true' ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} upload-artifact: executorch-frameworks-ios timeout: 90 script: | set -eux BUILD_TOOL=cmake VERSION="${{ needs.set-version.outputs.version }}" FRAMEWORKS=( "executorch" "backend_coreml" "backend_mps" "backend_xnnpack" "kernels_custom" "kernels_optimized" "kernels_portable" "kernels_quantized" ) .ci/scripts/setup-conda.sh # Setup MacOS dependencies as there is no Docker support on MacOS atm GITHUB_RUNNER=1 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ .ci/scripts/setup-macos.sh "${BUILD_TOOL}" # Install CoreML Backend Requirements PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ backends/apple/coreml/scripts/install_requirements.sh # Install MPS Backend Requirements PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ backends/apple/mps/install_requirements.sh # Build Release iOS Frameworks PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ build/build_apple_frameworks.sh --coreml --custom --mps --optimized --portable --quantized --xnnpack # Bundle Release iOS Frameworks for FRAMEWORK in "${FRAMEWORKS[@]}"; do ( cd cmake-out && \ zip -r "${RUNNER_TEMP}/artifacts/${FRAMEWORK}-${VERSION}.zip" "${FRAMEWORK}.xcframework" ) done # Build Debug iOS Frameworks PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ build/build_apple_frameworks.sh --coreml --custom --mps --optimized --portable --quantized --xnnpack --Debug # Bundle Debug iOS Frameworks for FRAMEWORK in "${FRAMEWORKS[@]}"; do ( cd cmake-out && \ mv "${FRAMEWORK}.xcframework" "${FRAMEWORK}_debug.xcframework" && \ zip -r "${RUNNER_TEMP}/artifacts/${FRAMEWORK}_debug-${VERSION}.zip" "${FRAMEWORK}_debug.xcframework" ) done upload-frameworks-ios: runs-on: ubuntu-22.04 needs: [build-frameworks-ios, set-version] timeout-minutes: 30 environment: ${{ github.ref == 'refs/heads/main' && 'cherry-pick-bot' || '' }} permissions: id-token: write contents: write steps: - uses: actions/checkout@v3 with: fetch-depth: 0 token: ${{ secrets.GH_PYTORCHBOT_CHERRY_PICK_TOKEN || secrets.GITHUB_TOKEN }} - uses: actions/setup-python@v4 with: python-version: '3.11' cache: pip - name: configure aws credentials uses: aws-actions/configure-aws-credentials@v1.7.0 with: role-to-assume: arn:aws:iam::308535385114:role/gha_executorch_upload-frameworks-ios aws-region: us-east-1 - name: Download the artifact uses: actions/download-artifact@v3 with: # NB: The name here needs to match the upload-artifact name from build-frameworks-ios job name: executorch-frameworks-ios path: ${{ runner.temp }}/frameworks-ios/ - name: Only push to S3 when running the workflow manually from main branch if: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main' }} shell: bash run: | echo "UPLOAD_ON_MAIN=1" >> "${GITHUB_ENV}" - name: Upload the artifact to ossci-ios S3 bucket shell: bash run: | set -eux VERSION="${{ needs.set-version.outputs.version }}" pip install awscli==1.32.18 AWS_CMD="aws s3 cp --dryrun" if [[ "${UPLOAD_ON_MAIN:-0}" == "1" ]]; then AWS_CMD="aws s3 cp" fi for FILENAME in "${RUNNER_TEMP}"/frameworks-ios/*.zip; do [ -e "${FILENAME}" ] || continue FRAMEWORK_NAME=$(basename "${FILENAME}" | sed "s/-${VERSION}.zip//") CHECKSUM=$(shasum -a 256 "${FILENAME}" | cut -d ' ' -f1) echo "${FRAMEWORK_NAME} ${CHECKSUM}" >> "${RUNNER_TEMP}/checksums.txt" ${AWS_CMD} "${FILENAME}" s3://ossci-ios/executorch/ --acl public-read done - name: Update SwiftPM shell: bash run: | set -eux VERSION="${{ needs.set-version.outputs.version }}" BRANCH="swiftpm-${VERSION}" git checkout swiftpm if git show-ref --verify --quiet refs/heads/${BRANCH}; then git checkout "${BRANCH}" else git checkout -b "${BRANCH}" fi [[ -f Package.swift ]] || mv Package.swift.template Package.swift sed -i "s/__VERSION__/${VERSION}/g" Package.swift while read -r FRAMEWORK CHECKSUM; do sed -i "s/__SHA256_${FRAMEWORK}__/${CHECKSUM}/g" Package.swift done < "${RUNNER_TEMP}/checksums.txt" if [[ "${UPLOAD_ON_MAIN:-0}" == "1" ]]; then git config --global user.name "PyTorch Bot" git config --global user.email "pytorchbot@users.noreply.github.com" git add Package.swift git commit -am "${VERSION}" git push -f origin "${BRANCH}" else echo "Draft Package.swift:" cat Package.swift fi build-benchmark-app: name: build-benchmark-app uses: pytorch/test-infra/.github/workflows/macos_job.yml@main secrets: inherit with: runner: macos-latest-xlarge python-version: '3.11' submodules: 'true' ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} upload-artifact: ios-apps secrets-env: BUILD_CERTIFICATE_BASE64 EXECUTORCH_BENCHMARK_BUILD_PROVISION_PROFILE_BASE64 KEYCHAIN_PASSWORD timeout: 90 script: | set -eux echo "::group::Setting up CI environment" .ci/scripts/setup-conda.sh BUILD_TOOL=cmake # Setup MacOS dependencies as there is no Docker support on MacOS atm GITHUB_RUNNER=1 PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ .ci/scripts/setup-macos.sh "${BUILD_TOOL}" export ARTIFACTS_DIR_NAME=artifacts-to-be-uploaded # Setup Apple certificate for iOS development BUILD_PROVISION_PROFILE_BASE64="${SECRET_EXECUTORCH_BENCHMARK_BUILD_PROVISION_PROFILE_BASE64}" \ BUILD_CERTIFICATE_BASE64="${SECRET_BUILD_CERTIFICATE_BASE64}" \ KEYCHAIN_PASSWORD="${SECRET_KEYCHAIN_PASSWORD}" \ .ci/scripts/setup-ios.sh # Install CoreML Backend Requirements PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ backends/apple/coreml/scripts/install_requirements.sh # Install MPS Backend Requirements PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ backends/apple/mps/install_requirements.sh echo "::endgroup::" echo "::group::Build ExecuTorch iOS frameworks" FRAMEWORKS=( "executorch" "backend_coreml" "backend_mps" "backend_xnnpack" "kernels_custom" "kernels_optimized" "kernels_portable" "kernels_quantized" ) # Build Release iOS Frameworks PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \ build/build_apple_frameworks.sh --coreml --custom --mps --optimized --portable --quantized --xnnpack mkdir -p extension/benchmark/apple/Benchmark/Frameworks for FRAMEWORK in "${FRAMEWORKS[@]}"; do ( cp -r "cmake-out/${FRAMEWORK}.xcframework" extension/benchmark/apple/Benchmark/Frameworks/ ) done echo "::endgroup::" echo "::group::Build ExecuTorch benchmark app" mkdir -p extension/benchmark/apple/Benchmark/Models ${CONDA_RUN} --no-capture-output \ build/build_apple_llm_demo.sh "${ARTIFACTS_DIR_NAME}" echo "::endgroup::"