diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md
index a192896fb..5b0ee38ec 100644
--- a/DOCUMENTATION.md
+++ b/DOCUMENTATION.md
@@ -305,6 +305,7 @@ const sdk = fromSharedOptions();
* [.isArchitectureCompatibleWith(osArchitecture, applicationArchitecture)](#balena.models.os.isArchitectureCompatibleWith) ⇒ Boolean
* [.hostapp](#balena.models.hostapp) : object
* [.getAllOsVersions(deviceTypes)](#balena.models.hostapp.getAllOsVersions) ⇒ Promise
+ * [.getLatestOsVersions(deviceTypes)](#balena.models.hostapp.getLatestOsVersions) ⇒ Promise
* [.config](#balena.models.config) : object
* [.getAll()](#balena.models.config.getAll) ⇒ Promise
* ~~[.getDeviceTypes()](#balena.models.config.getDeviceTypes) ⇒ Promise
~~
@@ -671,6 +672,7 @@ balena.models.device.get(123).catch(function (error) {
* [.isArchitectureCompatibleWith(osArchitecture, applicationArchitecture)](#balena.models.os.isArchitectureCompatibleWith) ⇒ Boolean
* [.hostapp](#balena.models.hostapp) : object
* [.getAllOsVersions(deviceTypes)](#balena.models.hostapp.getAllOsVersions) ⇒ Promise
+ * [.getLatestOsVersions(deviceTypes)](#balena.models.hostapp.getLatestOsVersions) ⇒ Promise
* [.config](#balena.models.config) : object
* [.getAll()](#balena.models.config.getAll) ⇒ Promise
* ~~[.getDeviceTypes()](#balena.models.config.getDeviceTypes) ⇒ Promise
~~
@@ -6273,6 +6275,11 @@ console.log(result2);
**Beta** The hostapp methods are still in beta and might change in a non-major release.
**Kind**: static namespace of [models
](#balena.models)
+
+* [.hostapp](#balena.models.hostapp) : object
+ * [.getAllOsVersions(deviceTypes)](#balena.models.hostapp.getAllOsVersions) ⇒ Promise
+ * [.getLatestOsVersions(deviceTypes)](#balena.models.hostapp.getLatestOsVersions) ⇒ Promise
+
##### hostapp.getAllOsVersions(deviceTypes) ⇒ Promise
@@ -6288,6 +6295,21 @@ console.log(result2);
```js
balena.models.hostapp.getAllOsVersions(['fincm3', 'raspberrypi3']);
```
+
+
+##### hostapp.getLatestOsVersions(deviceTypes) ⇒ Promise
+**Kind**: static method of [hostapp
](#balena.models.hostapp)
+**Summary**: Get latest OS versions for the passed device types
+**Access**: public
+
+| Param | Type | Description |
+| --- | --- | --- |
+| deviceTypes | Array.<String>
| device type slugs |
+
+**Example**
+```js
+balena.models.hostapp.getLatestOsVersions(['fincm3', 'raspberrypi3']);
+```
#### models.config : object
diff --git a/lib/models/hostapp.ts b/lib/models/hostapp.ts
index 27fa09ee6..21dbc7a73 100644
--- a/lib/models/hostapp.ts
+++ b/lib/models/hostapp.ts
@@ -9,6 +9,7 @@ import type {
} from '../types/models';
import { Dictionary } from '../../typings/utils';
import { getAuthDependentMemoize } from '../util/cache';
+import { maxSatisfying } from 'semver';
const RELEASE_POLICY_TAG_NAME = 'release-policy';
const ESR_NEXT_TAG_NAME = 'esr-next';
@@ -161,6 +162,12 @@ const getHostappModel = function (deps: InjectedDependenciesParam) {
return res;
};
+ const mapVersions = (versions: OsVersion[], type: OsTypes) => {
+ return versions
+ .filter((version) => version.osType === type)
+ .map((v) => v.strippedVersion);
+ };
+
// This mutates the passed object.
const transformVersionSets = (
osVersionsByDeviceType: OsVersionsByDeviceType,
@@ -261,9 +268,49 @@ const getHostappModel = function (deps: InjectedDependenciesParam) {
return memoizedGetTransformedOsVersions(sortedDeviceTypes);
};
+ /**
+ * @summary Get latest OS versions for the passed device types
+ * @name getLatestOsVersions
+ * @public
+ * @function
+ * @memberof balena.models.hostapp
+ *
+ * @param {String[]} deviceTypes - device type slugs
+ * @returns {Promise}
+ *
+ * @example
+ * balena.models.hostapp.getLatestOsVersions(['fincm3', 'raspberrypi3']);
+ */
+ const getLatestOsVersions = async (
+ deviceTypes: string[],
+ ): Promise => {
+ const allOsVersions = await getAllOsVersions(deviceTypes);
+ return Object.entries(allOsVersions).reduce(
+ (osVersionsByDeviceType: OsVersionsByDeviceType, [key, versions]) => {
+ const latestOSVersion = maxSatisfying(
+ mapVersions(versions, OsTypes.DEFAULT),
+ '>0.0.0',
+ );
+ const latestESRVersion = maxSatisfying(
+ mapVersions(versions, OsTypes.ESR),
+ '>0.0.0',
+ );
+ const filteredVersions = versions.filter(
+ (v) =>
+ v.strippedVersion === latestOSVersion ||
+ v.strippedVersion === latestESRVersion,
+ )!;
+ osVersionsByDeviceType[key] = filteredVersions;
+ return osVersionsByDeviceType;
+ },
+ {},
+ );
+ };
+
return {
OsTypes,
getAllOsVersions,
+ getLatestOsVersions,
};
};
diff --git a/tests/integration/models/hostapp.spec.ts b/tests/integration/models/hostapp.spec.ts
index 9659f09e1..634f5f8fe 100644
--- a/tests/integration/models/hostapp.spec.ts
+++ b/tests/integration/models/hostapp.spec.ts
@@ -75,4 +75,22 @@ describe('Hostapp model', function () {
expect(firstRes).to.equal(secondRes);
});
});
+
+ parallel('balena.models.hostapp.getLatestOsVersions()', function () {
+ it('should contain latest balenaOS and balenaOS ESR OS types', async () => {
+ const res = await balena.models.hostapp.getLatestOsVersions([
+ 'fincm3',
+ 'raspberrypi3',
+ ]);
+
+ ['fincm3', 'raspberrypi3'].forEach((key) => {
+ expect(res[key]).to.be.an('Array');
+ expect(res[key]).to.have.lengthOf(4);
+ expect(res[key].filter((r) => r.osType === 'esr')).to.have.lengthOf(2);
+ expect(res[key].filter((r) => r.osType === 'default')).to.have.lengthOf(
+ 2,
+ );
+ });
+ });
+ });
});