@algocare/react-native-code-push 10.3.2 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CodePush.js +440 -293
- package/cli/commands/common.js +1 -1
- package/cli/commands/createPullRequestHistoryCommand/createPullRequestHistory.js +3 -3
- package/cli/commands/createPullRequestHistoryCommand/index.js +1 -2
- package/cli/commands/createPullRequestReleaseCommand/addToPullRequestRelease.js +23 -7
- package/cli/commands/releaseCommand/index.js +6 -3
- package/cli/index.js +0 -5
- package/package.json +1 -1
- package/cli/commands/getDevelopmentKeyCommand/index.js +0 -31
package/CodePush.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import { Alert } from
|
|
2
|
-
import { AppState, Platform } from
|
|
3
|
-
import log from
|
|
4
|
-
import hoistStatics from 'hoist-non-react-statics'
|
|
1
|
+
import { Alert } from './AlertAdapter'
|
|
2
|
+
import { AppState, Platform } from 'react-native'
|
|
3
|
+
import log from './logging'
|
|
4
|
+
import hoistStatics from 'hoist-non-react-statics'
|
|
5
5
|
import { SemverVersioning } from './versioning/SemverVersioning'
|
|
6
6
|
|
|
7
|
-
let NativeCodePush = require(
|
|
8
|
-
const PackageMixins = require(
|
|
7
|
+
let NativeCodePush = require('react-native').NativeModules.CodePush
|
|
8
|
+
const PackageMixins = require('./package-mixins')(NativeCodePush)
|
|
9
9
|
|
|
10
|
-
async function checkForUpdate(
|
|
10
|
+
async function checkForUpdate(
|
|
11
|
+
prNumber,
|
|
12
|
+
packageHash,
|
|
13
|
+
handleBinaryVersionMismatchCallback = null
|
|
14
|
+
) {
|
|
11
15
|
/*
|
|
12
16
|
* Before we ask the server if an update exists, we
|
|
13
17
|
* need to retrieve three pieces of information from the
|
|
@@ -17,7 +21,7 @@ async function checkForUpdate(deploymentKey = null, handleBinaryVersionMismatchC
|
|
|
17
21
|
* for their specific deployment and version and which are actually
|
|
18
22
|
* different from the CodePush update they have already installed.
|
|
19
23
|
*/
|
|
20
|
-
const nativeConfig = await getConfiguration()
|
|
24
|
+
const nativeConfig = await getConfiguration()
|
|
21
25
|
/*
|
|
22
26
|
* If a deployment key was explicitly provided,
|
|
23
27
|
* then let's override the one we retrieved
|
|
@@ -25,10 +29,10 @@ async function checkForUpdate(deploymentKey = null, handleBinaryVersionMismatchC
|
|
|
25
29
|
* dynamically "redirecting" end-users at different
|
|
26
30
|
* deployments (e.g. an early access deployment for insiders).
|
|
27
31
|
*/
|
|
28
|
-
const config =
|
|
32
|
+
const config = nativeConfig
|
|
29
33
|
|
|
30
34
|
// Use dynamically overridden getCurrentPackage() during tests.
|
|
31
|
-
const localPackage = await module.exports.getCurrentPackage()
|
|
35
|
+
const localPackage = await module.exports.getCurrentPackage()
|
|
32
36
|
|
|
33
37
|
/*
|
|
34
38
|
* If the app has a previously installed update, and that update
|
|
@@ -38,13 +42,13 @@ async function checkForUpdate(deploymentKey = null, handleBinaryVersionMismatchC
|
|
|
38
42
|
* to send the app version to the server, since we are interested
|
|
39
43
|
* in any updates for current binary version, regardless of hash.
|
|
40
44
|
*/
|
|
41
|
-
let queryPackage
|
|
45
|
+
let queryPackage
|
|
42
46
|
if (localPackage) {
|
|
43
|
-
queryPackage = localPackage
|
|
47
|
+
queryPackage = localPackage
|
|
44
48
|
} else {
|
|
45
|
-
queryPackage = { appVersion: config.appVersion }
|
|
46
|
-
if (Platform.OS ===
|
|
47
|
-
queryPackage.packageHash = config.packageHash
|
|
49
|
+
queryPackage = { appVersion: config.appVersion }
|
|
50
|
+
if (Platform.OS === 'ios' && config.packageHash) {
|
|
51
|
+
queryPackage.packageHash = config.packageHash
|
|
48
52
|
}
|
|
49
53
|
}
|
|
50
54
|
|
|
@@ -58,43 +62,60 @@ async function checkForUpdate(deploymentKey = null, handleBinaryVersionMismatchC
|
|
|
58
62
|
is_companion: config.ignoreAppVersion,
|
|
59
63
|
label: queryPackage.label,
|
|
60
64
|
client_unique_id: config.clientUniqueId,
|
|
61
|
-
}
|
|
65
|
+
}
|
|
62
66
|
|
|
63
67
|
/**
|
|
64
68
|
* @type {updateChecker|undefined}
|
|
65
69
|
* @deprecated
|
|
66
70
|
*/
|
|
67
|
-
const updateChecker = sharedCodePushOptions.updateChecker
|
|
71
|
+
const updateChecker = sharedCodePushOptions.updateChecker
|
|
68
72
|
if (updateChecker) {
|
|
69
|
-
const { update_info } = await updateChecker(updateRequest)
|
|
73
|
+
const { update_info } = await updateChecker(updateRequest)
|
|
70
74
|
|
|
71
|
-
return mapToRemotePackageMetadata(update_info, config.deploymentKey)
|
|
75
|
+
return mapToRemotePackageMetadata(update_info, config.deploymentKey)
|
|
72
76
|
} else {
|
|
73
77
|
/**
|
|
74
78
|
* `releaseHistory`
|
|
75
79
|
* @type {ReleaseHistoryInterface}
|
|
76
80
|
*/
|
|
77
|
-
const releaseHistory =
|
|
81
|
+
const releaseHistory =
|
|
82
|
+
await sharedCodePushOptions.releaseHistoryFetcher(updateRequest)
|
|
83
|
+
|
|
84
|
+
const filteredReleaseHistory = Object.entries(releaseHistory)
|
|
85
|
+
.filter(([key]) => key.includes(prNumber))
|
|
86
|
+
.reduce((acc, [key, value]) => {
|
|
87
|
+
const version = key.split('-')[1]
|
|
88
|
+
acc[version] = value
|
|
89
|
+
return acc
|
|
90
|
+
}, {})
|
|
91
|
+
|
|
92
|
+
const _releaseHistory = packageHash
|
|
93
|
+
? filteredReleaseHistory
|
|
94
|
+
: releaseHistory
|
|
78
95
|
|
|
79
96
|
/**
|
|
80
97
|
* `runtimeVersion`
|
|
81
98
|
* The version of currently running CodePush update. (It can be undefined if the app is running without CodePush update.)
|
|
82
99
|
* @type {string|undefined}
|
|
83
100
|
*/
|
|
84
|
-
const runtimeVersion =
|
|
101
|
+
const runtimeVersion = packageHash
|
|
102
|
+
? updateRequest.label.split('-')[1]
|
|
103
|
+
: updateRequest.label
|
|
85
104
|
|
|
86
|
-
const versioning = new SemverVersioning(
|
|
105
|
+
const versioning = new SemverVersioning(_releaseHistory)
|
|
87
106
|
|
|
88
|
-
const shouldRollbackToBinary =
|
|
107
|
+
const shouldRollbackToBinary =
|
|
108
|
+
versioning.shouldRollbackToBinary(runtimeVersion)
|
|
89
109
|
if (shouldRollbackToBinary) {
|
|
90
110
|
// Reset to latest major version and restart
|
|
91
|
-
CodePush.clearUpdates()
|
|
92
|
-
CodePush.allowRestart()
|
|
93
|
-
CodePush.restartApp()
|
|
111
|
+
CodePush.clearUpdates()
|
|
112
|
+
CodePush.allowRestart()
|
|
113
|
+
CodePush.restartApp()
|
|
94
114
|
}
|
|
95
115
|
|
|
96
|
-
const [latestVersion, latestReleaseInfo] =
|
|
97
|
-
|
|
116
|
+
const [latestVersion, latestReleaseInfo] =
|
|
117
|
+
versioning.findLatestRelease()
|
|
118
|
+
const isMandatory = versioning.checkIsMandatory(runtimeVersion)
|
|
98
119
|
|
|
99
120
|
/**
|
|
100
121
|
* Convert the update information decided from `ReleaseHistoryInterface` to be passed to the library core (original CodePush library).
|
|
@@ -128,15 +149,15 @@ async function checkForUpdate(deploymentKey = null, handleBinaryVersionMismatchC
|
|
|
128
149
|
should_run_binary_version: false,
|
|
129
150
|
}
|
|
130
151
|
|
|
131
|
-
return mapToRemotePackageMetadata(updateInfo, config.deploymentKey)
|
|
152
|
+
return mapToRemotePackageMetadata(updateInfo, config.deploymentKey)
|
|
132
153
|
}
|
|
133
154
|
} catch (error) {
|
|
134
|
-
log(`An error has occurred at update checker :`)
|
|
155
|
+
log(`An error has occurred at update checker :`)
|
|
135
156
|
console.error(error)
|
|
136
157
|
// update will not happen
|
|
137
|
-
return undefined
|
|
158
|
+
return undefined
|
|
138
159
|
}
|
|
139
|
-
})()
|
|
160
|
+
})()
|
|
140
161
|
|
|
141
162
|
/*
|
|
142
163
|
* There are four cases where checkForUpdate will resolve to null:
|
|
@@ -156,22 +177,33 @@ async function checkForUpdate(deploymentKey = null, handleBinaryVersionMismatchC
|
|
|
156
177
|
* because we want to avoid having to install diff updates against the binary's
|
|
157
178
|
* version, which we can't do yet on Android.
|
|
158
179
|
*/
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
180
|
+
if (
|
|
181
|
+
!update ||
|
|
182
|
+
update.updateAppVersion ||
|
|
183
|
+
(localPackage && update.packageHash === localPackage.packageHash) ||
|
|
184
|
+
((!localPackage || localPackage._isDebugOnly) &&
|
|
185
|
+
config.packageHash === update.packageHash)
|
|
186
|
+
) {
|
|
162
187
|
if (update && update.updateAppVersion) {
|
|
163
|
-
log(
|
|
164
|
-
|
|
188
|
+
log(
|
|
189
|
+
'An update is available but it is not targeting the binary version of your app.'
|
|
190
|
+
)
|
|
191
|
+
if (
|
|
192
|
+
handleBinaryVersionMismatchCallback &&
|
|
193
|
+
typeof handleBinaryVersionMismatchCallback === 'function'
|
|
194
|
+
) {
|
|
165
195
|
handleBinaryVersionMismatchCallback(update)
|
|
166
196
|
}
|
|
167
197
|
}
|
|
168
198
|
|
|
169
|
-
return null
|
|
199
|
+
return null
|
|
170
200
|
} else {
|
|
171
|
-
const remotePackage = { ...update, ...PackageMixins.remote() }
|
|
172
|
-
remotePackage.failedInstall = await NativeCodePush.isFailedUpdate(
|
|
173
|
-
|
|
174
|
-
|
|
201
|
+
const remotePackage = { ...update, ...PackageMixins.remote() }
|
|
202
|
+
remotePackage.failedInstall = await NativeCodePush.isFailedUpdate(
|
|
203
|
+
remotePackage.packageHash
|
|
204
|
+
)
|
|
205
|
+
remotePackage.deploymentKey = nativeConfig.deploymentKey
|
|
206
|
+
return remotePackage
|
|
175
207
|
}
|
|
176
208
|
}
|
|
177
209
|
|
|
@@ -182,12 +214,12 @@ async function checkForUpdate(deploymentKey = null, handleBinaryVersionMismatchC
|
|
|
182
214
|
*/
|
|
183
215
|
function mapToRemotePackageMetadata(updateInfo, deploymentKey) {
|
|
184
216
|
if (!updateInfo) {
|
|
185
|
-
return null
|
|
217
|
+
return null
|
|
186
218
|
} else if (!updateInfo.download_url) {
|
|
187
|
-
log(
|
|
188
|
-
return null
|
|
219
|
+
log('download_url is missed in the release history.')
|
|
220
|
+
return null
|
|
189
221
|
} else if (!updateInfo.is_available) {
|
|
190
|
-
return null
|
|
222
|
+
return null
|
|
191
223
|
}
|
|
192
224
|
|
|
193
225
|
// refer to `RemotePackage` type inside code-push SDK
|
|
@@ -200,220 +232,255 @@ function mapToRemotePackageMetadata(updateInfo, deploymentKey) {
|
|
|
200
232
|
packageHash: updateInfo.package_hash ?? '',
|
|
201
233
|
packageSize: updateInfo.package_size ?? 0,
|
|
202
234
|
downloadUrl: updateInfo.download_url ?? '',
|
|
203
|
-
}
|
|
235
|
+
}
|
|
204
236
|
}
|
|
205
237
|
|
|
206
238
|
const getConfiguration = (() => {
|
|
207
|
-
let config
|
|
239
|
+
let config
|
|
208
240
|
return async function getConfiguration() {
|
|
209
241
|
if (config) {
|
|
210
|
-
return config
|
|
242
|
+
return config
|
|
211
243
|
} else if (testConfig) {
|
|
212
|
-
return testConfig
|
|
244
|
+
return testConfig
|
|
213
245
|
} else {
|
|
214
|
-
config = await NativeCodePush.getConfiguration()
|
|
215
|
-
return config
|
|
246
|
+
config = await NativeCodePush.getConfiguration()
|
|
247
|
+
return config
|
|
216
248
|
}
|
|
217
249
|
}
|
|
218
|
-
})()
|
|
250
|
+
})()
|
|
219
251
|
|
|
220
252
|
async function getCurrentPackage() {
|
|
221
|
-
return await getUpdateMetadata(CodePush.UpdateState.LATEST)
|
|
253
|
+
return await getUpdateMetadata(CodePush.UpdateState.LATEST)
|
|
222
254
|
}
|
|
223
255
|
|
|
224
256
|
async function getUpdateMetadata(updateState) {
|
|
225
|
-
let updateMetadata = await NativeCodePush.getUpdateMetadata(
|
|
257
|
+
let updateMetadata = await NativeCodePush.getUpdateMetadata(
|
|
258
|
+
updateState || CodePush.UpdateState.RUNNING
|
|
259
|
+
)
|
|
226
260
|
if (updateMetadata) {
|
|
227
|
-
updateMetadata = {...PackageMixins.local, ...updateMetadata}
|
|
228
|
-
updateMetadata.failedInstall = await NativeCodePush.isFailedUpdate(
|
|
229
|
-
|
|
261
|
+
updateMetadata = { ...PackageMixins.local, ...updateMetadata }
|
|
262
|
+
updateMetadata.failedInstall = await NativeCodePush.isFailedUpdate(
|
|
263
|
+
updateMetadata.packageHash
|
|
264
|
+
)
|
|
265
|
+
updateMetadata.isFirstRun = await NativeCodePush.isFirstRun(
|
|
266
|
+
updateMetadata.packageHash
|
|
267
|
+
)
|
|
230
268
|
}
|
|
231
|
-
return updateMetadata
|
|
269
|
+
return updateMetadata
|
|
232
270
|
}
|
|
233
271
|
|
|
234
272
|
// This ensures that notifyApplicationReadyInternal is only called once
|
|
235
273
|
// in the lifetime of this module instance.
|
|
236
274
|
const notifyApplicationReady = (() => {
|
|
237
|
-
let notifyApplicationReadyPromise
|
|
275
|
+
let notifyApplicationReadyPromise
|
|
238
276
|
return () => {
|
|
239
277
|
if (!notifyApplicationReadyPromise) {
|
|
240
|
-
notifyApplicationReadyPromise = notifyApplicationReadyInternal()
|
|
278
|
+
notifyApplicationReadyPromise = notifyApplicationReadyInternal()
|
|
241
279
|
}
|
|
242
280
|
|
|
243
|
-
return notifyApplicationReadyPromise
|
|
244
|
-
}
|
|
245
|
-
})()
|
|
281
|
+
return notifyApplicationReadyPromise
|
|
282
|
+
}
|
|
283
|
+
})()
|
|
246
284
|
|
|
247
285
|
async function notifyApplicationReadyInternal() {
|
|
248
|
-
await NativeCodePush.notifyApplicationReady()
|
|
249
|
-
const statusReport = await NativeCodePush.getNewStatusReport()
|
|
250
|
-
statusReport && tryReportStatus(statusReport)
|
|
286
|
+
await NativeCodePush.notifyApplicationReady()
|
|
287
|
+
const statusReport = await NativeCodePush.getNewStatusReport()
|
|
288
|
+
statusReport && tryReportStatus(statusReport) // Don't wait for this to complete.
|
|
251
289
|
|
|
252
|
-
return statusReport
|
|
290
|
+
return statusReport
|
|
253
291
|
}
|
|
254
292
|
|
|
255
293
|
async function tryReportStatus(statusReport, retryOnAppResume) {
|
|
256
|
-
const config = await getConfiguration()
|
|
294
|
+
const config = await getConfiguration()
|
|
257
295
|
|
|
258
296
|
try {
|
|
259
297
|
if (statusReport.appVersion) {
|
|
260
|
-
log(`Reporting binary update (${statusReport.appVersion})`)
|
|
298
|
+
log(`Reporting binary update (${statusReport.appVersion})`)
|
|
261
299
|
|
|
262
300
|
if (!config.deploymentKey) {
|
|
263
|
-
throw new Error(
|
|
301
|
+
throw new Error('Deployment key is missed')
|
|
264
302
|
}
|
|
265
303
|
} else {
|
|
266
|
-
const label = statusReport.package.label
|
|
267
|
-
if (statusReport.status ===
|
|
268
|
-
log(`Reporting CodePush update success (${label})`)
|
|
304
|
+
const label = statusReport.package.label
|
|
305
|
+
if (statusReport.status === 'DeploymentSucceeded') {
|
|
306
|
+
log(`Reporting CodePush update success (${label})`)
|
|
269
307
|
} else {
|
|
270
|
-
log(`Reporting CodePush update rollback (${label})`)
|
|
271
|
-
await NativeCodePush.setLatestRollbackInfo(
|
|
308
|
+
log(`Reporting CodePush update rollback (${label})`)
|
|
309
|
+
await NativeCodePush.setLatestRollbackInfo(
|
|
310
|
+
statusReport.package.packageHash
|
|
311
|
+
)
|
|
272
312
|
}
|
|
273
313
|
}
|
|
274
314
|
|
|
275
|
-
NativeCodePush.recordStatusReported(statusReport)
|
|
276
|
-
retryOnAppResume && retryOnAppResume.remove()
|
|
315
|
+
NativeCodePush.recordStatusReported(statusReport)
|
|
316
|
+
retryOnAppResume && retryOnAppResume.remove()
|
|
277
317
|
} catch (e) {
|
|
278
|
-
log(`Report status failed: ${JSON.stringify(statusReport)}`)
|
|
279
|
-
NativeCodePush.saveStatusReportForRetry(statusReport)
|
|
318
|
+
log(`Report status failed: ${JSON.stringify(statusReport)}`)
|
|
319
|
+
NativeCodePush.saveStatusReportForRetry(statusReport)
|
|
280
320
|
// Try again when the app resumes
|
|
281
321
|
if (!retryOnAppResume) {
|
|
282
|
-
const resumeListener = AppState.addEventListener(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
322
|
+
const resumeListener = AppState.addEventListener(
|
|
323
|
+
'change',
|
|
324
|
+
async (newState) => {
|
|
325
|
+
if (newState !== 'active') return
|
|
326
|
+
const refreshedStatusReport =
|
|
327
|
+
await NativeCodePush.getNewStatusReport()
|
|
328
|
+
if (refreshedStatusReport) {
|
|
329
|
+
tryReportStatus(refreshedStatusReport, resumeListener)
|
|
330
|
+
} else {
|
|
331
|
+
resumeListener && resumeListener.remove()
|
|
332
|
+
}
|
|
289
333
|
}
|
|
290
|
-
|
|
334
|
+
)
|
|
291
335
|
}
|
|
292
336
|
}
|
|
293
337
|
}
|
|
294
338
|
|
|
295
339
|
async function shouldUpdateBeIgnored(remotePackage, syncOptions) {
|
|
296
|
-
let { rollbackRetryOptions } = syncOptions
|
|
340
|
+
let { rollbackRetryOptions } = syncOptions
|
|
297
341
|
|
|
298
|
-
const isFailedPackage = remotePackage && remotePackage.failedInstall
|
|
342
|
+
const isFailedPackage = remotePackage && remotePackage.failedInstall
|
|
299
343
|
if (!isFailedPackage || !syncOptions.ignoreFailedUpdates) {
|
|
300
|
-
return false
|
|
344
|
+
return false
|
|
301
345
|
}
|
|
302
346
|
|
|
303
347
|
if (!rollbackRetryOptions) {
|
|
304
|
-
return true
|
|
348
|
+
return true
|
|
305
349
|
}
|
|
306
350
|
|
|
307
|
-
if (typeof rollbackRetryOptions !==
|
|
308
|
-
rollbackRetryOptions = CodePush.DEFAULT_ROLLBACK_RETRY_OPTIONS
|
|
351
|
+
if (typeof rollbackRetryOptions !== 'object') {
|
|
352
|
+
rollbackRetryOptions = CodePush.DEFAULT_ROLLBACK_RETRY_OPTIONS
|
|
309
353
|
} else {
|
|
310
|
-
rollbackRetryOptions = {
|
|
354
|
+
rollbackRetryOptions = {
|
|
355
|
+
...CodePush.DEFAULT_ROLLBACK_RETRY_OPTIONS,
|
|
356
|
+
...rollbackRetryOptions,
|
|
357
|
+
}
|
|
311
358
|
}
|
|
312
359
|
|
|
313
360
|
if (!validateRollbackRetryOptions(rollbackRetryOptions)) {
|
|
314
|
-
return true
|
|
361
|
+
return true
|
|
315
362
|
}
|
|
316
363
|
|
|
317
|
-
const latestRollbackInfo = await NativeCodePush.getLatestRollbackInfo()
|
|
318
|
-
if (
|
|
319
|
-
|
|
320
|
-
|
|
364
|
+
const latestRollbackInfo = await NativeCodePush.getLatestRollbackInfo()
|
|
365
|
+
if (
|
|
366
|
+
!validateLatestRollbackInfo(latestRollbackInfo, remotePackage.packageHash)
|
|
367
|
+
) {
|
|
368
|
+
log('The latest rollback info is not valid.')
|
|
369
|
+
return true
|
|
321
370
|
}
|
|
322
371
|
|
|
323
|
-
const { delayInHours, maxRetryAttempts } = rollbackRetryOptions
|
|
324
|
-
const hoursSinceLatestRollback =
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
372
|
+
const { delayInHours, maxRetryAttempts } = rollbackRetryOptions
|
|
373
|
+
const hoursSinceLatestRollback =
|
|
374
|
+
(Date.now() - latestRollbackInfo.time) / (1000 * 60 * 60)
|
|
375
|
+
if (
|
|
376
|
+
hoursSinceLatestRollback >= delayInHours &&
|
|
377
|
+
maxRetryAttempts >= latestRollbackInfo.count
|
|
378
|
+
) {
|
|
379
|
+
log('Previous rollback should be ignored due to rollback retry options.')
|
|
380
|
+
return false
|
|
328
381
|
}
|
|
329
382
|
|
|
330
|
-
return true
|
|
383
|
+
return true
|
|
331
384
|
}
|
|
332
385
|
|
|
333
386
|
function validateLatestRollbackInfo(latestRollbackInfo, packageHash) {
|
|
334
|
-
return
|
|
387
|
+
return (
|
|
388
|
+
latestRollbackInfo &&
|
|
335
389
|
latestRollbackInfo.time &&
|
|
336
390
|
latestRollbackInfo.count &&
|
|
337
391
|
latestRollbackInfo.packageHash &&
|
|
338
|
-
latestRollbackInfo.packageHash === packageHash
|
|
392
|
+
latestRollbackInfo.packageHash === packageHash
|
|
393
|
+
)
|
|
339
394
|
}
|
|
340
395
|
|
|
341
396
|
function validateRollbackRetryOptions(rollbackRetryOptions) {
|
|
342
|
-
if (typeof rollbackRetryOptions.delayInHours !==
|
|
343
|
-
log("The 'delayInHours' rollback retry parameter must be a number.")
|
|
344
|
-
return false
|
|
397
|
+
if (typeof rollbackRetryOptions.delayInHours !== 'number') {
|
|
398
|
+
log("The 'delayInHours' rollback retry parameter must be a number.")
|
|
399
|
+
return false
|
|
345
400
|
}
|
|
346
401
|
|
|
347
|
-
if (typeof rollbackRetryOptions.maxRetryAttempts !==
|
|
348
|
-
log("The 'maxRetryAttempts' rollback retry parameter must be a number.")
|
|
349
|
-
return false
|
|
402
|
+
if (typeof rollbackRetryOptions.maxRetryAttempts !== 'number') {
|
|
403
|
+
log("The 'maxRetryAttempts' rollback retry parameter must be a number.")
|
|
404
|
+
return false
|
|
350
405
|
}
|
|
351
406
|
|
|
352
407
|
if (rollbackRetryOptions.maxRetryAttempts < 1) {
|
|
353
|
-
log(
|
|
354
|
-
|
|
408
|
+
log(
|
|
409
|
+
"The 'maxRetryAttempts' rollback retry parameter cannot be less then 1."
|
|
410
|
+
)
|
|
411
|
+
return false
|
|
355
412
|
}
|
|
356
413
|
|
|
357
|
-
return true
|
|
414
|
+
return true
|
|
358
415
|
}
|
|
359
416
|
|
|
360
|
-
let testConfig
|
|
417
|
+
let testConfig
|
|
361
418
|
|
|
362
419
|
// This function is only used for tests. Replaces the default SDK, configuration and native bridge
|
|
363
420
|
function setUpTestDependencies(testSdk, providedTestConfig, testNativeBridge) {
|
|
364
|
-
if (testSdk) module.exports.AcquisitionSdk = testSdk
|
|
365
|
-
if (providedTestConfig) testConfig = providedTestConfig
|
|
366
|
-
if (testNativeBridge) NativeCodePush = testNativeBridge
|
|
421
|
+
if (testSdk) module.exports.AcquisitionSdk = testSdk
|
|
422
|
+
if (providedTestConfig) testConfig = providedTestConfig
|
|
423
|
+
if (testNativeBridge) NativeCodePush = testNativeBridge
|
|
367
424
|
}
|
|
368
425
|
|
|
369
426
|
async function restartApp(onlyIfUpdateIsPending = false) {
|
|
370
|
-
NativeCodePush.restartApp(onlyIfUpdateIsPending)
|
|
427
|
+
NativeCodePush.restartApp(onlyIfUpdateIsPending)
|
|
371
428
|
}
|
|
372
429
|
|
|
373
430
|
// This function allows only one syncInternal operation to proceed at any given time.
|
|
374
431
|
// Parallel calls to sync() while one is ongoing yields CodePush.SyncStatus.SYNC_IN_PROGRESS.
|
|
375
432
|
const sync = (() => {
|
|
376
|
-
let syncInProgress = false
|
|
377
|
-
const setSyncCompleted = () => {
|
|
433
|
+
let syncInProgress = false
|
|
434
|
+
const setSyncCompleted = () => {
|
|
435
|
+
syncInProgress = false
|
|
436
|
+
}
|
|
378
437
|
|
|
379
|
-
return (
|
|
380
|
-
|
|
381
|
-
|
|
438
|
+
return (
|
|
439
|
+
options = {},
|
|
440
|
+
syncStatusChangeCallback,
|
|
441
|
+
downloadProgressCallback,
|
|
442
|
+
handleBinaryVersionMismatchCallback
|
|
443
|
+
) => {
|
|
444
|
+
let syncStatusCallbackWithTryCatch, downloadProgressCallbackWithTryCatch
|
|
445
|
+
if (typeof syncStatusChangeCallback === 'function') {
|
|
382
446
|
syncStatusCallbackWithTryCatch = (...args) => {
|
|
383
447
|
try {
|
|
384
|
-
syncStatusChangeCallback(...args)
|
|
448
|
+
syncStatusChangeCallback(...args)
|
|
385
449
|
} catch (error) {
|
|
386
|
-
log(`An error has occurred : ${error.stack}`)
|
|
450
|
+
log(`An error has occurred : ${error.stack}`)
|
|
387
451
|
}
|
|
388
452
|
}
|
|
389
453
|
}
|
|
390
454
|
|
|
391
|
-
if (typeof downloadProgressCallback ===
|
|
455
|
+
if (typeof downloadProgressCallback === 'function') {
|
|
392
456
|
downloadProgressCallbackWithTryCatch = (...args) => {
|
|
393
457
|
try {
|
|
394
|
-
downloadProgressCallback(...args)
|
|
458
|
+
downloadProgressCallback(...args)
|
|
395
459
|
} catch (error) {
|
|
396
|
-
log(`An error has occurred: ${error.stack}`)
|
|
460
|
+
log(`An error has occurred: ${error.stack}`)
|
|
397
461
|
}
|
|
398
462
|
}
|
|
399
463
|
}
|
|
400
464
|
|
|
401
465
|
if (syncInProgress) {
|
|
402
|
-
typeof syncStatusCallbackWithTryCatch ===
|
|
466
|
+
typeof syncStatusCallbackWithTryCatch === 'function'
|
|
403
467
|
? syncStatusCallbackWithTryCatch(CodePush.SyncStatus.SYNC_IN_PROGRESS)
|
|
404
|
-
: log(
|
|
405
|
-
return Promise.resolve(CodePush.SyncStatus.SYNC_IN_PROGRESS)
|
|
468
|
+
: log('Sync already in progress.')
|
|
469
|
+
return Promise.resolve(CodePush.SyncStatus.SYNC_IN_PROGRESS)
|
|
406
470
|
}
|
|
407
471
|
|
|
408
|
-
syncInProgress = true
|
|
409
|
-
const syncPromise = syncInternal(
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
472
|
+
syncInProgress = true
|
|
473
|
+
const syncPromise = syncInternal(
|
|
474
|
+
options,
|
|
475
|
+
syncStatusCallbackWithTryCatch,
|
|
476
|
+
downloadProgressCallbackWithTryCatch,
|
|
477
|
+
handleBinaryVersionMismatchCallback
|
|
478
|
+
)
|
|
479
|
+
syncPromise.then(setSyncCompleted).catch(setSyncCompleted)
|
|
413
480
|
|
|
414
|
-
return syncPromise
|
|
415
|
-
}
|
|
416
|
-
})()
|
|
481
|
+
return syncPromise
|
|
482
|
+
}
|
|
483
|
+
})()
|
|
417
484
|
|
|
418
485
|
/*
|
|
419
486
|
* The syncInternal method provides a simple, one-line experience for
|
|
@@ -424,8 +491,13 @@ const sync = (() => {
|
|
|
424
491
|
* releases, and displaying a standard confirmation UI to the end-user
|
|
425
492
|
* when an update is available.
|
|
426
493
|
*/
|
|
427
|
-
async function syncInternal(
|
|
428
|
-
|
|
494
|
+
async function syncInternal(
|
|
495
|
+
options = {},
|
|
496
|
+
syncStatusChangeCallback,
|
|
497
|
+
downloadProgressCallback,
|
|
498
|
+
handleBinaryVersionMismatchCallback
|
|
499
|
+
) {
|
|
500
|
+
let resolvedInstallMode
|
|
429
501
|
const syncOptions = {
|
|
430
502
|
deploymentKey: null,
|
|
431
503
|
ignoreFailedUpdates: true,
|
|
@@ -434,146 +506,178 @@ async function syncInternal(options = {}, syncStatusChangeCallback, downloadProg
|
|
|
434
506
|
mandatoryInstallMode: CodePush.InstallMode.IMMEDIATE,
|
|
435
507
|
minimumBackgroundDuration: 0,
|
|
436
508
|
updateDialog: null,
|
|
437
|
-
...options
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
syncStatusChangeCallback =
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
} else
|
|
469
|
-
|
|
509
|
+
...options,
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
syncStatusChangeCallback =
|
|
513
|
+
typeof syncStatusChangeCallback === 'function'
|
|
514
|
+
? syncStatusChangeCallback
|
|
515
|
+
: (syncStatus) => {
|
|
516
|
+
switch (syncStatus) {
|
|
517
|
+
case CodePush.SyncStatus.CHECKING_FOR_UPDATE:
|
|
518
|
+
log('Checking for update.')
|
|
519
|
+
break
|
|
520
|
+
case CodePush.SyncStatus.AWAITING_USER_ACTION:
|
|
521
|
+
log('Awaiting user action.')
|
|
522
|
+
break
|
|
523
|
+
case CodePush.SyncStatus.DOWNLOADING_PACKAGE:
|
|
524
|
+
log('Downloading package.')
|
|
525
|
+
break
|
|
526
|
+
case CodePush.SyncStatus.INSTALLING_UPDATE:
|
|
527
|
+
log('Installing update.')
|
|
528
|
+
break
|
|
529
|
+
case CodePush.SyncStatus.UP_TO_DATE:
|
|
530
|
+
log('App is up to date.')
|
|
531
|
+
break
|
|
532
|
+
case CodePush.SyncStatus.UPDATE_IGNORED:
|
|
533
|
+
log('User cancelled the update.')
|
|
534
|
+
break
|
|
535
|
+
case CodePush.SyncStatus.UPDATE_INSTALLED:
|
|
536
|
+
if (resolvedInstallMode == CodePush.InstallMode.ON_NEXT_RESTART) {
|
|
537
|
+
log(
|
|
538
|
+
'Update is installed and will be run on the next app restart.'
|
|
539
|
+
)
|
|
540
|
+
} else if (
|
|
541
|
+
resolvedInstallMode == CodePush.InstallMode.ON_NEXT_RESUME
|
|
542
|
+
) {
|
|
543
|
+
if (syncOptions.minimumBackgroundDuration > 0) {
|
|
544
|
+
log(
|
|
545
|
+
`Update is installed and will be run after the app has been in the background for at least ${syncOptions.minimumBackgroundDuration} seconds.`
|
|
546
|
+
)
|
|
547
|
+
} else {
|
|
548
|
+
log(
|
|
549
|
+
'Update is installed and will be run when the app next resumes.'
|
|
550
|
+
)
|
|
551
|
+
}
|
|
470
552
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
553
|
+
break
|
|
554
|
+
case CodePush.SyncStatus.UNKNOWN_ERROR:
|
|
555
|
+
log('An unknown error occurred.')
|
|
556
|
+
break
|
|
557
|
+
}
|
|
476
558
|
}
|
|
477
|
-
};
|
|
478
559
|
|
|
479
560
|
try {
|
|
480
|
-
await CodePush.notifyApplicationReady()
|
|
561
|
+
await CodePush.notifyApplicationReady()
|
|
481
562
|
|
|
482
|
-
syncStatusChangeCallback(CodePush.SyncStatus.CHECKING_FOR_UPDATE)
|
|
483
|
-
const remotePackage = await checkForUpdate(
|
|
563
|
+
syncStatusChangeCallback(CodePush.SyncStatus.CHECKING_FOR_UPDATE)
|
|
564
|
+
const remotePackage = await checkForUpdate(
|
|
565
|
+
syncOptions.deploymentKey,
|
|
566
|
+
handleBinaryVersionMismatchCallback
|
|
567
|
+
)
|
|
484
568
|
|
|
485
569
|
const doDownloadAndInstall = async () => {
|
|
486
|
-
syncStatusChangeCallback(CodePush.SyncStatus.DOWNLOADING_PACKAGE)
|
|
487
|
-
const localPackage = await remotePackage.download(
|
|
570
|
+
syncStatusChangeCallback(CodePush.SyncStatus.DOWNLOADING_PACKAGE)
|
|
571
|
+
const localPackage = await remotePackage.download(
|
|
572
|
+
downloadProgressCallback
|
|
573
|
+
)
|
|
488
574
|
|
|
489
575
|
// Determine the correct install mode based on whether the update is mandatory or not.
|
|
490
|
-
resolvedInstallMode = localPackage.isMandatory
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
576
|
+
resolvedInstallMode = localPackage.isMandatory
|
|
577
|
+
? syncOptions.mandatoryInstallMode
|
|
578
|
+
: syncOptions.installMode
|
|
579
|
+
|
|
580
|
+
syncStatusChangeCallback(CodePush.SyncStatus.INSTALLING_UPDATE)
|
|
581
|
+
await localPackage.install(
|
|
582
|
+
resolvedInstallMode,
|
|
583
|
+
syncOptions.minimumBackgroundDuration,
|
|
584
|
+
() => {
|
|
585
|
+
syncStatusChangeCallback(CodePush.SyncStatus.UPDATE_INSTALLED)
|
|
586
|
+
}
|
|
587
|
+
)
|
|
496
588
|
|
|
497
|
-
return CodePush.SyncStatus.UPDATE_INSTALLED
|
|
498
|
-
}
|
|
589
|
+
return CodePush.SyncStatus.UPDATE_INSTALLED
|
|
590
|
+
}
|
|
499
591
|
|
|
500
|
-
const updateShouldBeIgnored = await shouldUpdateBeIgnored(
|
|
592
|
+
const updateShouldBeIgnored = await shouldUpdateBeIgnored(
|
|
593
|
+
remotePackage,
|
|
594
|
+
syncOptions
|
|
595
|
+
)
|
|
501
596
|
|
|
502
597
|
if (!remotePackage || updateShouldBeIgnored) {
|
|
503
598
|
if (updateShouldBeIgnored) {
|
|
504
|
-
|
|
599
|
+
log(
|
|
600
|
+
'An update is available, but it is being ignored due to having been previously rolled back.'
|
|
601
|
+
)
|
|
505
602
|
}
|
|
506
603
|
|
|
507
|
-
const currentPackage = await CodePush.getCurrentPackage()
|
|
604
|
+
const currentPackage = await CodePush.getCurrentPackage()
|
|
508
605
|
if (currentPackage && currentPackage.isPending) {
|
|
509
|
-
syncStatusChangeCallback(CodePush.SyncStatus.UPDATE_INSTALLED)
|
|
510
|
-
return CodePush.SyncStatus.UPDATE_INSTALLED
|
|
606
|
+
syncStatusChangeCallback(CodePush.SyncStatus.UPDATE_INSTALLED)
|
|
607
|
+
return CodePush.SyncStatus.UPDATE_INSTALLED
|
|
511
608
|
} else {
|
|
512
|
-
syncStatusChangeCallback(CodePush.SyncStatus.UP_TO_DATE)
|
|
513
|
-
return CodePush.SyncStatus.UP_TO_DATE
|
|
609
|
+
syncStatusChangeCallback(CodePush.SyncStatus.UP_TO_DATE)
|
|
610
|
+
return CodePush.SyncStatus.UP_TO_DATE
|
|
514
611
|
}
|
|
515
612
|
} else if (syncOptions.updateDialog) {
|
|
516
613
|
// updateDialog supports any truthy value (e.g. true, "goo", 12),
|
|
517
614
|
// but we should treat a non-object value as just the default dialog
|
|
518
|
-
if (typeof syncOptions.updateDialog !==
|
|
519
|
-
syncOptions.updateDialog = CodePush.DEFAULT_UPDATE_DIALOG
|
|
615
|
+
if (typeof syncOptions.updateDialog !== 'object') {
|
|
616
|
+
syncOptions.updateDialog = CodePush.DEFAULT_UPDATE_DIALOG
|
|
520
617
|
} else {
|
|
521
|
-
syncOptions.updateDialog = {
|
|
618
|
+
syncOptions.updateDialog = {
|
|
619
|
+
...CodePush.DEFAULT_UPDATE_DIALOG,
|
|
620
|
+
...syncOptions.updateDialog,
|
|
621
|
+
}
|
|
522
622
|
}
|
|
523
623
|
|
|
524
624
|
return await new Promise((resolve, reject) => {
|
|
525
|
-
let message = null
|
|
526
|
-
let installButtonText = null
|
|
625
|
+
let message = null
|
|
626
|
+
let installButtonText = null
|
|
527
627
|
|
|
528
|
-
const dialogButtons = []
|
|
628
|
+
const dialogButtons = []
|
|
529
629
|
|
|
530
630
|
if (remotePackage.isMandatory) {
|
|
531
|
-
message = syncOptions.updateDialog.mandatoryUpdateMessage
|
|
532
|
-
installButtonText =
|
|
631
|
+
message = syncOptions.updateDialog.mandatoryUpdateMessage
|
|
632
|
+
installButtonText =
|
|
633
|
+
syncOptions.updateDialog.mandatoryContinueButtonLabel
|
|
533
634
|
} else {
|
|
534
|
-
message = syncOptions.updateDialog.optionalUpdateMessage
|
|
535
|
-
installButtonText =
|
|
635
|
+
message = syncOptions.updateDialog.optionalUpdateMessage
|
|
636
|
+
installButtonText =
|
|
637
|
+
syncOptions.updateDialog.optionalInstallButtonLabel
|
|
536
638
|
// Since this is an optional update, add a button
|
|
537
639
|
// to allow the end-user to ignore it
|
|
538
640
|
dialogButtons.push({
|
|
539
641
|
text: syncOptions.updateDialog.optionalIgnoreButtonLabel,
|
|
540
642
|
onPress: () => {
|
|
541
|
-
syncStatusChangeCallback(CodePush.SyncStatus.UPDATE_IGNORED)
|
|
542
|
-
resolve(CodePush.SyncStatus.UPDATE_IGNORED)
|
|
543
|
-
}
|
|
544
|
-
})
|
|
643
|
+
syncStatusChangeCallback(CodePush.SyncStatus.UPDATE_IGNORED)
|
|
644
|
+
resolve(CodePush.SyncStatus.UPDATE_IGNORED)
|
|
645
|
+
},
|
|
646
|
+
})
|
|
545
647
|
}
|
|
546
648
|
|
|
547
649
|
// Since the install button should be placed to the
|
|
548
650
|
// right of any other button, add it last
|
|
549
651
|
dialogButtons.push({
|
|
550
652
|
text: installButtonText,
|
|
551
|
-
onPress:() => {
|
|
552
|
-
doDownloadAndInstall()
|
|
553
|
-
|
|
554
|
-
}
|
|
653
|
+
onPress: () => {
|
|
654
|
+
doDownloadAndInstall().then(resolve, reject)
|
|
655
|
+
},
|
|
555
656
|
})
|
|
556
657
|
|
|
557
658
|
// If the update has a description, and the developer
|
|
558
659
|
// explicitly chose to display it, then set that as the message
|
|
559
|
-
if (
|
|
560
|
-
|
|
660
|
+
if (
|
|
661
|
+
syncOptions.updateDialog.appendReleaseDescription &&
|
|
662
|
+
remotePackage.description
|
|
663
|
+
) {
|
|
664
|
+
message += `${syncOptions.updateDialog.descriptionPrefix} ${remotePackage.description}`
|
|
561
665
|
}
|
|
562
666
|
|
|
563
|
-
syncStatusChangeCallback(CodePush.SyncStatus.AWAITING_USER_ACTION)
|
|
564
|
-
Alert.alert(syncOptions.updateDialog.title, message, dialogButtons)
|
|
565
|
-
})
|
|
667
|
+
syncStatusChangeCallback(CodePush.SyncStatus.AWAITING_USER_ACTION)
|
|
668
|
+
Alert.alert(syncOptions.updateDialog.title, message, dialogButtons)
|
|
669
|
+
})
|
|
566
670
|
} else {
|
|
567
|
-
return await doDownloadAndInstall()
|
|
671
|
+
return await doDownloadAndInstall()
|
|
568
672
|
}
|
|
569
673
|
} catch (error) {
|
|
570
|
-
syncStatusChangeCallback(CodePush.SyncStatus.UNKNOWN_ERROR)
|
|
571
|
-
log(error.message)
|
|
572
|
-
throw error
|
|
674
|
+
syncStatusChangeCallback(CodePush.SyncStatus.UNKNOWN_ERROR)
|
|
675
|
+
log(error.message)
|
|
676
|
+
throw error
|
|
573
677
|
}
|
|
574
|
-
}
|
|
678
|
+
}
|
|
575
679
|
|
|
576
|
-
let CodePush
|
|
680
|
+
let CodePush
|
|
577
681
|
|
|
578
682
|
/**
|
|
579
683
|
* @callback releaseHistoryFetcher
|
|
@@ -601,105 +705,145 @@ let CodePush;
|
|
|
601
705
|
const sharedCodePushOptions = {
|
|
602
706
|
releaseHistoryFetcher: undefined,
|
|
603
707
|
setReleaseHistoryFetcher(releaseHistoryFetcherFunction) {
|
|
604
|
-
if (
|
|
605
|
-
|
|
708
|
+
if (
|
|
709
|
+
!releaseHistoryFetcherFunction ||
|
|
710
|
+
typeof releaseHistoryFetcherFunction !== 'function'
|
|
711
|
+
)
|
|
712
|
+
throw new Error('Please implement the releaseHistoryFetcher function')
|
|
713
|
+
this.releaseHistoryFetcher = releaseHistoryFetcherFunction
|
|
606
714
|
},
|
|
607
715
|
updateChecker: undefined,
|
|
608
716
|
setUpdateChecker(updateCheckerFunction) {
|
|
609
|
-
if (!updateCheckerFunction) return
|
|
610
|
-
if (typeof updateCheckerFunction !== 'function')
|
|
611
|
-
|
|
717
|
+
if (!updateCheckerFunction) return
|
|
718
|
+
if (typeof updateCheckerFunction !== 'function')
|
|
719
|
+
throw new Error('Please pass a function to updateChecker')
|
|
720
|
+
this.updateChecker = updateCheckerFunction
|
|
612
721
|
},
|
|
613
722
|
}
|
|
614
723
|
|
|
615
724
|
function codePushify(options = {}) {
|
|
616
|
-
let React
|
|
617
|
-
let ReactNative = require(
|
|
725
|
+
let React
|
|
726
|
+
let ReactNative = require('react-native')
|
|
618
727
|
|
|
619
|
-
try {
|
|
728
|
+
try {
|
|
729
|
+
React = require('react')
|
|
730
|
+
} catch (e) {}
|
|
620
731
|
if (!React) {
|
|
621
|
-
try {
|
|
732
|
+
try {
|
|
733
|
+
React = ReactNative.React
|
|
734
|
+
} catch (e) {}
|
|
622
735
|
if (!React) {
|
|
623
|
-
throw new Error("Unable to find the 'React' module.")
|
|
736
|
+
throw new Error("Unable to find the 'React' module.")
|
|
624
737
|
}
|
|
625
738
|
}
|
|
626
739
|
|
|
627
740
|
if (!React.Component) {
|
|
628
741
|
throw new Error(
|
|
629
|
-
`Unable to find the "Component" class, please either:
|
|
742
|
+
`Unable to find the "Component" class, please either:
|
|
630
743
|
1. Upgrade to a newer version of React Native that supports it, or
|
|
631
744
|
2. Call the codePush.sync API in your component instead of using the @codePush decorator`
|
|
632
|
-
)
|
|
745
|
+
)
|
|
633
746
|
}
|
|
634
747
|
|
|
635
748
|
if (options.updateChecker && !options.releaseHistoryFetcher) {
|
|
636
|
-
throw new Error(
|
|
749
|
+
throw new Error(
|
|
750
|
+
'If you want to use `updateChecker`, pass a no-op function to releaseHistoryFetcher option. (e.g. `releaseHistoryFetcher: async () => ({})`)'
|
|
751
|
+
)
|
|
637
752
|
}
|
|
638
753
|
|
|
639
|
-
sharedCodePushOptions.setReleaseHistoryFetcher(options.releaseHistoryFetcher)
|
|
640
|
-
sharedCodePushOptions.setUpdateChecker(options.updateChecker)
|
|
754
|
+
sharedCodePushOptions.setReleaseHistoryFetcher(options.releaseHistoryFetcher)
|
|
755
|
+
sharedCodePushOptions.setUpdateChecker(options.updateChecker)
|
|
641
756
|
|
|
642
757
|
const decorator = (RootComponent) => {
|
|
643
758
|
class CodePushComponent extends React.Component {
|
|
644
759
|
constructor(props) {
|
|
645
|
-
super(props)
|
|
646
|
-
this.rootComponentRef = React.createRef()
|
|
760
|
+
super(props)
|
|
761
|
+
this.rootComponentRef = React.createRef()
|
|
647
762
|
}
|
|
648
763
|
|
|
649
764
|
componentDidMount() {
|
|
650
765
|
if (options.checkFrequency === CodePush.CheckFrequency.MANUAL) {
|
|
651
|
-
CodePush.notifyAppReady()
|
|
766
|
+
CodePush.notifyAppReady()
|
|
652
767
|
} else {
|
|
653
|
-
const rootComponentInstance = this.rootComponentRef.current
|
|
654
|
-
|
|
655
|
-
let syncStatusCallback
|
|
656
|
-
if (
|
|
657
|
-
|
|
768
|
+
const rootComponentInstance = this.rootComponentRef.current
|
|
769
|
+
|
|
770
|
+
let syncStatusCallback
|
|
771
|
+
if (
|
|
772
|
+
rootComponentInstance &&
|
|
773
|
+
rootComponentInstance.codePushStatusDidChange
|
|
774
|
+
) {
|
|
775
|
+
syncStatusCallback =
|
|
776
|
+
rootComponentInstance.codePushStatusDidChange.bind(
|
|
777
|
+
rootComponentInstance
|
|
778
|
+
)
|
|
658
779
|
}
|
|
659
780
|
|
|
660
|
-
let downloadProgressCallback
|
|
661
|
-
if (
|
|
662
|
-
|
|
781
|
+
let downloadProgressCallback
|
|
782
|
+
if (
|
|
783
|
+
rootComponentInstance &&
|
|
784
|
+
rootComponentInstance.codePushDownloadDidProgress
|
|
785
|
+
) {
|
|
786
|
+
downloadProgressCallback =
|
|
787
|
+
rootComponentInstance.codePushDownloadDidProgress.bind(
|
|
788
|
+
rootComponentInstance
|
|
789
|
+
)
|
|
663
790
|
}
|
|
664
791
|
|
|
665
|
-
let handleBinaryVersionMismatchCallback
|
|
666
|
-
if (
|
|
667
|
-
|
|
792
|
+
let handleBinaryVersionMismatchCallback
|
|
793
|
+
if (
|
|
794
|
+
rootComponentInstance &&
|
|
795
|
+
rootComponentInstance.codePushOnBinaryVersionMismatch
|
|
796
|
+
) {
|
|
797
|
+
handleBinaryVersionMismatchCallback =
|
|
798
|
+
rootComponentInstance.codePushOnBinaryVersionMismatch.bind(
|
|
799
|
+
rootComponentInstance
|
|
800
|
+
)
|
|
668
801
|
}
|
|
669
802
|
|
|
670
|
-
CodePush.sync(
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
803
|
+
CodePush.sync(
|
|
804
|
+
options,
|
|
805
|
+
syncStatusCallback,
|
|
806
|
+
downloadProgressCallback,
|
|
807
|
+
handleBinaryVersionMismatchCallback
|
|
808
|
+
)
|
|
809
|
+
|
|
810
|
+
if (
|
|
811
|
+
options.checkFrequency === CodePush.CheckFrequency.ON_APP_RESUME
|
|
812
|
+
) {
|
|
813
|
+
ReactNative.AppState.addEventListener('change', (newState) => {
|
|
814
|
+
if (newState === 'active') {
|
|
815
|
+
CodePush.sync(
|
|
816
|
+
options,
|
|
817
|
+
syncStatusCallback,
|
|
818
|
+
downloadProgressCallback
|
|
819
|
+
)
|
|
676
820
|
}
|
|
677
|
-
})
|
|
821
|
+
})
|
|
678
822
|
}
|
|
679
823
|
}
|
|
680
824
|
}
|
|
681
825
|
|
|
682
826
|
render() {
|
|
683
|
-
const props = {...this.props}
|
|
827
|
+
const props = { ...this.props }
|
|
684
828
|
|
|
685
829
|
// We can set ref property on class components only (not stateless)
|
|
686
830
|
// Check it by render method
|
|
687
831
|
if (RootComponent.prototype && RootComponent.prototype.render) {
|
|
688
|
-
props.ref = this.rootComponentRef
|
|
832
|
+
props.ref = this.rootComponentRef
|
|
689
833
|
}
|
|
690
834
|
|
|
691
835
|
return <RootComponent {...props} />
|
|
692
836
|
}
|
|
693
837
|
}
|
|
694
838
|
|
|
695
|
-
return hoistStatics(CodePushComponent, RootComponent)
|
|
839
|
+
return hoistStatics(CodePushComponent, RootComponent)
|
|
696
840
|
}
|
|
697
841
|
|
|
698
|
-
if (typeof options ===
|
|
842
|
+
if (typeof options === 'function') {
|
|
699
843
|
// Infer that the root component was directly passed to us.
|
|
700
|
-
return decorator(options)
|
|
844
|
+
return decorator(options)
|
|
701
845
|
} else {
|
|
702
|
-
return decorator
|
|
846
|
+
return decorator
|
|
703
847
|
}
|
|
704
848
|
}
|
|
705
849
|
|
|
@@ -708,7 +852,7 @@ function codePushify(options = {}) {
|
|
|
708
852
|
// and therefore, it doesn't make sense initializing
|
|
709
853
|
// the JS interface when it wouldn't work anyways.
|
|
710
854
|
if (NativeCodePush) {
|
|
711
|
-
CodePush = codePushify
|
|
855
|
+
CodePush = codePushify
|
|
712
856
|
Object.assign(CodePush, {
|
|
713
857
|
checkForUpdate,
|
|
714
858
|
getConfiguration,
|
|
@@ -727,7 +871,7 @@ if (NativeCodePush) {
|
|
|
727
871
|
IMMEDIATE: NativeCodePush.codePushInstallModeImmediate, // Restart the app immediately
|
|
728
872
|
ON_NEXT_RESTART: NativeCodePush.codePushInstallModeOnNextRestart, // Don't artificially restart the app. Allow the update to be "picked up" on the next app restart
|
|
729
873
|
ON_NEXT_RESUME: NativeCodePush.codePushInstallModeOnNextResume, // Restart the app the next time it is resumed from the background
|
|
730
|
-
ON_NEXT_SUSPEND: NativeCodePush.codePushInstallModeOnNextSuspend // Restart the app _while_ it is in the background,
|
|
874
|
+
ON_NEXT_SUSPEND: NativeCodePush.codePushInstallModeOnNextSuspend, // Restart the app _while_ it is in the background,
|
|
731
875
|
// but only after it has been in the background for "minimumBackgroundDuration" seconds (0 by default),
|
|
732
876
|
// so that user context isn't lost unless the app suspension is long enough to not matter
|
|
733
877
|
},
|
|
@@ -740,39 +884,42 @@ if (NativeCodePush) {
|
|
|
740
884
|
CHECKING_FOR_UPDATE: 5,
|
|
741
885
|
AWAITING_USER_ACTION: 6,
|
|
742
886
|
DOWNLOADING_PACKAGE: 7,
|
|
743
|
-
INSTALLING_UPDATE: 8
|
|
887
|
+
INSTALLING_UPDATE: 8,
|
|
744
888
|
},
|
|
745
889
|
CheckFrequency: {
|
|
746
890
|
ON_APP_START: 0,
|
|
747
891
|
ON_APP_RESUME: 1,
|
|
748
|
-
MANUAL: 2
|
|
892
|
+
MANUAL: 2,
|
|
749
893
|
},
|
|
750
894
|
UpdateState: {
|
|
751
895
|
RUNNING: NativeCodePush.codePushUpdateStateRunning,
|
|
752
896
|
PENDING: NativeCodePush.codePushUpdateStatePending,
|
|
753
|
-
LATEST: NativeCodePush.codePushUpdateStateLatest
|
|
897
|
+
LATEST: NativeCodePush.codePushUpdateStateLatest,
|
|
754
898
|
},
|
|
755
899
|
DeploymentStatus: {
|
|
756
|
-
FAILED:
|
|
757
|
-
SUCCEEDED:
|
|
900
|
+
FAILED: 'DeploymentFailed',
|
|
901
|
+
SUCCEEDED: 'DeploymentSucceeded',
|
|
758
902
|
},
|
|
759
903
|
DEFAULT_UPDATE_DIALOG: {
|
|
760
904
|
appendReleaseDescription: false,
|
|
761
|
-
descriptionPrefix:
|
|
762
|
-
mandatoryContinueButtonLabel:
|
|
763
|
-
mandatoryUpdateMessage:
|
|
764
|
-
optionalIgnoreButtonLabel:
|
|
765
|
-
optionalInstallButtonLabel:
|
|
766
|
-
optionalUpdateMessage:
|
|
767
|
-
|
|
905
|
+
descriptionPrefix: ' Description: ',
|
|
906
|
+
mandatoryContinueButtonLabel: 'Continue',
|
|
907
|
+
mandatoryUpdateMessage: 'An update is available that must be installed.',
|
|
908
|
+
optionalIgnoreButtonLabel: 'Ignore',
|
|
909
|
+
optionalInstallButtonLabel: 'Install',
|
|
910
|
+
optionalUpdateMessage:
|
|
911
|
+
'An update is available. Would you like to install it?',
|
|
912
|
+
title: 'Update available',
|
|
768
913
|
},
|
|
769
914
|
DEFAULT_ROLLBACK_RETRY_OPTIONS: {
|
|
770
915
|
delayInHours: 24,
|
|
771
|
-
maxRetryAttempts: 1
|
|
916
|
+
maxRetryAttempts: 1,
|
|
772
917
|
},
|
|
773
|
-
})
|
|
918
|
+
})
|
|
774
919
|
} else {
|
|
775
|
-
log(
|
|
920
|
+
log(
|
|
921
|
+
"The CodePush module doesn't appear to be properly installed. Please double-check that everything is setup correctly."
|
|
922
|
+
)
|
|
776
923
|
}
|
|
777
924
|
|
|
778
|
-
module.exports = CodePush
|
|
925
|
+
module.exports = CodePush
|
package/cli/commands/common.js
CHANGED
|
@@ -3,12 +3,12 @@ const path = require('path')
|
|
|
3
3
|
|
|
4
4
|
async function createPullRequestHistory(
|
|
5
5
|
setReleaseHistory,
|
|
6
|
-
|
|
6
|
+
binaryVersion,
|
|
7
7
|
app,
|
|
8
8
|
platform
|
|
9
9
|
) {
|
|
10
10
|
try {
|
|
11
|
-
const JSON_FILE_NAME = `${
|
|
11
|
+
const JSON_FILE_NAME = `${binaryVersion}.json`
|
|
12
12
|
const JSON_FILE_PATH = path.resolve(process.cwd(), JSON_FILE_NAME)
|
|
13
13
|
|
|
14
14
|
console.log(
|
|
@@ -17,7 +17,7 @@ async function createPullRequestHistory(
|
|
|
17
17
|
)
|
|
18
18
|
fs.writeFileSync(JSON_FILE_PATH, JSON.stringify({}))
|
|
19
19
|
|
|
20
|
-
await setReleaseHistory(
|
|
20
|
+
await setReleaseHistory(binaryVersion, JSON_FILE_PATH, {}, app, platform)
|
|
21
21
|
|
|
22
22
|
fs.unlinkSync(JSON_FILE_PATH)
|
|
23
23
|
} catch (error) {
|
|
@@ -8,7 +8,6 @@ program
|
|
|
8
8
|
.description('Creates a new pull request history.')
|
|
9
9
|
.option('-a, --app <string>', 'target app (user/device)')
|
|
10
10
|
.option('-p, --platform <string>', 'target platform (ios/android)')
|
|
11
|
-
.option('-r, --pr-number <number>', 'pull request number')
|
|
12
11
|
.option(
|
|
13
12
|
'-c, --config <path>',
|
|
14
13
|
'set config file name (JS/TS)',
|
|
@@ -22,7 +21,7 @@ program
|
|
|
22
21
|
|
|
23
22
|
await createPullRequestHistory(
|
|
24
23
|
setReleaseHistory,
|
|
25
|
-
options.
|
|
24
|
+
options.binaryVersion,
|
|
26
25
|
options.app,
|
|
27
26
|
options.platform
|
|
28
27
|
)
|
|
@@ -13,12 +13,17 @@ async function addToPullRequestRelease(
|
|
|
13
13
|
setReleaseHistory,
|
|
14
14
|
getReleaseHistory
|
|
15
15
|
) {
|
|
16
|
-
const releaseHistory = await getReleaseHistory(app,
|
|
17
|
-
const latestReleaseHistoryNumber = Object.keys(releaseHistory).at(-1)
|
|
16
|
+
const releaseHistory = await getReleaseHistory(app, binaryVersion, platform)
|
|
18
17
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
const latestReleaseHistoryKeys = Object.keys(releaseHistory)
|
|
19
|
+
const releaseHistoryWithPRNumber = latestReleaseHistoryKeys.filter((key) =>
|
|
20
|
+
key.includes(prNumber)
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const newReleaseHistoryNumber = getNewReleaseHistoryNumber(
|
|
24
|
+
releaseHistoryWithPRNumber,
|
|
25
|
+
prNumber
|
|
26
|
+
)
|
|
22
27
|
const newReleaseHistory = structuredClone(releaseHistory)
|
|
23
28
|
|
|
24
29
|
newReleaseHistory[newReleaseHistoryNumber] = {
|
|
@@ -30,7 +35,7 @@ async function addToPullRequestRelease(
|
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
try {
|
|
33
|
-
const JSON_FILE_NAME = `${
|
|
38
|
+
const JSON_FILE_NAME = `${binaryVersion}.json`
|
|
34
39
|
const JSON_FILE_PATH = path.resolve(process.cwd(), JSON_FILE_NAME)
|
|
35
40
|
|
|
36
41
|
console.log(
|
|
@@ -40,12 +45,13 @@ async function addToPullRequestRelease(
|
|
|
40
45
|
fs.writeFileSync(JSON_FILE_PATH, JSON.stringify(newReleaseHistory))
|
|
41
46
|
|
|
42
47
|
await setReleaseHistory(
|
|
43
|
-
|
|
48
|
+
binaryVersion,
|
|
44
49
|
JSON_FILE_PATH,
|
|
45
50
|
newReleaseHistory,
|
|
46
51
|
app,
|
|
47
52
|
platform
|
|
48
53
|
)
|
|
54
|
+
process.stdout.write(packageHash)
|
|
49
55
|
} catch (error) {
|
|
50
56
|
console.error('Error occurred while updating history:', error)
|
|
51
57
|
process.exit(1)
|
|
@@ -55,3 +61,13 @@ async function addToPullRequestRelease(
|
|
|
55
61
|
module.exports = {
|
|
56
62
|
addToPullRequestRelease,
|
|
57
63
|
}
|
|
64
|
+
|
|
65
|
+
function getNewReleaseHistoryNumber(releaseHistoryWithPRNumber, prNumber) {
|
|
66
|
+
if (releaseHistoryWithPRNumber.length) {
|
|
67
|
+
const [, latestVersion] = releaseHistoryWithPRNumber.at(-1).split('-')
|
|
68
|
+
const newVersion = `${prNumber}-${Number(latestVersion[0]) + 1}.0.0`
|
|
69
|
+
return newVersion
|
|
70
|
+
} else {
|
|
71
|
+
return `${prNumber}-1.0.0`
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -22,7 +22,7 @@ program
|
|
|
22
22
|
)
|
|
23
23
|
.option('-a, --app <string>', 'target app (user/device)')
|
|
24
24
|
.option('-p, --platform <string>', 'target platform (ios/android)')
|
|
25
|
-
.option('-i, --identifier <string>', 'target env identifier (stg/prd)')
|
|
25
|
+
.option('-i, --identifier <string>', 'target env identifier (dev/stg/prd)')
|
|
26
26
|
.option('-b, --binary-version <string>', 'target binary version (x.y.z)')
|
|
27
27
|
.option('-v, --app-version <string>', 'target codepush version (x.y.z)')
|
|
28
28
|
.option(
|
|
@@ -67,8 +67,11 @@ program
|
|
|
67
67
|
throw new Error('Device app is not supported on iOS')
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
if (
|
|
71
|
-
|
|
70
|
+
if (
|
|
71
|
+
options.identifier &&
|
|
72
|
+
!['dev', 'stg', 'prd'].includes(options.identifier)
|
|
73
|
+
) {
|
|
74
|
+
throw new Error('Identifier must be either "dev" or "stg" or "prd"')
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
const semverRegex = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/
|
package/cli/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
const { program } = require('commander')
|
|
2
|
-
const { findAndReadConfigFile } = require('../../utils/fsUtils')
|
|
3
|
-
const { COMPILED_CONFIG_FILE_NAME } = require('../../constant')
|
|
4
|
-
|
|
5
|
-
program
|
|
6
|
-
.command('get-development-key')
|
|
7
|
-
.description('the development key for a specific app and platform.')
|
|
8
|
-
.option('-a, --app <string>', 'target app (user/device)')
|
|
9
|
-
.option('-p, --platform <string>', 'target platform (ios/android)')
|
|
10
|
-
.option('-b, --binary-version <string>', 'target binary version (x.y.z)')
|
|
11
|
-
.option('-r, --pr-number <number>', 'pull request number')
|
|
12
|
-
.option(
|
|
13
|
-
'-c, --config <path>',
|
|
14
|
-
'configuration file name (JS/TS)',
|
|
15
|
-
COMPILED_CONFIG_FILE_NAME
|
|
16
|
-
)
|
|
17
|
-
.action(async (options) => {
|
|
18
|
-
const { getReleaseHistory } = await findAndReadConfigFile(
|
|
19
|
-
process.cwd(),
|
|
20
|
-
options.config
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
const releaseHistory = await getReleaseHistory(
|
|
24
|
-
options.app,
|
|
25
|
-
options.binaryVersion || options.prNumber,
|
|
26
|
-
options.platform
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
const latestReleaseVersion = Object.keys(releaseHistory).at(-1)
|
|
30
|
-
process.stdout.write(releaseHistory[latestReleaseVersion].packageHash)
|
|
31
|
-
})
|