Skip to content

Publish

Publish #28

Workflow file for this run

name: Publish
on:
workflow_dispatch:
inputs:
release_type:
description: Release type
type: choice
required: true
default: patch
options:
- patch
- minor
- major
- prepatch
- preminor
- premajor
- prerelease
dry_run:
description: Dry run (build everything and run `npm publish --dry-run`, but don't publish, commit, tag or create a release)
type: boolean
default: false
concurrency:
group: publish-${{ github.workflow }}
cancel-in-progress: false
jobs:
build-windows:
name: Build Windows tool (${{ matrix.arch }})
# SwiftPM builds macro tools only for the host, so each architecture builds on a runner of its own.
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
strategy:
matrix:
include:
- arch: x64
runner: windows-latest
build_arch: amd64
- arch: arm64
runner: windows-11-arm
build_arch: arm64
steps:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
- name: Install Swift
uses: compnerd/gha-setup-swift@bbae8ce86bac5a3449f3992b3d88bc4ca25f2057 # v0.5.0
with:
swift-version: swift-6.4.0-release
swift-build: 6.4.0-RELEASE
build_arch: ${{ matrix.build_arch }}
- name: Setup Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24
- name: Build release tool
# Runs scripts/build.js: builds the release plugin binary for this architecture as
# platforms/win32-<arch>/ExpoModulesMacros.exe.
run: npm run build
- name: Upload tool
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
# Named after the package directory: the publish job downloads every artifact into
# `platforms/`, and each one lands in a directory of its name.
name: win32-${{ matrix.arch }}
path: platforms/win32-${{ matrix.arch }}/ExpoModulesMacros.exe
if-no-files-found: error
publish:
name: Build and publish to npm
needs: build-windows
# Builds the native macOS tool binary, so it must run on macOS. The Windows binaries come from the
# build-windows jobs.
# The package declares swift-tools-version 6.2, which requires Xcode 26+.
runs-on: macos-26
permissions:
# Required for npm trusted publishing (OIDC) and provenance.
id-token: write
# Required to push the version bump commit/tag and create the release.
contents: write
steps:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
# The default token lets gh create the release and push the bump
# commit/tag. Note: commits pushed with GITHUB_TOKEN do NOT trigger
# other workflows (e.g. the Swift CI), by GitHub's design.
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24
registry-url: https://registry.npmjs.org
- name: Update npm
# Trusted publishing requires npm >= 11.5.1.
run: npm install -g npm@latest
- name: Configure git
run: |
git config user.name "expo-bot"
git config user.email "expo-bot@users.noreply.github.com"
- name: Bump version
id: bump
# Only edit package.json here; the commit, tag and release are created
# at the end so a failed build/publish leaves the branch untouched.
run: |
version=$(npm version "${{ inputs.release_type }}" --no-git-tag-version)
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "Bumping to $version"
# npm 11 doesn't publish a prerelease version (one with a hyphen) without a dist-tag, and
# it must not become `latest` anyway.
case "$version" in
*-*) tag=next ;;
*) tag=latest ;;
esac
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "Publishing with the dist-tag $tag"
# The platform packages get the same version, and `expo-modules-macros` lists them as
# optional dependencies with that exact version.
node scripts/set-platform-versions.js
- name: Select Xcode
# Pin to an Xcode that ships Swift 6.2 (required by Package.swift).
run: sudo xcode-select -switch /Applications/Xcode_26.4.1.app
- name: Cache SwiftPM build
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: apple/.build
key: spm-${{ github.repository }}-${{ runner.os }}-${{ hashFiles('apple/Package.resolved') }}
restore-keys: |
spm-${{ github.repository }}-${{ runner.os }}-
- name: Resolve dependencies
run: swift package resolve
working-directory: apple
- name: Install dependencies
# The wrapper's `prepublishOnly` build needs `tsc`; the tool binary needs none.
run: npm install
- name: Build release tool
# Runs scripts/build.js: builds the release plugin binary,
# copies it to apple/ExpoModulesMacros, and strips it.
run: npm run build
- name: Download Windows tools
# Each artifact goes into the directory of its name: `platforms/win32-<arch>`.
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
pattern: win32-*
path: platforms
- name: Verify Windows tools
run: ls -l platforms/win32-x64/ExpoModulesMacros.exe platforms/win32-arm64/ExpoModulesMacros.exe
- name: Publish the Windows packages
# Published before `expo-modules-macros`, whose optional dependencies point at them, so that
# package is never on npm without them. Each package needs trusted publishing (OIDC)
# configured on npmjs.com for this workflow.
env:
DRY_RUN: ${{ inputs.dry_run && '--dry-run' || '' }}
run: |
for arch in x64 arm64; do
npm publish --access public --tag "${{ steps.bump.outputs.tag }}" $DRY_RUN "./platforms/win32-$arch"
done
- name: Publish
# Authentication is handled via OIDC trusted publishing — no token needed.
# npm generates provenance automatically when publishing via OIDC.
env:
DRY_RUN: ${{ inputs.dry_run && '--dry-run' || '' }}
run: npm publish --access public --tag "${{ steps.bump.outputs.tag }}" $DRY_RUN
# Everything below only runs once the publish above has succeeded, and not in a dry run.
- name: Commit, tag and push
if: ${{ !inputs.dry_run }}
run: |
version="${{ steps.bump.outputs.version }}"
git commit -am "Release $version"
# Use an annotated tag so `git push --follow-tags` actually pushes it
# (--follow-tags ignores lightweight tags).
git tag -a "$version" -m "Release $version"
git push --follow-tags origin HEAD
- name: Create GitHub release
if: ${{ !inputs.dry_run }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Tag prerelease versions (those containing a hyphen) as prereleases.
run: |
version="${{ steps.bump.outputs.version }}"
prerelease=""
case "$version" in
*-*) prerelease="--prerelease" ;;
esac
gh release create "$version" \
--title "$version" \
--generate-notes \
$prerelease