Github Action workflows
The template comes with over 10 GitHub Actions workflows that help you automate the process of checking, testing, releasing, and much more.
All those workflows are self-documented and contain all details directly inside the workflow file as comments. This approach makes it easier to understand what each workflow does and how to use it without having to go back and forth between the documentation and the workflow file.
This page lists all workflows and actions we use and adds more details on the approach we are using to make those workflows as simple as possible.
All files related to GitHub Actions are located in the .github/workflows
and .github/actions
folders.
Actions
You can think of actions as functions that are used by workflows to perform a specific task and allow you to reuse the same task in multiple workflows without duplicating the code which made them easier to maintain.
All actions are located in the .github/actions
folder, and here is the complete list:
⚙️ Node setup and PNM install
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/actions/setup-node-pnpm-install/action.yml# Composite actions docs: https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
# ✍️ Description:# This is a composite action, which means it can be used in other actions.# It is used in almost all workflows to set up the environment and install dependencies.# Updating the package manager or Node version here will be reflected in all workflows.
# 👀 Example usage:# - name : 📦 Setup Node + PNPM + install deps# uses: ./.github/actions/setup-node-pnpm-install
name: 'Setup Node + PNPM + Install Dependencies'description: 'Setup Node + PNPM + Install Dependencies'runs: using: 'composite' steps: - uses: pnpm/action-setup@v4 name: Install pnpm with: run_install: false - uses: actions/setup-node@v4 name: Install Node.js with: node-version: 20 cache: 'pnpm'
- name: 📦 Install Project Dependencies run: pnpm install --frozen-lockfile shell: bash
⚙️ Setup JDK && Generate APK
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/actions/setup-jdk-generate-apk/action.yml# Composite actions docs: https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
# ✍️ Description:# This is a composite action, which means it can be used in other actions.# This action is used to set up the JDK environment and generate an Android APK for testing.# This action accepts one input: `APP_ENV`, which is used to generate an APK for a specific environment (development, staging, production). We use staging by default.# Before generating the APK, we run a pre-build script to generate the necessary native folders based on the APP_ENV.# On success, the APK is generated at `./android/app/build/outputs/apk/release/app-release.apk`.
# 👀 Example usage:# - name : 📦 Set Up JDK + Generate Test APK# uses: ./.github/actions/setup-jdk-generate-apk# with:# APP_ENV: 'staging'
name: 'Setup JDK + GRADLE + Generate APK'description: 'Setup JDK + GRADLE + Generate APK'inputs: APP_ENV: description: 'APP_ENV (one of): development, staging, production' required: true default: 'staging'
runs: using: 'composite' steps: - name: Set Up JDK uses: actions/setup-java@v3 with: distribution: 'zulu' # See 'Supported distributions' for available options java-version: '11' - name: Setup Gradle uses: gradle/gradle-build-action@v2
- name: Generate Test APK run: | pnpm prebuild:${{ inputs.APP_ENV }} cd android chmod +x ./gradlew ./gradlew assembleRelease --no-daemon cd .. shell: bash env: EXPO_NO_DOTENV: '1' APP_ENV: ${{ inputs.APP_ENV }} CI: 'true'
⚙️ EAS Build
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/workflows/eas-build.yml# EAS Build docs: https://docs.expo.dev/eas-update/github-actions/
# ✍️ Description:# This workflow is used to trigger a build on EAS.# Can be triggered manually from the actions tab.
# This action accepts those inputs:# `environment`, which is used to generate a build for a specific environment (development, staging, QA, production). We use staging by default.# `android`, true by default, set to true if you don't want to trigger build for Android.# `ios`, false by default, set to true if you want to trigger build for IOS.
# Before triggering the build, we run a pre-build script to generate the necessary native folders based on the APP_ENV.# Based on the ANDROID and IOS inputs, we trigger the build for the corresponding platform with the corresponding flags.
# 🚨 GITHUB SECRETS REQUIRED:# - EXPO_TOKEN: Expo token to authenticate with EAS# - You can get it from https://expo.dev/settings/access-tokens
name: 'EAS Build (Android & IOS) (EAS)'
on: workflow_dispatch: inputs: environment: type: choice description: 'Environment' required: true default: 'staging' options: - development - staging - qa - production android: type: boolean description: 'Build for Android' required: true default: true ios: type: boolean description: 'Build for iOS' required: true default: true
jobs: Build: runs-on: ubuntu-latest steps: - name: Check for EXPO_TOKEN run: | if [ -z "${{ secrets.EXPO_TOKEN }}" ]; then echo "You must provide an EXPO_TOKEN secret linked to this project's Expo account in this repo's secrets. Learn more: https://docs.expo.dev/eas-update/github-actions" exit 1 fi
- name: 📦 Setup Expo and EAS uses: expo/expo-github-action@v8 with: eas-version: latest token: ${{ secrets.EXPO_TOKEN }}
- name: 📦 Checkout project repo uses: actions/checkout@v3 with: fetch-depth: 0
- name: 📦 Setup Node + PNPM + install deps uses: ./.github/actions/setup-node-pnpm-install
- name: ⚙️ Run Prebuild run: pnpm prebuild:${{ inputs.environment }}
- name: 📱 Run Android Build if: ${{ inputs.android == true }} run: pnpm build:${{ inputs.environment }}:android --non-interactive --no-wait --message "Build ${{ inputs.environment }}"
- name: 📱 Run IOS Build if: ${{ inputs.ios == true }} run: pnpm build:${{ inputs.environment }}:ios --non-interactive --no-wait --message "Build ${{ inputs.environment }}"
Workflows
⚙️ Linting and formatting
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/workflows/lint-ts.yml
# ✍️ Description:# This action is used to run eslint checks# Runs on any pull request, and also when pushing to main/master# Based on the event type:# - If it's a pull request, it will run eslint, then add the check to the PR as well as annotate the code with the errors and warnings.# - If it's a push to main/master, it will run the type checking and fail if there are any errors.
# 🚨 GITHUB SECRETS REQUIRED: NONE
name: Lint TS (eslint, prettier)
on: push: branches: [main, master] pull_request: types: [opened, synchronize]
jobs: lint: name: Lint TS (eslint, prettier) runs-on: ubuntu-latest permissions: contents: read pull-requests: write
steps: - name: 📦 Checkout project repo uses: actions/checkout@v3 with: fetch-depth: 0
- name: 📦 Setup Node + PNPM + install deps uses: ./.github/actions/setup-node-pnpm-install
- name: 🏃♂️ Run ESLint PR if: github.event_name == 'pull_request' uses: reviewdog/action-eslint@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} reporter: github-pr-review eslint_flags: '. --ext .js,.jsx,.ts,.tsx'
- name: 🏃♂️ Run ESLint PR if: github.event_name != 'pull_request' run: pnpm run lint
⚙️ Type checking
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/workflows/type-check.yml
# ✍️ Description:# This action is used to run the type-check on the project.# Runs on any pull request, and also when pushing to main/master# Based on the event type:# - If it's a pull request, it will run type checking, then add the check to the PR as well as annotate the code with the errors using reviewdog.# - If it's a push to main/master, it will run the type checking and fail if there are any errors.
# 🚨 GITHUB SECRETS REQUIRED: NONE
name: Type Check (tsc)
on: push: branches: [main, master] pull_request: types: [opened, synchronize]
jobs: type-check: name: Type Check (tsc) runs-on: ubuntu-latest permissions: contents: read pull-requests: write
steps: - name: 📦 Checkout project repo uses: actions/checkout@v3 with: fetch-depth: 0
- name: 📦 Setup Node + PNPM + install deps uses: ./.github/actions/setup-node-pnpm-install
- name: 📦 Install Reviewdog if: github.event_name == 'pull_request' uses: reviewdog/action-setup@v1
- name: 🏃♂️ Run TypeScript PR # Reviewdog tsc errorformat: %f:%l:%c - error TS%n: %m # We only need to add the reviewdog step if it's a pull request if: github.event_name == 'pull_request' run: | pnpm type-check | reviewdog -name="tsc" -efm="%f(%l,%c): error TS%n: %m" -reporter="github-pr-review" -filter-mode="nofilter" -fail-on-error -tee env: REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: 🏃♂️ Run TypeScript Commit # If it's not a Pull Request then we just need to run the type-check if: github.event_name != 'pull_request' run: pnpm type-check
⚙️ Expo Doctor
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/workflows/expo-doctor.yml
# ✍️ Description:# This workflow runs the expo doctor command to check if your project dependencies are aligned with the expo sdk version you are using.# Can be triggered manually from the Actions tab in your project.# Runs Also on pull requests and pushes to the main/master branch, but only if the `package.json` or `pnpm-lock.yaml` files have been changed.
# 🚨 GITHUB SECRETS REQUIRED: NONE
name: Expo Doctor (expo)
on: push: branches: - main - master paths: - 'package.json' - 'pnpm-lock.yaml' pull_request: paths: - 'package.json' - 'pnpm-lock.yaml'
jobs: doctor: name: Expo Doctor (expo) runs-on: ubuntu-latest
steps: - name: 📦 Checkout project repo uses: actions/checkout@v3 with: fetch-depth: 0
- name: 📦 Setup Node + PNPM + install deps uses: ./.github/actions/setup-node-pnpm-install
- name: 🚑 Run Doctor Checks run: rm -rf ios android && pnpm run doctor ## apprently the new update of expo will break if you already have ios and android folders in your project as they will show up a eas warning
⚙️ Compress Images
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/workflows/compress-images.yml
# ✍️ Description:# This workflow is used to compress images in the repo.# This workflow will trigger on a push to the "master" or "main" branch and only run when a new image is added or updated.# If it's the case, it will compress those images and create a pull request with the compressed images.
# 🚨 GITHUB SECRETS REQUIRED: None
name: Compress imageson: push: branches: - master - main paths: - '**.jpg' - '**.jpeg' - '**.png' - '**.webp' workflow_dispatch:
jobs: build: name: calibreapp/image-actions runs-on: ubuntu-latest steps: - name: Checkout Branch uses: actions/checkout@v3 with: fetch-depth: 0 - name: Compress Images id: calibre uses: calibreapp/image-actions@main with: githubToken: ${{ secrets.GITHUB_TOKEN }} compressOnly: true ignorePaths: 'node_modules/**,ios/**,android/**'
- name: Create Pull Request if: steps.calibre.outputs.markdown != '' uses: peter-evans/create-pull-request@v3 with: title: Auto Compress Images branch-suffix: timestamp commit-message: Compress Images body: ${{ steps.calibre.outputs.markdown }}
⚙️ Running Tests + Coverage Reports
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/workflows/test.yml
# ✍️ Description:# This action is used to run unit tests# Runs on any pull request, and also when pushing to main/master# Based on the event type:# - If it's a pull request, it will run the tests and post a comment with coverage details.# - If it's a push to main/master, it will run the tests and add the check to the commit.
# 🚨 GITHUB SECRETS REQUIRED: NONE
name: Tests (jest)
on: push: branches: [main, master] pull_request: types: [opened, synchronize]
jobs: test: name: Tests (jest) runs-on: ubuntu-latest permissions: contents: read pull-requests: write
steps: - name: 📦 Checkout project repo uses: actions/checkout@v3 with: fetch-depth: 0
- name: 📦 Setup Node + PNPM + install deps uses: ./.github/actions/setup-node-pnpm-install
- name: 🏃♂️ Run Tests run: pnpm run test:ci
- name: Jest Coverage Comment uses: MishaKav/jest-coverage-comment@main if: (success() || failure()) && github.event_name == 'pull_request' with: coverage-summary-path: ./coverage/coverage-summary.json summary-title: '💯 Test Coverage' badge-title: Coverage create-new-comment: false junitxml-title: 😎 Tests Results junitxml-path: ./coverage/jest-junit.xml coverage-title: 👀 Tests Details coverage-path: ./coverage/coverage.txt report-only-changed-files: true
⚙️ New App Version
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/workflows/lint-ts.yml# Starter releasing process: https://rootstrap.github.io/react-native-template/ci-cd/app-releasing-process/
# ✍️ Description:# This workflow is used to create a new version of the template and push a new tag to the repo.# As this workflow will push code to the repo, we set up GitHub Bot as a Git user.# This Workflow need to be triggered manually from the Actions tab in the repo.# 1. Choose your release type (patch, minor, major)# 2. The workflow will run the np-release script which runs the following steps:# - Bump the version in package.json based on the release type using np# - Run the prebuild of the app to align the package.json version with the native code# - Create a new tag with the new version# - Push the new tag to the repo#
# 🚨 GITHUB SECRETS REQUIRED:# - NEW_TEMPLATE_VERSION_PAT: A fine-grained Personal Access Token.# This token is used to commit, push and create a new release in the template repository.# You can generate one from here: https://github.com/settings/tokens?type=beta# Set the Repository access to "Only select repositories" and select the template repository.# Set the following Repo permissions:# - Contents: Read & write (to commit, push and create a new release)# - Metadata: Read-only (mandatory by GitHub)# - Actions: Read and write (to allow triggering other workflows, like docs deployment)# Make sure to add it to the repo secrets with the name NEW_TEMPLATE_VERSION_PAT:# - Go to Repository Settings > Secrets and variables > Actions > New repository secret# - Name: NEW_TEMPLATE_VERSION_PAT# - Value: The Personal Access Token you created
name: New Template Version
on: workflow_dispatch: inputs: release-type: type: choice description: 'Release type (one of): patch, minor, major' required: true default: 'patch' options: - patch - minor - major
jobs: release: name: Create New Version and push new tag runs-on: ubuntu-latest environment: name: template url: https://github.com/rootstrap/react-native-template/releases/tag/v${{ env.NEW_VERSION }} permissions: contents: write steps: - name: Check if Personal Access Token exists env: PAT: ${{ secrets.NEW_TEMPLATE_VERSION_PAT }} if: env.PAT == '' run: | echo "NEW_TEMPLATE_VERSION_PAT secret not found. Please create a fine-grained Personal Access Token following the instructions in the workflow file." exit 1 - name: 📦 Checkout project repo uses: actions/checkout@v3 with: fetch-depth: 0 token: ${{ secrets.NEW_TEMPLATE_VERSION_PAT }} - name: 📝 Git User Setup run: | git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" git config --global user.name "github-actions[bot]"
- name: 📦 Setup Node + PNPM + install deps uses: ./.github/actions/setup-node-pnpm-install
- name: 🏃♂️ Run Template release run: | pnpm app-release ${{ github.event.inputs.release-type }}
- name: 📝 Get new package version run: | echo "NEW_VERSION=$(awk -F'"' '/"version": ".+"/{ print $4; exit; }' package.json)" >> $GITHUB_ENV
- name: 🏃♂️Create A Github Release uses: ncipollo/release-action@v1 with: tag: v${{ env.NEW_VERSION }} generateReleaseNotes: true draft: false token: ${{ secrets.NEW_TEMPLATE_VERSION_PAT }}
⚙️ E2E Test for Android
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/workflows/e2e-android.yml# End-to-end testing: https://rootstrap.github.io/react-native-template/testing/end-to-end-testing/
# ✍️ Description:# This workflow is used to run end-to-end tests on Android using Maestro.# As a first step, it will generate a test APK using the Gradle build and then upload it as an artifact.# A new job will be started to run the tests using the test APK generated in the previous job.# To test the app, we set up an Android emulator using the `reactivecircus/android-emulator-runner` action. This runner requires macOS as the operating system for the runner.# This workflow will be triggered on pull requests (PRs) with the label "android-test-github" or can be manually triggered from the Actions tab.#
# 🚨 GITHUB SECRETS REQUIRED: None
name: E2E Tests Android (Maestro + Github Action)
on: workflow_dispatch: pull_request: branches: [main, master]
jobs: generate-test-apk: if: github.event_name != 'pull_request' || ( github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'android-test-github')) name: Generate Test APK (Gradle) runs-on: ubuntu-latest
steps: - name: 📦 Checkout project repo uses: actions/checkout@v3 with: fetch-depth: 0
- name: 📦 Setup Node + PNPM + install deps uses: ./.github/actions/setup-node-pnpm-install
- name: 📦 Set Up JDK + Generate Test APK uses: ./.github/actions/setup-jdk-generate-apk with: APP_ENV: staging
- name: Upload Test APK uses: actions/upload-artifact@v3 with: name: test-apk path: ./android/app/build/outputs/apk/release/app-release.apk
test-android: name: Run Android E2E Tests (Maestro + Github Action) needs: generate-test-apk runs-on: macOS-latest
steps: - name: 📦 Checkout project repo uses: actions/checkout@v3 with: fetch-depth: 0
- name: 📦 Install Maestro run: npm run install-maestro ## We use npm because we don't need to install deps again
- name: Download Test APK uses: actions/download-artifact@v3 with: name: test-apk path: ${{ github.workspace }}
- name: Gradle cache uses: gradle/gradle-build-action@v2
- name: AVD cache uses: actions/cache@v3 id: avd-cache with: path: | ~/.android/avd/* ~/.android/adb* key: avd-cache
- name: create AVD and generate snapshot for caching if: steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@v2 with: api-level: 29 force-avd-creation: false emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: false cores: 2 ram-size: 4096M profile: Nexus 6 script: echo "Generated AVD snapshot for caching."
- name: Run tests with Maestro uses: reactivecircus/android-emulator-runner@v2 with: api-level: 29 force-avd-creation: false emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: false cores: 2 ram-size: 4096M profile: Nexus 6 script: | adb install "${{ github.workspace }}/app-release.apk" $HOME/.maestro/bin/maestro test .maestro/ --env=APP_ID=com.obytes.staging --format junit
- name: Upload artifacts if: always() uses: actions/upload-artifact@v3 with: name: e2e-test-logs path: ~/.maestro/tests/**/*
- name: Store tests result uses: actions/upload-artifact@v3 with: name: e2e_android_report path: | report.xml
⚙️ E2E Test for Android using Maestro Cloud
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/workflows/e2e-android.yml# End-to-end testing: https://rootstrap.github.io/react-native-template/testing/end-to-end-testing/
# ✍️ Description:# This workflow is used to run end-to-end tests on Android using Maestro Cloud.# As a first step, it will generate a test APK using the Gradle build and then trigger Maestro Cloud to run the tests on the generated APK.# This workflow will be triggered on pull requests (PRs) with the label "android-test-maestro-cloud" or can be manually triggered from the Actions tab.
# 🚨 GITHUB SECRETS REQUIRED:# MAESTRO_CLOUD_API_KEY: API key for Maestro Cloud. You can get it from https://cloud.mobile.dev/ci-integration/github-actions#add-your-api-key-secret
name: E2E Tests Android (Maestro Cloud)
on: workflow_dispatch: pull_request: branches: [main, master]
jobs: generate-and-test-apk: if: github.event_name != 'pull_request' || ( github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'android-test-maestro-cloud')) name: Generate and Test Test APK (Maestro Cloud) runs-on: ubuntu-latest
steps: - name: 📦 Checkout project repo uses: actions/checkout@v3 with: fetch-depth: 0
- name: 📦 Setup Node + PNPM + install deps uses: ./.github/actions/setup-node-pnpm-install
- name: 📦 Set Up JDK + Generate Test APK uses: ./.github/actions/setup-jdk-generate-apk with: APP_ENV: staging
- name: Upload Test APK uses: actions/upload-artifact@v3 with: name: test-apk path: ./android/app/build/outputs/apk/release/app-release.apk
- name: 📱 Run E2E Tests with Maestro Cloud uses: mobile-dev-inc/action-maestro-cloud@v1.4.1 with: api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }} app-file: ./android/app/build/outputs/apk/release/app-release.apk env: | APP_ID=com.obytes.staging
⚙️ E2E Test for Android using EAS Build
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/workflows/e2e-android-eas-build.yml# End-to-end testing: https://rootstrap.github.io/react-native-template/testing/end-to-end-testing/
# ✍️ Description:# This workflow is used to run end-to-end tests for EAS build on Android.# It uses Maestro Cloud to run tests on Android emulator.# It downloads the APK from EAS build and triggers the tests on Maestro Cloud with the downloaded APK.
# 🚨 GITHUB SECRETS REQUIRED:# MAESTRO_CLOUD_API_KEY: API key for Maestro Cloud. You can get it from https://cloud.mobile.dev/ci-integration/github-actions#add-your-api-key-secret
name: E2E Tests EAS Build Android (Maestro + Github Action)
on: workflow_dispatch: inputs: apk-url: type: string description: 'EAS APK URL' required: true default: ''
jobs: download-eas-apk: if: github.event_name != 'pull_request' && github.event.inputs.apk-url != '' name: Download Test APK From EAS Url (wget) runs-on: ubuntu-latest
steps: - name: 📦 Download EAS APK run: wget ${{ github.event.inputs.apk-url }} -O ./app-release.apk
- name: Upload Test APK uses: actions/upload-artifact@v3 with: name: test-apk path: ./app-release.apk
test-android: name: E2E Tests EAS Build Android (Maestro + Github Action) needs: download-eas-apk runs-on: macOS-latest
steps: - name: 📦 Checkout project repo uses: actions/checkout@v3 with: fetch-depth: 0
- name: 📦 Install Maestro run: npm run install-maestro ## We use npm because we don't need to install deps again
- name: Download Test APK uses: actions/download-artifact@v3 with: name: test-apk path: ${{ github.workspace }}
- name: Gradle cache uses: gradle/gradle-build-action@v2
- name: AVD cache uses: actions/cache@v3 id: avd-cache with: path: | ~/.android/avd/* ~/.android/adb* key: avd-cache
- name: create AVD and generate snapshot for caching if: steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@v2 with: api-level: 29 force-avd-creation: false emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: false cores: 2 ram-size: 4096M profile: Nexus 6 script: echo "Generated AVD snapshot for caching."
- name: Run tests with Maestro uses: reactivecircus/android-emulator-runner@v2 with: api-level: 29 force-avd-creation: false emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: false cores: 2 ram-size: 4096M profile: Nexus 6 script: | adb install "${{ github.workspace }}/app-release.apk" $HOME/.maestro/bin/maestro test .maestro/ --env=APP_ID=com.obytes.staging --format junit
- name: Upload artifacts if: always() uses: actions/upload-artifact@v3 with: name: e2e-test-logs path: ~/.maestro/tests/**/*
- name: Store tests result uses: actions/upload-artifact@v3 with: name: e2e_android_report path: | report.xml
⚙️ Sync with template
# 🔗 Links:# Source file: https://github.com/rootstrap/react-native-template/blob/master/.github/project-workflows/sync-with-template.yml
# ✍️ Description:# This workflow is used to keep the project up to date with the latest version of the template.
# 🚨 GITHUB SECRETS REQUIRED:# - UPDATE_FROM_TEMPLATE_PAT: A fine-grained Personal Access Token.# This token is used to commit and push to the project repository.# You can generate one from here: https://github.com/settings/tokens?type=beta# Set the Repository access to "Only select repositories" and select the project repository.# Set the following Repo permissions:# - Contents: Read & write (to commit and push the update branch to the project repository)# - Metadata: Read-only (mandatory by GitHub)# - Workflows: Read and write (to create, update and delete workflows in the project repository)# Make sure to add it to the repo secrets with the name UPDATE_FROM_TEMPLATE_PAT:# - Go to Repository Settings > Secrets and variables > Actions > New repository secret# - Name: UPDATE_FROM_TEMPLATE_PAT# - Value: The Personal Access Token you created
# ℹ️ Environment variables:# - TEMPLATE_REPOSITORY: Repository to sync with# - DIFF_EXCLUDED_ROUTES: List of files or directories to exclude from the diff.# Any changes in these files or directories will be ignored# and won't be incorporated to the Pull Request.
name: 🔄 Sync with template
on: schedule: - cron: '0 12 * * 1-5' # At 12:00 UTC on every day-of-week from Monday through Friday workflow_dispatch: inputs: template-version: type: string description: 'Template release version to sync with (e.g. v1.0.0). Leave empty to sync with the latest release.' required: false default: ''
env: TEMPLATE_REPOSITORY: rootstrap/react-native-template DIFF_EXCLUDED_ROUTES: | cli docs ios android .github/workflows/deploy-docs.yml .github/workflows/new-template-version.yml .github/workflows/upstream-to-pr.yml .github/workflows/sync-with-upstream.yml README-project.md
jobs: sync: runs-on: ubuntu-latest permissions: actions: write contents: read pull-requests: write
steps: - name: Check if Personal Access Token exists env: PAT: ${{ secrets.UPDATE_FROM_TEMPLATE_PAT }} if: env.PAT == '' run: | echo "UPDATE_FROM_TEMPLATE_PAT secret not found. Please create a fine-grained Personal Access Token following the instructions in the workflow file." exit 1 - name: Checkout project repository uses: actions/checkout@v3 with: fetch-depth: 0 path: project token: ${{ secrets.UPDATE_FROM_TEMPLATE_PAT }} - name: Get template version used in project from package.json run: | echo "PROJECT_TEMPLATE_VERSION=v$(jq -r 'if has("rsMetadata") then .rsMetadata.templateVersion else .osMetadata.initVersion end' project/package.json | sed 's/^.*@//')" >> $GITHUB_ENV - name: Set template version to sync with run: | if [ -z "${{ inputs.template-version }}" ]; then TEMPLATE_UPDATE_VERSION=$(curl -s https://api.github.com/repos/${{ env.TEMPLATE_REPOSITORY }}/releases/latest | jq '.tag_name' | sed 's/\"//g') else TEMPLATE_UPDATE_VERSION=${{ inputs.template-version }} fi echo "TEMPLATE_UPDATE_VERSION=$TEMPLATE_UPDATE_VERSION" >> $GITHUB_ENV - name: Check if the project is up to date run: | if [[ $TEMPLATE_UPDATE_VERSION == $PROJECT_TEMPLATE_VERSION ]]; then echo "Template is up to date" cd project gh run cancel ${{ github.run_id }} gh run watch ${{ github.run_id }} fi env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Check if branch already exists run: | cd project git fetch origin BRANCH_NAME=update-template-${{ env.TEMPLATE_UPDATE_VERSION }} echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV git branch -r | grep -q "origin/$BRANCH_NAME" && echo "BRANCH_EXISTS=true" >> $GITHUB_ENV || echo "BRANCH_EXISTS=false" >> $GITHUB_ENV - name: Check if PR already exists run: | cd project prs=$(gh pr list \ --head "$BRANCH_NAME" \ --json title \ --jq 'length') if ((prs > 0)); then echo "PR_EXISTS=true" >> $GITHUB_ENV else echo "PR_EXISTS=false" >> $GITHUB_ENV fi env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Install dependencies if: ${{ env.BRANCH_EXISTS == 'false' }} run: | sudo apt install wiggle - name: Checkout update release of template if: ${{ env.BRANCH_EXISTS == 'false' }} uses: actions/checkout@v3 with: repository: ${{ env.TEMPLATE_REPOSITORY }} ref: ${{ env.TEMPLATE_UPDATE_VERSION }} fetch-depth: 0 path: react-native-template - name: Get diff between latest release and used release if: ${{ env.BRANCH_EXISTS == 'false' }} run: | EXCLUDED_ROUTES="" for route in $DIFF_EXCLUDED_ROUTES; do EXCLUDED_ROUTES="$EXCLUDED_ROUTES ':(exclude)$route'" done cd react-native-template git diff ${{ env.PROJECT_TEMPLATE_VERSION }} -- . $(echo $EXCLUDED_ROUTES | xargs) > ../update.patch - name: Update template version in package.json if: ${{ env.BRANCH_EXISTS == 'false' }} run: | cd project jq 'del(.osMetadata)' package.json > tmp.json && mv tmp.json package.json PLAIN_VERSION=${TEMPLATE_UPDATE_VERSION#v} jq --arg version $PLAIN_VERSION '.rsMetadata.templateVersion = $version' package.json > tmp.json && mv tmp.json package.json - name: Apply diff to project repository if: ${{ env.BRANCH_EXISTS == 'false' }} run: | cd project git apply --reject ../update.patch continue-on-error: true - name: Solve conflicts with wiggle if: ${{ env.BRANCH_EXISTS == 'false' }} run: | cd project find . -iname '*.rej' -exec sh -c 'printf "%s\n" "${0%.*}"' {} ';' | xargs -I _ wiggle --replace --merge _ _.rej continue-on-error: true - name: Remove wiggle's backup and .rej files if: ${{ env.BRANCH_EXISTS == 'false' }} run: | cd project find . -not -path './.git/*' -type f -name '*.porig' -delete find . -not -path './.git/*' -type f -name '*.rej' -delete - name: Commit and push changes to the update branch if: ${{ env.BRANCH_EXISTS == 'false' }} run: | cd project git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" git config --global user.name "github-actions[bot]" git checkout -b ${{ env.BRANCH_NAME }} git add . git commit -m "chore: update template to ${{ env.TEMPLATE_UPDATE_VERSION }}" git push origin ${{ env.BRANCH_NAME }} echo "BRANCH_EXISTS=true" >> $GITHUB_ENV - name: 🎉 Create PR with changes if: ${{ env.BRANCH_EXISTS == 'true' && env.PR_EXISTS == 'false' }} run: | cd project gh pr create --title "chore: update template to ${{ env.TEMPLATE_UPDATE_VERSION }}" --body "Integrating latest changes from [rootstrap/react-native-template@${{ env.TEMPLATE_UPDATE_VERSION }}](https://github.com/rootstrap/react-native-template/releases/tag/${{ env.TEMPLATE_UPDATE_VERSION }})" --head ${{ env.BRANCH_NAME }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}