Automating CodePush Releases with DeployPulse Using GitHub Actions
Managing over-the-air (OTA) updates for React Native apps can be time-consuming, but DeployPulse and GitHub Actions make it seamless. In this guide, we'll walk through a GitHub Action workflow that automates the release process of a CodePush update to DeployPulse.
This guide uses dpctl, the DeployPulse CLI. code-push-standalone is fully compatible - substitute dpctl with code-push-standalone in all commands below.
Recommended: Using the setup-dpctl Action
The easiest way to integrate DeployPulse into your workflow is with the official setup-dpctl GitHub Action. It installs dpctl in a single step — no cloning or building required.
- uses: deploypulseio/setup-dpctl@v1
with:
node-version: '22' # pin Node.js version (optional, default: "22")
version: 'v1.0.0' # pin dpctl version (recommended for production)
If you are already running actions/setup-node earlier in your workflow, pass the same node-version to setup-dpctl to avoid Node.js being installed a second time.
A complete workflow using the action:
name: Deploy CodePush Update via DeployPulse
on:
push:
branches:
- main
- dev
paths:
- 'app/**'
jobs:
release:
environment: ${{github.ref == 'refs/heads/main' && 'production' || 'dev'}}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install dpctl
uses: deploypulseio/setup-dpctl@v1
- name: Authenticate with DeployPulse
run: dpctl login --key ${{ secrets.DEPLOYPULSE_ACCESS_TOKEN }}
- name: Read Current Version
working-directory: ./app
run: |
TARGET_VERSION=$(node -p "require('./package.json').version")
echo "TARGET_VERSION=$TARGET_VERSION" >> $GITHUB_ENV
- name: Install Dependencies
working-directory: ./app
run: npm install
- name: Release Update via dpctl
working-directory: ./app
env:
DEPLOYMENT: ${{ vars.DEPLOYMENT }}
APP_NAME: ${{ vars.APP_NAME }}
run: |
dpctl release-react \
"$APP_NAME" ios \
-d "$DEPLOYMENT" \
--mandatory \
--targetBinaryVersion "$TARGET_VERSION" \
--description "CodePush Release for Version $TARGET_VERSION"
For production environments, pin dpctl to a specific version via the version input to avoid unexpected behavior from new releases.
To release in a disabled state (e.g. to stage a release before enabling it in the dashboard), add --disabled true to the release command.
What This Workflow Does
- Runs on push to
mainordevbranches when changes occur inside theapp/directory. - Installs
dpctlvia thesetup-dpctlaction — no manual clone or build needed. - Authenticates with DeployPulse using a secret API key stored in GitHub Secrets.
- Reads the current app version from
package.jsonand passes it astargetBinaryVersion. - Deploys a CodePush release targeting either the production or development environment.
Step-by-Step Breakdown
Step 1 — Trigger the Workflow on Code Changes
on:
push:
branches:
- main
- dev
paths:
- 'app/**'
Only runs when changes are pushed to main or dev inside the app/ directory. Update paths if your app code lives elsewhere.
Step 2 — Set the Deployment Environment
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'dev' }}
Dynamically sets the deployment environment — production on main, dev otherwise.
Step 3 — Checkout the Repository
- name: Checkout repository
uses: actions/checkout@v6
Step 4 — Install dpctl
- name: Install dpctl
uses: deploypulseio/setup-dpctl@v1
Installs Node.js and dpctl in a single step.
Step 5 — Authenticate with DeployPulse
- name: Authenticate with DeployPulse
run: dpctl login --key ${{ secrets.DEPLOYPULSE_ACCESS_TOKEN }}
DEPLOYPULSE_ACCESS_TOKEN should be stored as a GitHub Secret.
Step 6 — Read the Current App Version
- name: Read Current Version
working-directory: ./app
run: |
TARGET_VERSION=$(node -p "require('./package.json').version")
echo "TARGET_VERSION=$TARGET_VERSION" >> $GITHUB_ENV
Reads the version from package.json and exposes it as TARGET_VERSION for subsequent steps.
Step 7 — Install App Dependencies
- name: Install Dependencies
working-directory: ./app
run: npm install
Step 8 — Release the Update
- name: Release Update via dpctl
working-directory: ./app
env:
DEPLOYMENT: ${{ vars.DEPLOYMENT }}
APP_NAME: ${{ vars.APP_NAME }}
run: |
dpctl release-react \
"$APP_NAME" ios \
-d "$DEPLOYMENT" \
--mandatory \
--targetBinaryVersion "$TARGET_VERSION" \
--description "CodePush Release for Version $TARGET_VERSION"
APP_NAME and DEPLOYMENT are GitHub Environment Variables set per environment (dev/production).
Why This GitHub Action is Useful
- Automates OTA updates to DeployPulse with zero manual effort.
- Ensures updates are version-controlled via
package.json. - Uses secure authentication with GitHub Secrets.
- Handles multiple environments (
devandproduction) dynamically. - Only triggers when necessary (
app/directory changes).
This GitHub Action streamlines CodePush updates by integrating directly with DeployPulse. For more details, see the rest of the DeployPulse documentation.
To sign your releases with a private key so devices can verify bundle integrity before applying an update, see the Code Signing guide — it includes a GitHub Actions snippet.
Manual Installation (Alternative)
If you prefer not to use the setup-dpctl action, you can clone and build the CLI directly in your workflow:
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 23
- name: Clone dpctl CLI
run: |
git clone https://github.com/deploypulseio/dpctl dpctl
cd dpctl
npm install
npm run build
npm install -g
- name: Verify dpctl CLI
run: dpctl --version
These three steps replace the single setup-dpctl step above. The rest of the workflow (authenticate, read version, install deps, release) remains identical.
Full workflow using manual installation:
name: Deploy CodePush Update via DeployPulse
on:
push:
branches:
- main
- dev
paths:
- 'app/**'
jobs:
release:
environment: ${{github.ref == 'refs/heads/main' && 'production' || 'dev'}}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 23
- name: Clone dpctl CLI
run: |
git clone https://github.com/deploypulseio/dpctl dpctl
cd dpctl
npm install
npm run build
npm install -g
- name: Verify dpctl CLI
run: dpctl --version
- name: Authenticate with DeployPulse
run: |
dpctl login --key ${{ secrets.DEPLOYPULSE_ACCESS_TOKEN }}
- name: Read Current Version
working-directory: ./app
run: |
TARGET_VERSION=$(node -p "require('./package.json').version")
echo "TARGET_VERSION=$TARGET_VERSION" >> $GITHUB_ENV
echo "Deploying CodePush for version: $TARGET_VERSION"
- name: Install Dependencies
working-directory: ./app
run: npm install
- name: Release Update via dpctl
working-directory: ./app
env:
DEPLOYMENT: ${{ vars.DEPLOYMENT }}
APP_NAME: ${{ vars.APP_NAME }}
run: |
dpctl release-react \
"$APP_NAME" ios \
-d "$DEPLOYMENT" \
--mandatory \
--targetBinaryVersion "$TARGET_VERSION" \
--description "CodePush Release for Version $TARGET_VERSION"
