Skip to content

Hermes prebuilt

Hermes prebuilt #5

Workflow file for this run

name: Hermes prebuilt
# Builds the pinned Hermes for Apple platforms and publishes it as a release
# asset, so `pod install` downloads it instead of compiling Hermes as part of
# every app build. The asset is keyed by everything that changes its contents,
# so a bumped pin publishes alongside the previous one rather than replacing it.
env:
GIT_CONFIG_COUNT: 1
GIT_CONFIG_KEY_0: "url.https://github.com/.insteadOf"
GIT_CONFIG_VALUE_0: "git@github.com:"
on:
workflow_dispatch:
push:
branches:
- main
- next
paths:
- "packages/host/src/node/cli/hermes.ts"
- "packages/host/src/node/cli/hermes-prebuilt.ts"
- ".github/workflows/hermes-prebuilt.yml"
# Two runs publishing the same tag would race on creating the release.
concurrency:
group: ${{ github.workflow }}
jobs:
publish:
name: Publish prebuilt Hermes
runs-on: macos-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: lts/krypton
- uses: pnpm/action-setup@v6
with:
cache: true
- run: pnpm install
- run: pnpm run build
# Resolved from the test app so the archive is built against the React
# Native version this repository actually pins.
# Each command substitution is assigned before it is echoed: inside
# `echo "x=$(cmd)"` the step's exit status is echo's, so a failing cmd
# passes the step with an empty value.
- name: Resolve prebuilt Hermes name
id: hermes
working-directory: apps/test-app
run: |
archive=$(pnpm exec react-native-node-api prebuilt-hermes --print name)
tag=$(pnpm exec react-native-node-api prebuilt-hermes --print tag)
echo "archive=$archive" >> "$GITHUB_OUTPUT"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
- name: Cache prebuilt Hermes
uses: actions/cache@v6
with:
path: ~/Library/Caches/react-native-node-api/hermes-prebuilt
key: ${{ steps.hermes.outputs.archive }}
# --no-download so a re-run rebuilds rather than round-tripping the asset
# it is about to publish.
- name: Build prebuilt Hermes
id: build
working-directory: apps/test-app
run: |
path=$(pnpm exec react-native-node-api prebuilt-hermes --no-download)
echo "path=$path" >> "$GITHUB_OUTPUT"
# CMake reports a failed feature check as a bare "not found", with the
# compiler's actual complaint only in its configure log. Surface that log
# here so a failure is diagnosable without another round trip.
- name: Dump CMake configure log
if: failure()
run: |
log=$(find "$PWD" -name CMakeConfigureLog.yaml -path '*build_host_hermesc*' | head -1)
if [ -z "$log" ]; then
echo "No CMakeConfigureLog.yaml found"
find "$PWD" -name 'CMakeError.log' -path '*build_host_hermesc*' -exec cat {} \;
exit 0
fi
echo "::group::Environment seen by CMake"
env | sort
xcode-select --print-path
xcrun --show-sdk-path || true
echo "::endgroup::"
echo "::group::unistd.h check"
grep -n -B 5 -A 45 'unistd\.h' "$log" | head -150
echo "::endgroup::"
echo "::group::atomics check"
grep -n -B 5 -A 60 'HAVE_CXX_ATOMICS_WITHOUT_LIB' "$log" | head -180
echo "::endgroup::"
cp "$log" "$RUNNER_TEMP/CMakeConfigureLog.yaml"
- name: Upload CMake configure log
if: failure()
uses: actions/upload-artifact@v7
with:
name: hermesc-cmake-configure-log
path: ${{ runner.temp }}/CMakeConfigureLog.yaml
if-no-files-found: ignore
# --latest=false keeps these out of the "latest release" slot, which
# belongs to the package releases changesets publishes.
- name: Publish as a release asset
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ steps.hermes.outputs.tag }}
ARCHIVE_PATH: ${{ steps.build.outputs.path }}
run: |
if ! gh release view "$TAG" --repo "$GITHUB_REPOSITORY" > /dev/null 2>&1; then
gh release create "$TAG" \
--repo "$GITHUB_REPOSITORY" \
--title "Prebuilt Hermes ($TAG)" \
--notes "Hermes, built for Apple platforms from the commit pinned in \`packages/host/src/node/cli/hermes.ts\`. Downloaded by \`react-native-node-api prebuilt-hermes\` and injected into the app's \`pod install\` through \`HERMES_ENGINE_TARBALL_PATH\`." \
--latest=false
fi
gh release upload "$TAG" "$ARCHIVE_PATH" --repo "$GITHUB_REPOSITORY" --clobber