diff --git a/lib/config.ts b/lib/config.ts index a3e7ec4..a5d95b0 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -14,7 +14,7 @@ limitations under the License. */ -import { ActionsConfig } from './types'; +import type { ActionsConfig } from './types'; export const actionsConfig: ActionsConfig = { actions: { @@ -82,6 +82,13 @@ export const actionsConfig: ActionsConfig = { minSourceVersion: '2.7.4', }, }, + 'jetson-xavier-nx-devkit-emmc': { + takeover: { + // NOTE: this version is here as a placeholder for + // testing. Replace with the correct version before merging + minTargetVersion: '5.1.45+rev1', + }, + }, qemux86: { balenahup: { minSourceVersion: '2.9.3', diff --git a/lib/index.ts b/lib/index.ts index 41077f2..054a78e 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -17,7 +17,7 @@ import * as bSemver from 'balena-semver'; import { TypedError } from 'typed-error'; import { actionsConfig as defaultActionsConfig } from './config'; -import { ActionName, ActionsConfig } from './types'; +import type { ActionName, ActionsConfig } from './types'; export { actionsConfig } from './config'; export * from './types'; @@ -120,8 +120,13 @@ export class HUPActionHelper { ); } } else { + // Takeover overrides the checks below for the device type + if (this.isTakeoverRequired(deviceType, currentVersion, targetVersion)) { + return 'takeover'; + } actionName = 'balenahup'; } + const { actionsConfig } = this; const defaultActions = actionsConfig.deviceTypesDefaults; const deviceActions = actionsConfig.deviceTypes[deviceType] || {}; @@ -177,6 +182,27 @@ export class HUPActionHelper { return actionName; } + private isTakeoverRequired( + deviceType: string, + currentVersion: string, + targetVersion: string, + ) { + const { actionsConfig } = this; + const deviceActions = actionsConfig.deviceTypes[deviceType] || {}; + + if (deviceActions.takeover == null) { + return false; + } + + const { minTargetVersion } = deviceActions.takeover; + if ( + bSemver.lt(currentVersion, minTargetVersion) && + bSemver.gte(targetVersion, minTargetVersion) + ) { + return true; + } + } + /** * @summary Returns whether the provided device type supports OS updates between the current and target balenaOS versions * @name isSupportedOsUpdate diff --git a/lib/types.ts b/lib/types.ts index 24408d8..53fafaf 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -27,10 +27,17 @@ export interface ActionConfig { maxTargetVersion?: string; } +// The per device configuration can override the version configuration of the +// action, or define a 'takeover' version when a jump between two versions +// cannot be done with balenahup, but needs a full re-flash +type DeviceTypeConfig = { + [K in ActionName]?: Partial; +} & { takeover?: Pick }; + export interface ActionsConfig { actions: { [K in ActionName]: ActionConfig }; deviceTypesDefaults: { [K in ActionName]?: Partial }; deviceTypes: Partial<{ - [deviceTypeSlug: string]: { [K in ActionName]?: Partial }; + [deviceTypeSlug: string]: DeviceTypeConfig; }>; } diff --git a/tests/01-actions.spec.ts b/tests/01-actions.spec.ts index 0bd7a70..9969c06 100644 --- a/tests/01-actions.spec.ts +++ b/tests/01-actions.spec.ts @@ -729,5 +729,35 @@ describe('BalenaHupActionUtils', () => { ).to.equal('balenahup'); }); }); + + describe('takeover', () => { + [ + { + deviceType: 'jetson-xavier-nx-devkit-emmc', + before: '5.0.0', + cutoff: '5.1.45', + takeover: '5.1.45+rev1', + after: '5.2.0', + }, + ].forEach(({ deviceType, before, cutoff, takeover, after }) => { + it(`should return 'balenahup' if doing HUP for ${deviceType} to a version before ${takeover}`, () => { + expect( + hupActionHelper.getHUPActionType(deviceType, before, cutoff), + ).to.equal('balenahup'); + }); + + it(`should return 'takeover' if doing HUP for ${deviceType} to a version after ${takeover}`, () => { + expect( + hupActionHelper.getHUPActionType(deviceType, before, after), + ).to.equal('takeover'); + }); + + it(`should return 'balenahup' if doing HUP for ${deviceType} from a version after ${takeover}`, () => { + expect( + hupActionHelper.getHUPActionType(deviceType, takeover, after), + ).to.equal('balenahup'); + }); + }); + }); }); });