diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index d2151ce01..464534ba9 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -367,7 +367,7 @@ const sdk = fromSharedOptions(); * [.download(options)](#balena.models.os.download) ⇒ Promise * [.getConfig(slugOrUuidOrId, options)](#balena.models.os.getConfig) ⇒ Promise * [.isSupportedOsUpdate(deviceType, currentVersion, targetVersion)](#balena.models.os.isSupportedOsUpdate) ⇒ Promise - * [.getSupportedOsUpdateVersions(deviceType, currentVersion)](#balena.models.os.getSupportedOsUpdateVersions) ⇒ Promise + * [.getSupportedOsUpdateVersions(deviceType, currentVersion, [options])](#balena.models.os.getSupportedOsUpdateVersions) ⇒ Promise * [.isArchitectureCompatibleWith(osArchitecture, applicationArchitecture)](#balena.models.os.isArchitectureCompatibleWith) ⇒ Boolean * [.getSupervisorImageForDeviceType(deviceTypeId, version)](#balena.models.os.getSupervisorImageForDeviceType) ⇒ Promise.<String> * [.config](#balena.models.config) : object @@ -774,7 +774,7 @@ balena.models.device.get(123).catch(function (error) { * [.download(options)](#balena.models.os.download) ⇒ Promise * [.getConfig(slugOrUuidOrId, options)](#balena.models.os.getConfig) ⇒ Promise * [.isSupportedOsUpdate(deviceType, currentVersion, targetVersion)](#balena.models.os.isSupportedOsUpdate) ⇒ Promise - * [.getSupportedOsUpdateVersions(deviceType, currentVersion)](#balena.models.os.getSupportedOsUpdateVersions) ⇒ Promise + * [.getSupportedOsUpdateVersions(deviceType, currentVersion, [options])](#balena.models.os.getSupportedOsUpdateVersions) ⇒ Promise * [.isArchitectureCompatibleWith(osArchitecture, applicationArchitecture)](#balena.models.os.isArchitectureCompatibleWith) ⇒ Boolean * [.getSupervisorImageForDeviceType(deviceTypeId, version)](#balena.models.os.getSupervisorImageForDeviceType) ⇒ Promise.<String> * [.config](#balena.models.config) : object @@ -5261,7 +5261,7 @@ balena.models.organization.remove(123); * [.download(options)](#balena.models.os.download) ⇒ Promise * [.getConfig(slugOrUuidOrId, options)](#balena.models.os.getConfig) ⇒ Promise * [.isSupportedOsUpdate(deviceType, currentVersion, targetVersion)](#balena.models.os.isSupportedOsUpdate) ⇒ Promise - * [.getSupportedOsUpdateVersions(deviceType, currentVersion)](#balena.models.os.getSupportedOsUpdateVersions) ⇒ Promise + * [.getSupportedOsUpdateVersions(deviceType, currentVersion, [options])](#balena.models.os.getSupportedOsUpdateVersions) ⇒ Promise * [.isArchitectureCompatibleWith(osArchitecture, applicationArchitecture)](#balena.models.os.isArchitectureCompatibleWith) ⇒ Boolean * [.getSupervisorImageForDeviceType(deviceTypeId, version)](#balena.models.os.getSupervisorImageForDeviceType) ⇒ Promise.<String> @@ -5468,10 +5468,12 @@ balena.models.os.isSupportedOsUpgrade('raspberry-pi', '2.9.6+rev2.prod', '2.29.2 ``` -##### os.getSupportedOsUpdateVersions(deviceType, currentVersion) ⇒ Promise +##### os.getSupportedOsUpdateVersions(deviceType, currentVersion, [options]) ⇒ Promise **Kind**: static method of [os](#balena.models.os) **Summary**: Returns the supported OS update targets for the provided device type **Access**: public +**Fulfil**: Object[]\|Object - An array of OsVersion objects when a single device type slug is provided, +or a dictionary of OsVersion objects by device type slug when an array of device type slugs is provided. **Fulfil**: Object - the versions information, of the following structure: * versions - an array of strings, containing exact version numbers that OS update is supported @@ -5479,10 +5481,12 @@ containing exact version numbers that OS update is supported that is _not_ pre-release, can be `null` * current - the provided current version after normalization -| Param | Type | Description | -| --- | --- | --- | -| deviceType | String | device type slug | -| currentVersion | String | semver-compatible version for the starting OS version | +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| deviceType | String | | device type slug | +| currentVersion | String | | semver-compatible version for the starting OS version | +| [options] | Object | | Extra options to filter the OS releases by | +| [options.includeDraft] | Boolean | false | Whether pre-releases should be included in the results | **Example** ```js diff --git a/src/models/os.ts b/src/models/os.ts index ea2f1c1cd..8647d4630 100644 --- a/src/models/os.ts +++ b/src/models/os.ts @@ -877,6 +877,10 @@ const getOsModel = function ( * * @param {String} deviceType - device type slug * @param {String} currentVersion - semver-compatible version for the starting OS version + * @param {Object} [options] - Extra options to filter the OS releases by + * @param {Boolean} [options.includeDraft=false] - Whether pre-releases should be included in the results + * @fulfil {Object[]|Object} - An array of OsVersion objects when a single device type slug is provided, + * or a dictionary of OsVersion objects by device type slug when an array of device type slugs is provided. * @fulfil {Object} - the versions information, of the following structure: * * versions - an array of strings, * containing exact version numbers that OS update is supported @@ -893,9 +897,10 @@ const getOsModel = function ( const getSupportedOsUpdateVersions = async ( deviceType: string, currentVersion: string, + options?: { includeDraft?: boolean }, ): Promise => { deviceType = await _getNormalizedDeviceTypeSlug(deviceType); - const allVersions = (await getAvailableOsVersions(deviceType)) + const allVersions = (await getAvailableOsVersions(deviceType, options)) .filter((v) => v.osType === OsTypes.DEFAULT) .map((v) => v.raw_version); // use bSemver.compare to find the current version in the OS list diff --git a/tests/integration/models/os.spec.ts b/tests/integration/models/os.spec.ts index db49107a0..ed4069639 100644 --- a/tests/integration/models/os.spec.ts +++ b/tests/integration/models/os.spec.ts @@ -860,24 +860,64 @@ describe('OS model', function () { ); })); - describe('given a valid device slug', () => - it('should return the list of supported hup targets', () => - balena.models.os - .getSupportedOsUpdateVersions('raspberrypi3', '2.9.6+rev1.prod') - .then(function ({ current, recommended, versions }) { - expect(current).to.equal('2.9.6+rev1.prod'); - expect(recommended).to.be.a('string'); - expect(versions).to.be.an('array'); - expect(versions).to.not.have.length(0); - versions.forEach(function (v) { - expect(v).to.be.a('string'); - expect(bSemver.gte(v, current)).to.be.true; - }); + describe('given a valid device slug', () => { + it('should return the list of supported hup targets', async () => { + const { current, recommended, versions } = + await balena.models.os.getSupportedOsUpdateVersions( + 'raspberrypi3', + '2.9.6+rev1.prod', + ); + expect(current).to.equal('2.9.6+rev1.prod'); + expect(recommended).to.be.a('string'); + expect(versions).to.be.an('array'); + expect(versions).to.not.have.length(0); + versions.forEach(function (v) { + expect(v).to.be.a('string'); + expect(bSemver.gte(v, current)).to.be.true; + }); + + expect(versions.length > 2).to.be.true; + const sortedVersions = versions.slice().sort(bSemver.rcompare); + expect(versions).to.deep.equal(sortedVersions); + }); + + it('should not include draft OS releases when the respective flag is not used', async () => { + const { current, recommended, versions } = + await balena.models.os.getSupportedOsUpdateVersions( + 'raspberrypi3', + '2.9.6+rev1.prod', + ); + expect(current).to.equal('2.9.6+rev1.prod'); + expect(recommended).to.be.a('string'); + expect(versions).to.be.an('array'); + expect(versions).to.not.have.length(0); + + const draftVersions = versions.filter( + (v) => bSemver.parse(v)?.prerelease.length ?? 0 > 0, + ); + expect(draftVersions).to.have.lengthOf(0); + }); + + // This relies on the API we are testing against having a newer OS version + // that's a draft, like api.balena-cloud.com had at the time of writing this test. + it('should include draft OS releases when the respective flag is used', async () => { + const { current, recommended, versions } = + await balena.models.os.getSupportedOsUpdateVersions( + 'raspberrypi3', + '2.9.6+rev1.prod', + { includeDraft: true }, + ); + expect(current).to.equal('2.9.6+rev1.prod'); + expect(recommended).to.be.a('string'); + expect(versions).to.be.an('array'); + expect(versions).to.not.have.length(0); - expect(versions.length > 2).to.be.true; - const sortedVersions = versions.slice().sort(bSemver.rcompare); - expect(versions).to.deep.equal(sortedVersions); - }))); + const draftVersions = versions.filter( + (v) => bSemver.parse(v)?.prerelease.length ?? 0 > 0, + ); + expect(draftVersions).to.have.length.greaterThan(0); + }); + }); }); describe('when logged in as a user with a single application', function () {