Skip to content
Latchkey

build-hermes-macos workflow (facebook/hermes)

The build-hermes-macos workflow from facebook/hermes, explained and optimized by Latchkey.

A

CI health: A - excellent

Run this on Latchkey for self-healing, caching, and up to 58% lower cost.

Grade your own workflow free or run it on Latchkey →
Source: facebook/hermes.github/workflows/build-hermes-macos.ymlLicense MITView source

What it does

This is the build-hermes-macos workflow from the facebook/hermes repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
name: build-hermes-macos

on: workflow_call

jobs:
  build-hermes-macos:
    runs-on: macos-15
    continue-on-error: true
    env:
      HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
    strategy:
      fail-fast: false
      matrix:
        flavor: [Debug, Release]
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Setup xcode
        uses: ./.github/actions/setup-xcode
      - name: Setup node.js
        uses: ./.github/actions/setup-node
      - name: Yarn Install Dependencies
        uses: ./.github/actions/yarn-install
      - name: Download slice artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: slice-*-${{ matrix.flavor }}
          path: .
          merge-multiple: true
      - name: Unzip slices
        shell: bash
        run: |
          ls -l .
          tar -xzv -f build_catalyst_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_iphoneos_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_iphonesimulator_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_appletvos_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_appletvsimulator_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_macosx_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_xros_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_xrsimulator_${{ matrix.flavor }}.tar.gz
      - name: Move back build folders
        shell: bash
        run: |
          ls -l build_*
          mv build_catalyst_${{ matrix.flavor }} build_catalyst
          mv build_iphoneos_${{ matrix.flavor }} build_iphoneos
          mv build_iphonesimulator_${{ matrix.flavor }} build_iphonesimulator
          mv build_appletvos_${{ matrix.flavor }} build_appletvos
          mv build_appletvsimulator_${{ matrix.flavor }} build_appletvsimulator
          mv build_macosx_${{ matrix.flavor }} build_macosx
          mv build_xros_${{ matrix.flavor }} build_xros
          mv build_xrsimulator_${{ matrix.flavor }} build_xrsimulator
      - name: Prepare destroot folder
        shell: bash
        run: ./utils/build-apple-framework.sh prepare_dest_root
      - name: Create universal xcframework
        shell: bash
        run: |
          echo "[HERMES] Creating the universal framework"
          ./utils/build-apple-framework.sh build_framework
          chmod +x ./destroot/bin/hermesc
      - name: Package the Hermes Apple frameworks
        shell: bash
        run: |
          BUILD_TYPE="${{ matrix.flavor }}"
          echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type"

          TARBALL_OUTPUT_DIR=$(mktemp -d /tmp/hermes-tarball-output-XXXXXXXX)

          echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type"

          TARBALL_OUTPUT_PATH=$(node ./utils/scripts/hermes/create-tarball.js \
            --inputDir . \
            --buildType "$BUILD_TYPE" \
            --outputDir $TARBALL_OUTPUT_DIR)

          echo "Hermes tarball saved to $TARBALL_OUTPUT_PATH"

          mkdir -p $HERMES_TARBALL_ARTIFACTS_DIR
          cp $TARBALL_OUTPUT_PATH $HERMES_TARBALL_ARTIFACTS_DIR/.

          mkdir -p /tmp/hermes/osx-bin/${{ matrix.flavor }}
          cp ./build_macosx/bin/* /tmp/hermes/osx-bin/${{ matrix.flavor }}
          ls -lR /tmp/hermes/osx-bin/
      - name: Create dSYM archive
        shell: bash
        run: |
          FLAVOR=${{ matrix.flavor }}
          WORKING_DIR="/tmp/hermes_tmp/dSYM/$FLAVOR"

          mkdir -p "$WORKING_DIR/macosx"
          mkdir -p "$WORKING_DIR/catalyst"
          mkdir -p "$WORKING_DIR/iphoneos"
          mkdir -p "$WORKING_DIR/iphonesimulator"
          mkdir -p "$WORKING_DIR/appletvos"
          mkdir -p "$WORKING_DIR/appletvsimulator"
          mkdir -p "$WORKING_DIR/xros"
          mkdir -p "$WORKING_DIR/xrsimulator"

          DSYM_FILE_PATH=lib/hermesvm.framework.dSYM
          cp -r build_macosx/$DSYM_FILE_PATH "$WORKING_DIR/macosx/"
          cp -r build_catalyst/$DSYM_FILE_PATH "$WORKING_DIR/catalyst/"
          cp -r build_iphoneos/$DSYM_FILE_PATH "$WORKING_DIR/iphoneos/"
          cp -r build_iphonesimulator/$DSYM_FILE_PATH "$WORKING_DIR/iphonesimulator/"
          cp -r build_appletvos/$DSYM_FILE_PATH "$WORKING_DIR/appletvos/"
          cp -r build_appletvsimulator/$DSYM_FILE_PATH "$WORKING_DIR/appletvsimulator/"
          cp -r build_xros/$DSYM_FILE_PATH "$WORKING_DIR/xros/"
          cp -r build_xrsimulator/$DSYM_FILE_PATH "$WORKING_DIR/xrsimulator/"

          DEST_DIR="/tmp/hermes/dSYM/$FLAVOR"
          tar -C "$WORKING_DIR" -czvf "hermesvm.framework.dSYM" .

          mkdir -p "$DEST_DIR"
          mv "hermesvm.framework.dSYM" "$DEST_DIR"
      - name: Upload hermes dSYM artifacts
        uses: actions/upload-artifact@v4.3.4
        with:
          name: hermes-dSYM-${{ matrix.flavor }}
          path: /tmp/hermes/dSYM/${{ matrix.flavor }}
      - name: Upload hermes Runtime artifacts
        uses: actions/upload-artifact@v4.3.4
        with:
          name: hermes-darwin-bin-${{ matrix.flavor }}
          path: /tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ matrix.flavor }}.tar.gz
      - name: Upload hermes osx artifacts
        uses: actions/upload-artifact@v4.3.4
        with:
          name: hermes-osx-bin-${{ matrix.flavor }}
          path: /tmp/hermes/osx-bin/${{ matrix.flavor }}
      - name: Upload Hermes Artifacts
        uses: actions/cache/save@v4
        if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }} # To avoid that the cache explode.
        with:
          key: v4-hermes-artifacts-${{ matrix.flavor }}-${{ matrix.hermes-version }}-${{ matrix.react-native-version }}-${{ hashFiles('./packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}
          path: |
            /tmp/hermes/osx-bin/${{ matrix.flavor }}
            /tmp/hermes/dSYM/${{ matrix.flavor }}
            /tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ matrix.flavor }}.tar.gz

The same workflow, on Latchkey

Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.

name: build-hermes-macos
 
on: workflow_call
 
jobs:
  build-hermes-macos:
    timeout-minutes: 30
    runs-on: macos-15
    continue-on-error: true
    env:
      HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
    strategy:
      fail-fast: false
      matrix:
        flavor: [Debug, Release]
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Setup xcode
        uses: ./.github/actions/setup-xcode
      - name: Setup node.js
        uses: ./.github/actions/setup-node
      - name: Yarn Install Dependencies
        uses: ./.github/actions/yarn-install
      - name: Download slice artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: slice-*-${{ matrix.flavor }}
          path: .
          merge-multiple: true
      - name: Unzip slices
        shell: bash
        run: |
          ls -l .
          tar -xzv -f build_catalyst_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_iphoneos_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_iphonesimulator_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_appletvos_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_appletvsimulator_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_macosx_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_xros_${{ matrix.flavor }}.tar.gz
          tar -xzv -f build_xrsimulator_${{ matrix.flavor }}.tar.gz
      - name: Move back build folders
        shell: bash
        run: |
          ls -l build_*
          mv build_catalyst_${{ matrix.flavor }} build_catalyst
          mv build_iphoneos_${{ matrix.flavor }} build_iphoneos
          mv build_iphonesimulator_${{ matrix.flavor }} build_iphonesimulator
          mv build_appletvos_${{ matrix.flavor }} build_appletvos
          mv build_appletvsimulator_${{ matrix.flavor }} build_appletvsimulator
          mv build_macosx_${{ matrix.flavor }} build_macosx
          mv build_xros_${{ matrix.flavor }} build_xros
          mv build_xrsimulator_${{ matrix.flavor }} build_xrsimulator
      - name: Prepare destroot folder
        shell: bash
        run: ./utils/build-apple-framework.sh prepare_dest_root
      - name: Create universal xcframework
        shell: bash
        run: |
          echo "[HERMES] Creating the universal framework"
          ./utils/build-apple-framework.sh build_framework
          chmod +x ./destroot/bin/hermesc
      - name: Package the Hermes Apple frameworks
        shell: bash
        run: |
          BUILD_TYPE="${{ matrix.flavor }}"
          echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type"
 
          TARBALL_OUTPUT_DIR=$(mktemp -d /tmp/hermes-tarball-output-XXXXXXXX)
 
          echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type"
 
          TARBALL_OUTPUT_PATH=$(node ./utils/scripts/hermes/create-tarball.js \
            --inputDir . \
            --buildType "$BUILD_TYPE" \
            --outputDir $TARBALL_OUTPUT_DIR)
 
          echo "Hermes tarball saved to $TARBALL_OUTPUT_PATH"
 
          mkdir -p $HERMES_TARBALL_ARTIFACTS_DIR
          cp $TARBALL_OUTPUT_PATH $HERMES_TARBALL_ARTIFACTS_DIR/.
 
          mkdir -p /tmp/hermes/osx-bin/${{ matrix.flavor }}
          cp ./build_macosx/bin/* /tmp/hermes/osx-bin/${{ matrix.flavor }}
          ls -lR /tmp/hermes/osx-bin/
      - name: Create dSYM archive
        shell: bash
        run: |
          FLAVOR=${{ matrix.flavor }}
          WORKING_DIR="/tmp/hermes_tmp/dSYM/$FLAVOR"
 
          mkdir -p "$WORKING_DIR/macosx"
          mkdir -p "$WORKING_DIR/catalyst"
          mkdir -p "$WORKING_DIR/iphoneos"
          mkdir -p "$WORKING_DIR/iphonesimulator"
          mkdir -p "$WORKING_DIR/appletvos"
          mkdir -p "$WORKING_DIR/appletvsimulator"
          mkdir -p "$WORKING_DIR/xros"
          mkdir -p "$WORKING_DIR/xrsimulator"
 
          DSYM_FILE_PATH=lib/hermesvm.framework.dSYM
          cp -r build_macosx/$DSYM_FILE_PATH "$WORKING_DIR/macosx/"
          cp -r build_catalyst/$DSYM_FILE_PATH "$WORKING_DIR/catalyst/"
          cp -r build_iphoneos/$DSYM_FILE_PATH "$WORKING_DIR/iphoneos/"
          cp -r build_iphonesimulator/$DSYM_FILE_PATH "$WORKING_DIR/iphonesimulator/"
          cp -r build_appletvos/$DSYM_FILE_PATH "$WORKING_DIR/appletvos/"
          cp -r build_appletvsimulator/$DSYM_FILE_PATH "$WORKING_DIR/appletvsimulator/"
          cp -r build_xros/$DSYM_FILE_PATH "$WORKING_DIR/xros/"
          cp -r build_xrsimulator/$DSYM_FILE_PATH "$WORKING_DIR/xrsimulator/"
 
          DEST_DIR="/tmp/hermes/dSYM/$FLAVOR"
          tar -C "$WORKING_DIR" -czvf "hermesvm.framework.dSYM" .
 
          mkdir -p "$DEST_DIR"
          mv "hermesvm.framework.dSYM" "$DEST_DIR"
      - name: Upload hermes dSYM artifacts
        uses: actions/upload-artifact@v4.3.4
        with:
          name: hermes-dSYM-${{ matrix.flavor }}
          path: /tmp/hermes/dSYM/${{ matrix.flavor }}
      - name: Upload hermes Runtime artifacts
        uses: actions/upload-artifact@v4.3.4
        with:
          name: hermes-darwin-bin-${{ matrix.flavor }}
          path: /tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ matrix.flavor }}.tar.gz
      - name: Upload hermes osx artifacts
        uses: actions/upload-artifact@v4.3.4
        with:
          name: hermes-osx-bin-${{ matrix.flavor }}
          path: /tmp/hermes/osx-bin/${{ matrix.flavor }}
      - name: Upload Hermes Artifacts
        uses: actions/cache/save@v4
        if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }} # To avoid that the cache explode.
        with:
          key: v4-hermes-artifacts-${{ matrix.flavor }}-${{ matrix.hermes-version }}-${{ matrix.react-native-version }}-${{ hashFiles('./packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}
          path: |
            /tmp/hermes/osx-bin/${{ matrix.flavor }}
            /tmp/hermes/dSYM/${{ matrix.flavor }}
            /tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ matrix.flavor }}.tar.gz
 

What changed

What Latchkey heals here

This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:

This workflow runs 1 job (2 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow