Skip to content

Instantly share code, notes, and snippets.

@Silthus
Last active February 9, 2023 19:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Silthus/165cd25e75dd10aacf039caf40664420 to your computer and use it in GitHub Desktop.
Save Silthus/165cd25e75dd10aacf039caf40664420 to your computer and use it in GitHub Desktop.
Solito Expo EAS Deployment
{
"branches": [
{
"name": "main",
"channel": "development",
"prerelease": "dev"
},
{
"name": "preview",
"channel": "preview",
"prerelease": "preview"
},
{
"name": "production"
}
],
"plugins": [
"@semantic-release/commit-analyzer",
["semantic-release-expo", {
"versions": {
"version": "${recommended}",
"android": "${increment}",
"ios": "${next.raw}"
},
"manifests": [
"apps/expo/app.json"
]
}],
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
["@semantic-release/git", {
"assets": [
"CHANGELOG.md",
"package.json",
"apps/expo/package.json",
"apps/next/package.json",
"yarn.lock",
"apps/expo/app.json"
]
}],
["@semantic-release/exec", {
"publishCmd": "cd apps/expo && eas build --non-interactive --profile ${branch.name} --platform=all --no-wait"
}],
"@semantic-release/github"
]
}

Define the NODE_VERSION secret variable and EXPO_TOKEN variable in your Github workflow secrets. Get the EXPO_TOKEN from your expo.dev account.

IMPORTANT
A main, preview and production branch must exist for the workflow to work.


Add the following dependencies to your root package.json

{
  "name": "solito-expo-router-tailwind",
  "private": true,
  "workspaces": [
    "apps/*",
    "packages/*"
  ],
  "devDependencies": {
    "@types/react": "^18.0.17",
    "@types/react-native": "^0.69.5",
    "eslint": "^8.21.0",
    "prettier": "^2.8.4",
    "prettier-plugin-tailwindcss": "^0.2.2",
    "turbo": "^1.4.2",
    "typescript": "^4.7.4",
    "@semantic-release/changelog": "^6.0.1",
    "@semantic-release/commit-analyzer": "^9.0.2",
    "@semantic-release/exec": "^6.0.3",
    "@semantic-release/git": "^10.0.1",
    "@semantic-release/github": "^8.0.6",
    "@semantic-release/release-notes-generator": "^10.0.3",
    "semantic-release": "^19.0.5",
    "semantic-release-expo": "^2.2.3"
  },
  "scripts": {
    "native": "yarn --cwd apps/expo start",
    "web": "yarn --cwd apps/next dev",
    "compile": "tsc --noEmit -p . --pretty",
    "format": "prettier --ignore-path .gitignore --write \"{apps,packages}/**/*.{js,jsx,json,md,ts,tsx}\"",
    "lint": "eslint --fix --ext .js,.ts,.tsx && yarn format",
    "lint:check": "eslint --ext .js,.ts,.tsx"
  },
  "resolutions": {
    "metro": "0.72.3"
  },
  "nohoist": [
    "**/expo-router",
    "**/expo-router/**"
  ]
}

And the apps/expo/package.json

{
  "dependencies": {
    "app": "*",
    "dotenv": "^16.0.3",
    "expo": "^47.0.0",
    "expo-build-properties": "~0.4.1",
    "expo-constants": "~14.0.2",
    "expo-dev-client": "~2.0.1",
    "expo-notifications": "~0.17.0",
    "expo-router": "0.0.31",
    "expo-splash-screen": "~0.17.5",
    "expo-status-bar": "~1.4.2",
    "expo-updates": "~0.15.6",
    "react": "18.1.0",
    "react-dom": "18.1.0",
    "react-native": "0.70.5",
    "react-native-gesture-handler": "~2.8.0",
    "react-native-reanimated": "~2.12.0",
    "react-native-safe-area-context": "4.4.1",
    "react-native-screens": "~3.18.0",
    "react-native-svg": "13.4.0",
    "react-native-web": "~0.18.7"
  },
  "devDependencies": {
    "@babel/core": "^7.19.3",
    "@expo/config-plugins": "^5.0.4",
    "@types/react": "~18.0.24",
    "@types/react-native": "~0.70.6",
    "tailwindcss": "^3.0.24",
    "typescript": "^4.6.3"
  },
  "scripts": {
    "start": "expo start --dev-client",
    "android": "expo run:android",
    "ios": "expo run:ios"
  },
  "version": "1.0.0",
  "private": true,
  "name": "expo-app"
}
import "dotenv/config"
import { ConfigContext } from "@expo/config"
let name = 'Your App'
let packageName = 'your.app.domain'
switch (process.env.APP_VARIANT) {
case 'production':
break
case 'preview':
name += ' (Preview)'
packageName += '.preview'
break
default:
case 'development':
name += ' (DEV)'
packageName += ".dev"
break
}
export default ({config}: ConfigContext) => ({
...config,
name: name,
scheme: packageName,
ios: {
...config.ios,
bundleIdentifier: packageName
},
android: {
...config.android,
package: packageName
},
extra: {
eas: {
projectId: "<YOUR_EAS_PROJECT_ID>"
},
}
});
{
"expo": {
"name": "your-app",
"slug": "your-slug",
"version": "1.0.0-dev.2",
"runtimeVersion": "1.0.0",
"jsEngine": "hermes",
"scheme": "your-scheme",
"platforms": [
"ios",
"android"
],
"plugins": [
[
"expo-build-properties",
{
"ios": {
"useFrameworks": "static"
}
}
]
],
"ios": {
"buildNumber": "1.0.0"
},
"android": {
"versionCode": 2
},
"extra": {
"eas": {
"projectId": "<YOUR_PROJECT_EXPO_ID>"
}
},
"updates": {
"url": "https://u.expo.dev/<YOUR_EXPO_UPDATE_ID>"
}
}
}
name: πŸš€ Build, Test, Update & Release
on:
push:
workflow_dispatch:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
env:
node_version: ${{ secrets.NODE_VERSION }}
jobs:
validate:
name: βœ… Validate
runs-on: ubuntu-latest
outputs:
branch: ${{ env.BRANCH_NAME }}
steps:
- name: 🌿 Get branch name
id: branch-name
uses: tj-actions/branch-names@v6
- name: πŸ’Ύ Set branch name to output
id: determine-branch
run: echo "BRANCH_NAME=${{ steps.branch-name.outputs.current_branch }}" >> $GITHUB_ENV
setup:
name: πŸ— Setup
needs: validate
uses: ./.github/workflows/yarn-install.yaml
secrets:
node_version: ${{ secrets.NODE_VERSION }}
lint:
name: πŸ–Ό Lint
runs-on: ubuntu-latest
needs: setup
steps:
- name: πŸ— Setup Repository
uses: actions/checkout@v3
- name: πŸ— Setup Node
uses: actions/setup-node@v3
with:
node-version: ${{ env.node_version }}
- name: πŸ“¦ Restore node_modules from cache
uses: actions/cache@v3
env:
cache_name: node-modules-yarn
cache_fingerprint: ${{ env.node_version }}-${{ hashFiles('yarn.lock') }}
with:
path: node_modules
key: ${{ runner.os }}-${{ env.cache_name }}-${{ env.cache_fingerprint }}
- name: πŸ–Ό Lint
run: yarn lint:check
build:
name: βš™ Build
needs: setup
runs-on: ubuntu-latest
steps:
- name: πŸ— Setup Repository
uses: actions/checkout@v3
- name: πŸ— Setup Node
uses: actions/setup-node@v3
with:
node-version: ${{ env.node_version }}
- name: πŸ“¦ Restore node_modules from cache
uses: actions/cache@v3
env:
cache_name: node-modules-yarn
cache_fingerprint: ${{ env.node_version }}-${{ hashFiles('yarn.lock') }}
with:
path: node_modules
key: ${{ runner.os }}-${{ env.cache_name }}-${{ env.cache_fingerprint }}
- name: πŸŽ›οΈ Compile
run: yarn compile
# test:
# name: πŸ§ͺ Test
# needs: setup
# runs-on: ubuntu-latest
# steps:
# - name: πŸ— Setup Repository
# uses: actions/checkout@v3
#
# - name: πŸ— Setup Node
# uses: actions/setup-node@v3
# with:
# node-version: ${{ env.node_version }}
#
# - name: πŸ“¦ Restore node_modules from cache
# uses: actions/cache@v3
# env:
# cache_name: node-modules-yarn
# cache_fingerprint: ${{ env.node_version }}-${{ hashFiles('yarn.lock') }}
# with:
# path: node_modules
# key: ${{ runner.os }}-${{ env.cache_name }}-${{ env.cache_fingerprint }}
#
# - name: πŸ§ͺ Test
# run: yarn test
update:
name: β™» EAS Update
runs-on: ubuntu-latest
if: ${{ github.actor != 'dependabot[bot]' }}
needs:
- lint
- build
# - test
steps:
- name: πŸ— Setup Repository
uses: actions/checkout@v3
- name: πŸ— Setup Node
uses: actions/setup-node@v3
with:
node-version: ${{ env.node_version }}
- name: πŸ— Setup Expo and EAS
uses: expo/expo-github-action@v7
with:
expo-version: latest
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: πŸ“¦ Restore node_modules from cache
uses: actions/cache@v3
env:
cache_name: node-modules-yarn
cache_fingerprint: ${{ env.node_version }}-${{ hashFiles('yarn.lock') }}
with:
path: node_modules
key: ${{ runner.os }}-${{ env.cache_name }}-${{ env.cache_fingerprint }}
- name: 🌿 Get branch name
id: branch-name
uses: tj-actions/branch-names@v6
- name: β™» Publish update
run: cd apps/expo && APP_VARIANT=${{ steps.branch-name.outputs.current_branch }} eas update --auto --non-interactive
release:
name: πŸš€ Release
runs-on: ubuntu-latest
permissions: write-all
needs:
- lint
- build
# - test
if: ${{ contains(fromJson('["main", "preview", "production"]'), needs.validate.outputs.branch) }}
steps:
- name: πŸ— Setup Repository
uses: actions/checkout@v3
- name: πŸ— Setup Node
uses: actions/setup-node@v3
with:
node-version: ${{ env.node_version }}
- name: πŸ— Setup Expo and EAS
uses: expo/expo-github-action@v7
with:
expo-version: latest
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: πŸ“¦ Restore node_modules from cache
uses: actions/cache@v3
env:
cache_name: node-modules-yarn
cache_fingerprint: ${{ env.node_version }}-${{ hashFiles('yarn.lock') }}
with:
path: node_modules
key: ${{ runner.os }}-${{ env.cache_name }}-${{ env.cache_fingerprint }}
- name: πŸš€ Create Release
run: yarn semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
{
"cli": {
"version": ">=3.5.2"
},
"build": {
"main": {
"developmentClient": true,
"distribution": "internal",
"channel": "development",
"env": {
"APP_VARIANT": "development"
},
"ios": {
"resourceClass": "m1-medium"
}
},
"preview": {
"distribution": "internal",
"env": {
"APP_VARIANT": "preview"
},
"ios": {
"resourceClass": "m1-medium"
}
},
"production": {
"env": {
"APP_VARIANT": "production"
},
"ios": {
"resourceClass": "m1-medium"
}
}
},
"submit": {
"production": {}
}
}
name: πŸ“¦ Yarn Cache
on:
workflow_call:
secrets:
node_version:
required: true
jobs:
setup:
name: πŸ“¦ Yarn install & cache
runs-on: ubuntu-latest
concurrency:
group: yarn-install-${{ github.sha }}
timeout-minutes: 10
steps:
- name: πŸ— Setup Repository
uses: actions/checkout@v3
- uses: actions/setup-node@v3
name: πŸ— Setup Node
with:
node-version: ${{ secrets.node_version }}
# node_module cache helps to avoid 1 minute copying from yarn cache on every job run
- name: πŸ“¦ Restore node_modules from cache
id: node-modules-cache
uses: actions/cache@v3
env:
cache-name: node-modules-yarn
cache-key: ${{ secrets.node_version }}-${{ hashFiles('yarn.lock') }}
with:
path: node_modules
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.cache-key }}
restore-keys: ${{ runner.os }}-${{ env.cache-name }}-
- name: πŸ“¦ Yarn install
if: steps.node-modules-cache.outputs.cache-hit != 'true'
run: yarn install --prefer-offline --frozen-lockfile
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment