@bravemobile/react-native-code-push
Version:
React Native plugin for the CodePush service
138 lines (115 loc) • 4.09 kB
JavaScript
/**
* @type {BaseVersioning}
*/
class BaseVersioning {
/**
* @param {ReleaseHistoryInterface} releaseHistory
* @param {SortingMethod} sortingMethod
*/
constructor(releaseHistory, sortingMethod) {
if (this.constructor == BaseVersioning) {
throw new Error("Abstract classes can't be instantiated.");
}
if (releaseHistory == null || sortingMethod == null) {
throw new Error("param releaseHistory and sortingMethod is needed");
}
/** @type {SortingMethod} */
this.sortingMethod = sortingMethod;
/** @type {ReleaseHistoryInterface} */
this.originalReleaseHistory = releaseHistory;
/** @type {[ReleaseVersion, ReleaseInfo][]} */
this.sortedReleaseHistory = Object.entries(releaseHistory).sort(
([a], [b]) => this.sortingMethod(a, b)
);
/** @type {boolean} */
this.isLatestReleaseInRollout = true;
}
/**
* @return {[ReleaseVersion, ReleaseInfo][]}
*/
get sortedEnabledReleaseHistory() {
const list = this.sortedReleaseHistory.filter(([_, bundle]) => bundle.enabled)
// If the latest release is not a rollout target, exclude it from the list.
// - This also means that rollout deployment can only be applied to the latest release.
return this.isLatestReleaseInRollout ? list : list.slice(1);
}
/**
* @return {[ReleaseVersion, ReleaseInfo][]}
*/
get sortedMandatoryReleaseHistory() {
return this.sortedEnabledReleaseHistory.filter(
([_, bundle]) => bundle.mandatory
);
}
/** @param isLatestReleaseInRollout {boolean} */
setIsLatestReleaseInRollout(isLatestReleaseInRollout) {
this.isLatestReleaseInRollout = isLatestReleaseInRollout;
}
/**
* find latest release in releaseHistory
* @return {[ReleaseVersion, ReleaseInfo]}
*/
findLatestRelease() {
const latestReleaseInfo = this.sortedEnabledReleaseHistory.at(0);
if (!latestReleaseInfo) {
throw new Error("There is no latest release.");
}
return latestReleaseInfo;
}
/**
* check if the update is mandatory
* @param {ReleaseVersion|undefined} runtimeVersion
* @return {boolean}
*/
checkIsMandatory(runtimeVersion) {
if (this.shouldRollback(runtimeVersion)) {
// rollback is always mandatory
return true;
}
if (this.sortedMandatoryReleaseHistory.length === 0) {
return false;
}
if (!runtimeVersion) {
// This means that there is at least one mandatory update, but the update has not been installed yet.
// So, the update is mandatory.
return true;
}
const [latestMandatoryVersion, _] = this.sortedMandatoryReleaseHistory[0];
const [larger] = [latestMandatoryVersion, runtimeVersion].sort(this.sortingMethod);
return runtimeVersion !== latestMandatoryVersion && larger === latestMandatoryVersion;
}
/**
* determine whether to rollback and execute it
* @param {ReleaseVersion|undefined} runtimeVersion
* @return {boolean}
*/
shouldRollback(runtimeVersion) {
if (!runtimeVersion) {
// Rollback is not possible because no updates have been installed.
return false;
}
const [latestRelease] = this.findLatestRelease();
const [larger] = [latestRelease, runtimeVersion].sort(this.sortingMethod);
return runtimeVersion !== latestRelease && larger === runtimeVersion;
}
/**
* Determine whether to clear the currently running bundle.
* If it returns true, the CodePush bundle will be erased, and the app will restart.
* @param {ReleaseVersion} runtimeVersion
* @return {boolean}
*/
shouldRollbackToBinary(runtimeVersion) {
if (!runtimeVersion) {
// Rollback is not possible because no updates have been installed.
return false;
}
const [latestReleaseVersion] = this.findLatestRelease();
const [binaryAppVersion] = this.sortedReleaseHistory.at(-1);
return (
runtimeVersion !== latestReleaseVersion &&
this.shouldRollback(runtimeVersion) &&
latestReleaseVersion === binaryAppVersion
);
}
}
module.exports = { BaseVersioning: BaseVersioning };