メインコンテンツまでスキップ

CodePush updates with Bitrise CI

You can release your CodePush updates via a Bitrise CI Workflow. The process requires:

  • Setting up CodePush credentials: create Secrets and Environment Variables that hold the deployment ID and the deployment key from Bitrise CodePush.
  • Creating a Workflow that creates the update packages for both iOS and Android, and updates both to the Bitrise CodePush Server.

Configuring CodePush credentials on BitriseClick to copy link​

  1. Get your credentials: you need the Release Management app IDs and the CodePush deployment IDs and deployment keys.

  2. Create Environment Variables for the deployment IDs and the connected app IDs:

    • IOS_PROD_DEPLOYMENT_ID: The deployment ID for the iOS app.
    • ANDROID_PROD_DEPLOYMENT_ID: The deployment ID for the Android app.
    • IOS_CONNECTED_APP_ID: The app ID for the iOS app.
    • ANDROID_CONNECTED_APP_ID: The app ID for the Android app.
  3. Create Secrets for the deployment key and the API token:

    • IOS_PROD_DEPLOYMENT_KEY: The deployment key of the iOS deployment from Bitrise CodePush.
    • ANDROID_PROD_DEPLOYMENT_KEY: The deployment key of the Android deployment from Bitrise CodePush.
    • BITRISE_API_TOKEN: Your personal access token or workspace API token.

Creating a Workflow for CodePush updatesClick to copy link​

This section shows you how to create a CI Workflow that will:

  • Create an update package for iOS.
  • Upload the iOS update package to Bitrise CodePush Server.
  • Create an update package for Android.
  • Upload the Android update package to Bitrise CodePush Server.
  1. Create a Workflow and after the git-clone Step, add an npm Step with the install command:

    ---
    format_version: '13'
    default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
    project_type: ios
    workflows:
    codepush_update_to_server:
    description: The workflow will generate and push your update to CodePush Server.
    steps:
    - git-clone@8: {}
    - npm@1:
    inputs:
    - command: install
  2. Add a script Step that extracts the app version using a JSON parser and set version in an Environment Variable using envman:

    - script@1:
    title: Extract App Version
    inputs:
    - content: |-
    #!/bin/bash
    set -e

    # Extract version from app.json using jq (JSON parser)
    VERSION=$(jq -r '.version' package.json)

    # Verify version extraction
    if [ -z "$VERSION" ]; then
    echo "Error: Could not extract version from package.json"
    exit 1
    fi

    echo "Extracted version from package.json: $VERSION"

    # Set the environment variable using envman
    envman add --key APP_VERSION --value "$VERSION"

    echo "Successfully set APP_VERSION=$VERSION"
  3. Add another script Step that clones the release-management-recipes repository from GitHub. This contains the upload script we'll use later.

    - script@1:
    title: Get Release Management Recipes
    inputs:
    - content: >-
    #!/usr/bin/env bash
    # fail if any commands fails
    set -e
    # make pipelines' return status equal the last command to exit with a
    non-zero status, or zero if all commands exit successfully
    set -o pipefail
    # debug log
    set -x

    # write your script here
    git clone https://github.com/bitrise-io/release-management-recipes
  4. Generate your iOS update bundle and create a zip archive from it:

    - script@1:
    title: Generate iOS Update Bundle
    inputs:
    - content: >-
    #!/usr/bin/env bash
    # fail if any commands fails
    set -e
    # make pipelines' return status equal the last command to exit with a
    non-zero status, or zero if all commands exit successfully
    set -o pipefail
    # debug log
    set -x

    npx react-native bundle \
    --platform ios \
    --dev false \
    --entry-file index.js \
    --bundle-output ./build/main.jsbundle \
    --assets-dest ./build

    # Create zip archive
    zip -r update.zip ./build
  5. Upload the iOS update bundle to the CodePush Server with upload_code_push_package.sh:

    - script@1:
    title: Upload iOS Update Bundle to Codepush Server
    inputs:
    - content: >
    #!/usr/bin/env bash
    # fail if any commands fails
    set -e
    # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all
    commands exit successfully
    set -o pipefail
    # debug log
    set -x

    cd release-management-recipes

    UPLOAD_RESPONSE=$(PACKAGE_PATH=../update.zip \
    AUTHORIZATION_TOKEN=$BITRISE_API_TOKEN \
    CONNECTED_APP_ID=$IOS_CONNECTED_APP_ID \
    DEPLOYMENT_ID=$IOS_PROD_DEPLOYMENT_ID \
    APP_VERSION=$APP_VERSION /bin/bash ./api/upload_code_push_package.sh 2>&1)
    EXIT_CODE=$?

    if [ $EXIT_CODE -ne 0 ]; then
    \ echo \"❌ upload_code_push_package.sh failed with exit code
    $EXIT_CODE\"
    \ echo \"$UPLOAD_RESPONSE\"
    \ exit $EXIT_CODE
    fi

    # Take only the last line of the response (final/latest status JSON
    object) FINAL_RESPONSE=$(echo "$UPLOAD_RESPONSE" | tail -n1)

    # Check explicitly for ERR_INTERNAL or other internal error indicators
    if echo \"$UPLOAD_RESPONSE\" | grep -q \"ERR_INTERNAL\"; then
    \ ERROR_MESSAGE=$(echo \"$FINAL_RESPONSE\" | jq -r '.message' ||
    echo \"Unknown error\")
    \ echo \"❌ Server returned internal error: $ERROR_MESSAGE\"
    \ exit 1
    fi


    # Now safely parse 'status' and 'status_reason' from the final
    response line PACKAGE_STATUS=$(echo "$FINAL_RESPONSE" | jq -r
    '.status' || echo "null") STATUS_REASON=$(echo "$FINAL_RESPONSE" | jq
    -r '.status_reason' || echo "")

    if [ "$PACKAGE_STATUS" = "processed_valid" ]; then echo "✅ Package
    uploaded and processed successfully." rm -rf ../build.zip rm -rf
    ../build else echo "⚠️ Package upload unexpected status:
    $PACKAGE_STATUS - Reason: $STATUS_REASON" exit 1 fi cd ..
  6. Generate the Android update bundle:

    - script@1:
    title: Generate Android Update Bundle
    inputs:
    - content: |
    #!/usr/bin/env bash
    # fail if any commands fails
    set -e
    # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully
    set -o pipefail
    # debug log
    set -x

    npx react-native bundle \
    --platform android \
    --dev false \
    --entry-file index.js \
    --bundle-output ./build/index.android.bundle \
    --assets-dest ./build

    # Create zip archive
    zip -r update.zip ./build
  7. Upload the Android update bundle to the CodePush Server:

    - script@1:
    title: Upload Android Update Bundle to Codepush Server
    inputs:
    - content: |
    #!/usr/bin/env bash
    # fail if any commands fails
    set -e
    # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully
    set -o pipefail
    # debug log
    set -x

    cd release-management-recipes

    UPLOAD_RESPONSE=$(PACKAGE_PATH=../update.zip \
    AUTHORIZATION_TOKEN=$BITRISE_API_TOKEN \
    CONNECTED_APP_ID=$ANDROID_CONNECTED_APP_ID \
    DEPLOYMENT_ID=$ANDROID_PROD_DEPLOYMENT_ID \
    APP_VERSION=$APP_VERSION /bin/bash ./api/upload_code_push_package.sh 2>&1)
    EXIT_CODE=$?

    if [ $EXIT_CODE -ne 0 ]; then
    echo "❌ upload_code_push_package.sh failed with exit code $EXIT_CODE"
    echo "$UPLOAD_RESPONSE"
    exit $EXIT_CODE
    fi

    # Take only the last line of the response (final/latest status JSON object)
    FINAL_RESPONSE=$(echo "$UPLOAD_RESPONSE" | tail -n1)

    # Check explicitly for ERR_INTERNAL or other internal error indicators
    if echo "$UPLOAD_RESPONSE" | grep -q "ERR_INTERNAL"; then
    ERROR_MESSAGE=$(echo "$FINAL_RESPONSE" | jq -r '.message' || echo "Unknown error")
    echo "❌ Server returned internal error: $ERROR_MESSAGE"
    exit 1
    fi

    # Now safely parse 'status' and 'status_reason' from the final response line
    PACKAGE_STATUS=$(echo "$FINAL_RESPONSE" | jq -r '.status' || echo "null")
    STATUS_REASON=$(echo "$FINAL_RESPONSE" | jq -r '.status_reason' || echo "")

    if [ "$PACKAGE_STATUS" = "processed_valid" ]; then
    echo "✅ Package uploaded and processed successfully."
    else
    echo "⚠️ Package upload unexpected status: $PACKAGE_STATUS - Reason: $STATUS_REASON"
    exit 1
    fi

    cd ..

Automating the CodePush update releaseClick to copy link​

After creating a Workflow to generate and upload your CodePush updates, you have two ways of running it:

You can set up several different types of triggers to automate the process. Our example configuration uses a pull request trigger with a label:

Release a CodePush update when a pull request is opened to a specific branch

In this example, we're setting up a trigger where:

  • Bitrise looks for pull requests opened with updates as the target branch.
  • The codepush_update_deploy Workflow is triggered when a pull request to the branch receives the release-update label to the PR.
  1. Create the trigger: set up a pull request trigger with two conditions, target_branch and label:

    • Set target_branch to updates.
    • Set label to release-update.
    GUI config

    You can set these up on the GUI of the Workflow Editor, too. Here we're showing you the YAML configuration.

    format_version: "13"
    default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
    project_type: react-native
    workflows:
    codepush_update_deploy:
    status_report_name: 'Executing <target_id> for <project_title>'
    description: |
    Uploads Update Bundle to Bitrise CodePush Server
    steps:
    [...]
    triggers:
    pull_request:
    - target_branch: updates
    label: release-update
  2. When you want to release CodePush updates, open a pull request to the updates branch.

  3. After the PR has been reviewed and approved, add the release-update label to it.