General Release
Releases an update to the Turbopush server that was generated by an external tool or build script (e.g. a Gulp task, the react-native bundle
command). This provides the most flexibility in terms of fitting into existing workflows, since it strictly deals with Turbopush-specific step, and leaves the app-specific compilation process to you.
turbopush release <appSlug> <updateContents> <targetBinaryVersion>
[--deploymentName <deploymentName>]
[--description <description>]
[--disabled <disabled>]
[--mandatory]
[--noDuplicateReleaseError]
[--rollout <rolloutPercentage>]
[--privateKeyPath <pathToPrivateKey>]
Parameters
App name parameter
This specifies the name of the Turbopush app that this update is being released for. This value corresponds to the friendly name that you specified when originally calling turbopush app add
(e.g. "MyApp-Android"). If you need to look it up, you can run the turbopush app ls
command to see your list of apps.
Update contents parameter
This specifies the location of the updated app code and assets you want to release. You can provide either a single file (e.g. a JS bundle for a React Native app), or a path to a directory. Note that you don't need to ZIP up multiple files or directories in order to deploy those changes, since the CLI will automatically ZIP them for you.
It's important that the path you specify refers to the platform-specific, prepared/bundled version of your app. The following table outlines which command you should run before releasing, as well as the location you can subsequently refer to using the updateContents
parameter:
Platform | Prepare command | Package path (relative to project root) |
---|---|---|
React Native wo/assets (Android) | react-native bundle --platform android --entry-file <entryFile> --bundle-output <bundleOutput> --dev false | Value of the --bundle-output option |
React Native w/assets (Android) | react-native bundle --platform android --entry-file <entryFile> --bundle-output <releaseFolder>/<bundleOutput> --assets-dest <releaseFolder> --dev false | Value of the --assets-dest option, which should represent a newly created directory that includes your assets and JS bundle |
React Native wo/assets (iOS) | react-native bundle --platform ios --entry-file <entryFile> --bundle-output <bundleOutput> --dev false | Value of the --bundle-output option |
React Native w/assets (iOS) | react-native bundle --platform ios --entry-file <entryFile> --bundle-output <releaseFolder>/<bundleOutput> --assets-dest <releaseFolder> --dev false | Value of the --assets-dest option, which should represent a newly created directory that includes your assets and JS bundle |
Target binary version parameter
This specifies the store/binary version of the application you are releasing the update for, so that only users running that version will receive the update, while users running an older and/or newer version of the app binary will not. This is useful for the following reasons:
-
If a user is running an older binary version, it's possible that there are breaking changes in the Turbopush update that wouldn't be compatible with what they're running.
-
If a user is running a newer binary version, then it's presumed that what they are running is newer (and potentially incompatible) with the Turbopush update.
If you ever want an update to target multiple versions of the app store binary, we also allow you to specify the parameter as a semver range expression. That way, any client device running a version of the binary that satisfies the range expression (i.e. semver.satisfies(version, range)
returns true
) will get the update. Examples of valid semver range expressions are as follows:
Range Expression | Who gets the update |
---|---|
1.2.3 | Only devices running the specific binary version 1.2.3 of your app |
* | Any device configured to consume updates from your Turbopush app |
1.2.x | Devices running major version 1, minor version 2 and any patch version of your app |
1.2.3 - 1.2.7 | Devices running any binary version between 1.2.3 (inclusive) and 1.2.7 (inclusive) |
>=1.2.3 <1.2.7 | Devices running any binary version between 1.2.3 (inclusive) and 1.2.7 (exclusive) |
1.2 | Equivalent to >=1.2.0 <1.3.0 |
~1.2.3 | Equivalent to >=1.2.3 <1.3.0 |
^1.2.3 | Equivalent to >=1.2.3 <2.0.0 |
*NOTE: If your semver expression starts with a special shell character or operator such as >
, ^
, or **
, the command may not execute correctly if you do not wrap the value in quotes as the shell will not supply the right values to our CLI process. Therefore, it is best to wrap your targetBinaryVersion
parameter in double quotes when calling the release
command, e.g. turbopush release myapp-ios updateContents ">1.2.3"
.
NOTE: As defined in the semver spec, ranges only work for non pre-release versions: https://github.com/npm/node-semver#prerelease-tags. If you want to update a version with pre-release tags, then you need to write the exact version you want to update (1.2.3-beta
for example).
The following table outlines the version value that Turbopush expects your update's semver range to satisfy for each respective app type:
Platform | Source of binary version |
---|---|
React Native (Android) | The android.defaultConfig.versionName property in your build.gradle file |
React Native (iOS) | The CFBundleShortVersionString key in the Info.plist file |
NOTE: If the binary version in the metadata files are missing a patch version, e.g. 2.0
, it will be treated as having a patch version of 0
, i.e. 2.0 -> 2.0.0
. The same is true for binary version equal to plain integer number, 1
will be treated as 1.0.0
in this case.
Deployment name parameter
This specifies which deployment you want to release the update to. This defaults to Staging
, but when you're ready to deploy to Production
, or one of your own custom deployments, just explicitly set this argument.
NOTE: The parameter can be set using either "--deploymentName" or "-d".
Description parameter
This provides an optional "change log" for the deployment. The value is simply round tripped to the client so that when the update is detected, your app can choose to display it to the end-user (e.g. via a "What's new?" dialog). This string accepts control characters such as \n
and \t
so that you can include whitespace formatting within your descriptions for improved readability.
NOTE: This parameter can be set using either "--description" or "--des"
Disabled parameter
This specifies whether an update should be downloadable by end users or not. If left unspecified, the update will not be disabled (i.e. users will download it the moment your app calls sync
). This parameter can be valuable if you want to release an update that isn't immediately available, until you expicitly patch it when you want end users to be able to download it (e.g. an announcement blog post went live).
NOTE: This parameter can be set using either "--disabled" or "-x"
Mandatory parameter
This specifies whether the update should be considered mandatory or not (e.g. it includes a critical security fix). This attribute is simply round tripped to the client, who can then decide if and how they would like to enforce it.
NOTE: This parameter is simply a "flag", and therefore, its absence indicates that the release is optional, and its presence indicates that it's mandatory. You can provide a value to it (e.g. --mandatory true
), however, simply specifying --mandatory
is sufficient for marking a release as mandatory.
The mandatory attribute is unique because the server will dynamically modify it as necessary in order to ensure that the semantics of your releases are maintained for your end-users. For example, imagine that you released the following three updates to your app:
Release | Mandatory? |
---|---|
v1 | No |
v2 | Yes |
v3 | No |
If an end-user is currently running v1
, and they query the server for an update, it will respond with v3
(since that is the latest), but it will dynamically convert the release to mandatory, since a mandatory update was released in between. This behavior is important since the code contained in v3
is incremental to that included in v2
, and therefore, whatever made v2
mandatory, continues to make v3
mandatory for anyone that didn't already acquire v2
.
If an end-user is currently running v2
, and they query the server for an update, it will respond with v3
, but leave the release as optional. This is because they already received the mandatory update, and therefore, there isn't a need to modify the policy of v3
. This behavior is why we say that the server will "dynamically convert" the mandatory flag, because as far as the release goes, its mandatory attribute will always be stored using the value you specified when releasing it. It is only changed on-the-fly as necessary when responding to an update check from an end-user.
If you never release an update that is marked as mandatory, then the above behavior doesn't apply to you, since the server will never change an optional release to mandatory unless there were intermingled mandatory updates as illustrated above. Additionally, if a release is marked as mandatory, it will never be converted to optional, since that wouldn't make any sense. The server will only change an optional release to mandatory in order to respect the semantics described above.
NOTE: This parameter can be set using either --mandatory
or -m
No duplicate release error parameter
This specifies that if the update is identical to the latest release on the deployment, the CLI should generate a warning instead of an error. This is useful for continuous integration scenarios where it is expected that small modifications may trigger releases where no production code has changed.
Rollout parameter
This specifies the percentage of users (as an integer between 1
and 100
) that should be eligible to receive this update. It can be helpful if you want to "flight" new releases with a portion of your audience (e.g. 25%), and get feedback and/or watch for exceptions/crashes, before making it broadly available for everyone. If this parameter isn't set, it is set to 100%
, and therefore, you only need to set it if you want to actually limit how many users will receive it.
When leveraging the rollout capability, there are a few additional considerations to keep in mind:
-
You cannot release a new update to a deployment whose latest release is an "active" rollout (i.e. its rollout property is non-null). The rollout needs to be "completed" (i.e. setting the
rollout
property to100
) before you can release further updates to the deployment. -
If you rollback a deployment whose latest release is an "active" rollout, the rollout value will be cleared, effectively "deactivating" the rollout behavior
-
Unlike the
mandatory
anddescription
fields, when you promote a release from one deployment to another, it will not propagate therollout
property, and therefore, if you want the new release (in the target deployment) to have a rollout value, you need to explicitly set it when you call thepromote
command.
NOTE: This parameter can be set using either --rollout
or -r
Private key path parameter
This parameter specifies a path to the private key file used to generate the signature of the update. If the private key path parameter is omitted, signature verification in the turbopush plugin will be ignored.
Please refer to the Code Signing section for more details on the Code Signing feature.
NOTE: This option is supported only for React Native applications on Android and iOS platforms.