Skip to content

Commit

Permalink
Enable OS Updates to pre-release versions of higher base semver
Browse files Browse the repository at this point in the history
Update balena-hup-action-utils from 5.0.0 to 6.1.0

Change-type: minor
  • Loading branch information
thgreasi committed Jan 19, 2024
1 parent 7c9d78e commit 7115ce8
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 120 deletions.
70 changes: 53 additions & 17 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,15 +359,15 @@ const sdk = fromSharedOptions();
* [.get(handleOrId, [options])](#balena.models.organization.get) ⇒ <code>Promise</code>
* [.remove(handleOrId)](#balena.models.organization.remove) ⇒ <code>Promise</code>
* [.os](#balena.models.os) : <code>object</code>
* [.getAvailableOsVersions(deviceTypes)](#balena.models.os.getAvailableOsVersions) ⇒ <code>Promise</code>
* [.getAvailableOsVersions(deviceTypes, [includeDraft])](#balena.models.os.getAvailableOsVersions) ⇒ <code>Promise</code>
* [.getAllOsVersions(deviceTypes, [options])](#balena.models.os.getAllOsVersions) ⇒ <code>Promise</code>
* [.getDownloadSize(deviceType, [version])](#balena.models.os.getDownloadSize) ⇒ <code>Promise</code>
* [.getMaxSatisfyingVersion(deviceType, versionOrRange, [osType])](#balena.models.os.getMaxSatisfyingVersion) ⇒ <code>Promise</code>
* [.getLastModified(deviceType, [version])](#balena.models.os.getLastModified) ⇒ <code>Promise</code>
* [.download(options)](#balena.models.os.download) ⇒ <code>Promise</code>
* [.getConfig(slugOrUuidOrId, options)](#balena.models.os.getConfig) ⇒ <code>Promise</code>
* [.isSupportedOsUpdate(deviceType, currentVersion, targetVersion)](#balena.models.os.isSupportedOsUpdate) ⇒ <code>Promise</code>
* [.getSupportedOsUpdateVersions(deviceType, currentVersion)](#balena.models.os.getSupportedOsUpdateVersions) ⇒ <code>Promise</code>
* [.getSupportedOsUpdateVersions(deviceType, currentVersion, [includeDraft])](#balena.models.os.getSupportedOsUpdateVersions) ⇒ <code>Promise</code>
* [.isArchitectureCompatibleWith(osArchitecture, applicationArchitecture)](#balena.models.os.isArchitectureCompatibleWith) ⇒ <code>Boolean</code>
* [.getSupervisorImageForDeviceType(deviceTypeId, version)](#balena.models.os.getSupervisorImageForDeviceType) ⇒ <code>Promise.&lt;String&gt;</code>
* [.config](#balena.models.config) : <code>object</code>
Expand Down Expand Up @@ -490,8 +490,7 @@ rejects with an error.
<a name="balena.utils"></a>

### balena.utils : <code>Object</code>
The utils instance used internally. This should not be necessary
in normal usage, but can be useful to handle some specific cases.
The utils instance offers some convenient features for clients.

**Kind**: static property of [<code>balena</code>](#balena)
**Summary**: Balena utils instance
Expand All @@ -503,6 +502,14 @@ balena.utils.mergePineOptions(
{ $expand: { device: { $select: ['name'] } } },
);
```
**Example**
```js
// Creating a new WebResourceFile in case 'File' API is not available.
new balena.utils.BalenaWebResourceFile(
[fs.readFileSync('./file.tgz')],
'file.tgz'
);
```
<a name="balena.request"></a>

### balena.request : <code>Object</code>
Expand Down Expand Up @@ -759,15 +766,15 @@ balena.models.device.get(123).catch(function (error) {
* [.get(handleOrId, [options])](#balena.models.organization.get) ⇒ <code>Promise</code>
* [.remove(handleOrId)](#balena.models.organization.remove) ⇒ <code>Promise</code>
* [.os](#balena.models.os) : <code>object</code>
* [.getAvailableOsVersions(deviceTypes)](#balena.models.os.getAvailableOsVersions) ⇒ <code>Promise</code>
* [.getAvailableOsVersions(deviceTypes, [includeDraft])](#balena.models.os.getAvailableOsVersions) ⇒ <code>Promise</code>
* [.getAllOsVersions(deviceTypes, [options])](#balena.models.os.getAllOsVersions) ⇒ <code>Promise</code>
* [.getDownloadSize(deviceType, [version])](#balena.models.os.getDownloadSize) ⇒ <code>Promise</code>
* [.getMaxSatisfyingVersion(deviceType, versionOrRange, [osType])](#balena.models.os.getMaxSatisfyingVersion) ⇒ <code>Promise</code>
* [.getLastModified(deviceType, [version])](#balena.models.os.getLastModified) ⇒ <code>Promise</code>
* [.download(options)](#balena.models.os.download) ⇒ <code>Promise</code>
* [.getConfig(slugOrUuidOrId, options)](#balena.models.os.getConfig) ⇒ <code>Promise</code>
* [.isSupportedOsUpdate(deviceType, currentVersion, targetVersion)](#balena.models.os.isSupportedOsUpdate) ⇒ <code>Promise</code>
* [.getSupportedOsUpdateVersions(deviceType, currentVersion)](#balena.models.os.getSupportedOsUpdateVersions) ⇒ <code>Promise</code>
* [.getSupportedOsUpdateVersions(deviceType, currentVersion, [includeDraft])](#balena.models.os.getSupportedOsUpdateVersions) ⇒ <code>Promise</code>
* [.isArchitectureCompatibleWith(osArchitecture, applicationArchitecture)](#balena.models.os.isArchitectureCompatibleWith) ⇒ <code>Boolean</code>
* [.getSupervisorImageForDeviceType(deviceTypeId, version)](#balena.models.os.getSupervisorImageForDeviceType) ⇒ <code>Promise.&lt;String&gt;</code>
* [.config](#balena.models.config) : <code>object</code>
Expand Down Expand Up @@ -5155,6 +5162,33 @@ balena.models.organization.create({ name:'MyOrganization' }).then(function(organ
console.log(organization);
});
```
**Example**
```js
balena.models.organization.create({
name:'MyOrganization',
logo_image: new balena.utils.BalenaWebResourceFile(
[fs.readFileSync('./img.jpeg')],
'img.jpeg'
);
})
.then(function(organization) {
console.log(organization);
});
```
**Example**
```js
balena.models.organization.create({
name:'MyOrganization',
// Only in case File API is avaialable (most browsers and Node 20+)
logo_image: new File(
imageContent,
'img.jpeg'
);
})
.then(function(organization) {
console.log(organization);
});
```
<a name="balena.models.organization.getAll"></a>

##### organization.getAll([options]) ⇒ <code>Promise</code>
Expand Down Expand Up @@ -5219,30 +5253,31 @@ balena.models.organization.remove(123);
**Kind**: static namespace of [<code>models</code>](#balena.models)

* [.os](#balena.models.os) : <code>object</code>
* [.getAvailableOsVersions(deviceTypes)](#balena.models.os.getAvailableOsVersions) ⇒ <code>Promise</code>
* [.getAvailableOsVersions(deviceTypes, [includeDraft])](#balena.models.os.getAvailableOsVersions) ⇒ <code>Promise</code>
* [.getAllOsVersions(deviceTypes, [options])](#balena.models.os.getAllOsVersions) ⇒ <code>Promise</code>
* [.getDownloadSize(deviceType, [version])](#balena.models.os.getDownloadSize) ⇒ <code>Promise</code>
* [.getMaxSatisfyingVersion(deviceType, versionOrRange, [osType])](#balena.models.os.getMaxSatisfyingVersion) ⇒ <code>Promise</code>
* [.getLastModified(deviceType, [version])](#balena.models.os.getLastModified) ⇒ <code>Promise</code>
* [.download(options)](#balena.models.os.download) ⇒ <code>Promise</code>
* [.getConfig(slugOrUuidOrId, options)](#balena.models.os.getConfig) ⇒ <code>Promise</code>
* [.isSupportedOsUpdate(deviceType, currentVersion, targetVersion)](#balena.models.os.isSupportedOsUpdate) ⇒ <code>Promise</code>
* [.getSupportedOsUpdateVersions(deviceType, currentVersion)](#balena.models.os.getSupportedOsUpdateVersions) ⇒ <code>Promise</code>
* [.getSupportedOsUpdateVersions(deviceType, currentVersion, [includeDraft])](#balena.models.os.getSupportedOsUpdateVersions) ⇒ <code>Promise</code>
* [.isArchitectureCompatibleWith(osArchitecture, applicationArchitecture)](#balena.models.os.isArchitectureCompatibleWith) ⇒ <code>Boolean</code>
* [.getSupervisorImageForDeviceType(deviceTypeId, version)](#balena.models.os.getSupervisorImageForDeviceType) ⇒ <code>Promise.&lt;String&gt;</code>

<a name="balena.models.os.getAvailableOsVersions"></a>

##### os.getAvailableOsVersions(deviceTypes) ⇒ <code>Promise</code>
##### os.getAvailableOsVersions(deviceTypes, [includeDraft]) ⇒ <code>Promise</code>
**Kind**: static method of [<code>os</code>](#balena.models.os)
**Summary**: Get the supported OS versions for the provided device type(s)
**Access**: public
**Fulfil**: <code>Object[]\|Object</code> - 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.

| Param | Type | Description |
| --- | --- | --- |
| deviceTypes | <code>String</code> \| <code>Array.&lt;String&gt;</code> | device type slug or array of slugs |
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| deviceTypes | <code>String</code> \| <code>Array.&lt;String&gt;</code> | | device type slug or array of slugs |
| [includeDraft] | <code>Boolean</code> | <code>false</code> | Whether pre-releases should be included in the results |

**Example**
```js
Expand Down Expand Up @@ -5432,7 +5467,7 @@ balena.models.os.isSupportedOsUpgrade('raspberry-pi', '2.9.6+rev2.prod', '2.29.2
```
<a name="balena.models.os.getSupportedOsUpdateVersions"></a>

##### os.getSupportedOsUpdateVersions(deviceType, currentVersion) ⇒ <code>Promise</code>
##### os.getSupportedOsUpdateVersions(deviceType, currentVersion, [includeDraft]) ⇒ <code>Promise</code>
**Kind**: static method of [<code>os</code>](#balena.models.os)
**Summary**: Returns the supported OS update targets for the provided device type
**Access**: public
Expand All @@ -5443,10 +5478,11 @@ 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 | <code>String</code> | device type slug |
| currentVersion | <code>String</code> | semver-compatible version for the starting OS version |
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| deviceType | <code>String</code> | | device type slug |
| currentVersion | <code>String</code> | | semver-compatible version for the starting OS version |
| [includeDraft] | <code>Boolean</code> | <code>false</code> | Whether prerelease OS versions should be included |

**Example**
```js
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
"abortcontroller-polyfill": "^1.7.1",
"balena-auth": "^5.1.0",
"balena-errors": "^4.9.0",
"balena-hup-action-utils": "~5.0.0",
"balena-hup-action-utils": "~6.1.0",
"balena-register-device": "^9.0.1",
"balena-request": "^13.2.0",
"balena-semver": "^2.3.0",
Expand Down
9 changes: 6 additions & 3 deletions src/models/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,9 @@ const getDeviceModel = function (
);
}

const isDraft =
(bSemver.parse(targetOsVersion)?.prerelease.length ?? 0) > 0;

const getDeviceType = memoizee(
async (deviceTypeId: number) =>
await sdkInstance.models.deviceType.get(deviceTypeId, {
Expand All @@ -358,8 +361,8 @@ const getDeviceModel = function (
{ primitive: true, promise: true },
);
const getAvailableOsVersions = memoizee(
async (slug: string) =>
await sdkInstance.models.os.getAvailableOsVersions(slug),
async (slug: string, includeDraft: boolean) =>
await sdkInstance.models.os.getAvailableOsVersions(slug, includeDraft),
{ primitive: true, promise: true },
);

Expand Down Expand Up @@ -392,7 +395,7 @@ const getDeviceModel = function (
targetOsVersion,
);

const osVersions = await getAvailableOsVersions(dt.slug);
const osVersions = await getAvailableOsVersions(dt.slug, isDraft);

if (
!osVersions.some(
Expand Down
27 changes: 18 additions & 9 deletions src/models/os.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,27 +362,32 @@ const getOsModel = function (
};

const _memoizedGetAllOsVersions = authDependentMemoizer(
async (deviceTypes: string[], listedByDefault: boolean | null) => {
async (
deviceTypes: string[],
filterOptions: 'default' | 'include_draft' | 'all',
) => {
return await _getAllOsVersions(
deviceTypes,
listedByDefault
? {
filterOptions === 'all'
? undefined
: {
$filter: {
is_final: true,
...(filterOptions !== 'include_draft' && { is_final: true }),
is_invalidated: false,
status: 'success',
},
}
: undefined,
},
);
},
);

async function getAvailableOsVersions(
deviceType: string,
includeDraft?: boolean,
): Promise<OsVersion[]>;
async function getAvailableOsVersions(
deviceTypes: string[],
includeDraft?: boolean,
): Promise<Dictionary<OsVersion[]>>;
/**
* @summary Get the supported OS versions for the provided device type(s)
Expand All @@ -392,6 +397,7 @@ const getOsModel = function (
* @memberof balena.models.os
*
* @param {String|String[]} deviceTypes - device type slug or array of slugs
* @param {Boolean} [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.
* @returns {Promise}
Expand All @@ -404,13 +410,14 @@ const getOsModel = function (
*/
async function getAvailableOsVersions(
deviceTypes: string[] | string,
includeDraft = false,
): Promise<TypeOrDictionary<OsVersion[]>> {
const singleDeviceTypeArg =
typeof deviceTypes === 'string' ? deviceTypes : false;
deviceTypes = Array.isArray(deviceTypes) ? deviceTypes : [deviceTypes];
const versionsByDt = await _memoizedGetAllOsVersions(
deviceTypes.slice().sort(),
true,
includeDraft ? 'include_draft' : 'default',
);
return singleDeviceTypeArg
? versionsByDt[singleDeviceTypeArg] ?? []
Expand Down Expand Up @@ -460,7 +467,7 @@ const getOsModel = function (
deviceTypes = Array.isArray(deviceTypes) ? deviceTypes : [deviceTypes];
const versionsByDt = (
options == null
? await _memoizedGetAllOsVersions(deviceTypes.slice().sort(), null)
? await _memoizedGetAllOsVersions(deviceTypes.slice().sort(), 'all')
: await _getAllOsVersions(deviceTypes, options)
) as Dictionary<Array<ExtendedPineTypedResult<Release, OsVersion, TP>>>;
return singleDeviceTypeArg
Expand Down Expand Up @@ -869,6 +876,7 @@ const getOsModel = function (
*
* @param {String} deviceType - device type slug
* @param {String} currentVersion - semver-compatible version for the starting OS version
* @param {Boolean} [includeDraft=false] - Whether prerelease OS versions should be included
* @fulfil {Object} - the versions information, of the following structure:
* * versions - an array of strings,
* containing exact version numbers that OS update is supported
Expand All @@ -885,9 +893,10 @@ const getOsModel = function (
const getSupportedOsUpdateVersions = async (
deviceType: string,
currentVersion: string,
includeDraft: boolean = false,
): Promise<OsUpdateVersions> => {
deviceType = await _getNormalizedDeviceTypeSlug(deviceType);
const allVersions = (await getAvailableOsVersions(deviceType))
const allVersions = (await getAvailableOsVersions(deviceType, includeDraft))
.filter((v) => v.osType === OsTypes.DEFAULT)
.map((v) => v.raw_version);
// use bSemver.compare to find the current version in the OS list
Expand Down
Loading

0 comments on commit 7115ce8

Please sign in to comment.