• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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