mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-02-20 17:33:18 +00:00
Merge pull request #2624 from balena-io/improve-typings
Use stricter typings
This commit is contained in:
commit
fcda09009a
@ -20,7 +20,7 @@ import Command from '../command';
|
||||
import { getBalenaSdk } from '../utils/lazy';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import * as compose from '../utils/compose';
|
||||
import type { Application, ApplicationType, BalenaSDK } from 'balena-sdk';
|
||||
import type { ApplicationType, BalenaSDK } from 'balena-sdk';
|
||||
import {
|
||||
buildArgDeprecation,
|
||||
dockerignoreHelp,
|
||||
@ -218,7 +218,9 @@ ${dockerignoreHelp}
|
||||
logger: import('../utils/logger'),
|
||||
composeOpts: ComposeOpts,
|
||||
opts: {
|
||||
app?: Application;
|
||||
app?: {
|
||||
application_type: [Pick<ApplicationType, 'supports_multicontainer'>];
|
||||
};
|
||||
arch: string;
|
||||
deviceType: string;
|
||||
buildEmulated: boolean;
|
||||
@ -234,7 +236,7 @@ ${dockerignoreHelp}
|
||||
opts.buildOpts.t,
|
||||
);
|
||||
|
||||
const appType = (opts.app?.application_type as ApplicationType[])?.[0];
|
||||
const appType = opts.app?.application_type?.[0];
|
||||
if (
|
||||
appType != null &&
|
||||
project.descriptors.length > 1 &&
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
devModeInfo,
|
||||
secureBootInfo,
|
||||
} from '../../utils/messages';
|
||||
import type { PineDeferred } from 'balena-sdk';
|
||||
import type { BalenaSDK, PineDeferred } from 'balena-sdk';
|
||||
|
||||
interface FlagsDef {
|
||||
version: string; // OS version
|
||||
@ -144,17 +144,24 @@ export default class ConfigGenerateCmd extends Command {
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async getApplication(balena: BalenaSDK, fleet: string) {
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
return await getApplication(balena, fleet, {
|
||||
$expand: {
|
||||
is_for__device_type: { $select: 'slug' },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(ConfigGenerateCmd);
|
||||
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
await this.validateOptions(options);
|
||||
|
||||
let resourceDeviceType: string;
|
||||
let application: ApplicationWithDeviceType | null = null;
|
||||
let application: Awaited<ReturnType<typeof this.getApplication>> | null =
|
||||
null;
|
||||
let device:
|
||||
| (DeviceWithDeviceType & { belongs_to__application: PineDeferred })
|
||||
| null = null;
|
||||
@ -174,11 +181,7 @@ export default class ConfigGenerateCmd extends Command {
|
||||
resourceDeviceType = device.is_of__device_type[0].slug;
|
||||
} else {
|
||||
// Disambiguate application (if is a number, it could either be an ID or a numerical name)
|
||||
application = (await getApplication(balena, options.fleet!, {
|
||||
$expand: {
|
||||
is_for__device_type: { $select: 'slug' },
|
||||
},
|
||||
})) as ApplicationWithDeviceType;
|
||||
application = await this.getApplication(balena, options.fleet!);
|
||||
resourceDeviceType = application.is_for__device_type[0].slug;
|
||||
}
|
||||
|
||||
|
@ -43,15 +43,13 @@ import {
|
||||
parseReleaseTagKeysAndValues,
|
||||
} from '../utils/compose_ts';
|
||||
import { dockerCliFlags } from '../utils/docker';
|
||||
import type {
|
||||
Application,
|
||||
ApplicationType,
|
||||
DeviceType,
|
||||
Release,
|
||||
} from 'balena-sdk';
|
||||
import type { ApplicationType, DeviceType, Release } from 'balena-sdk';
|
||||
|
||||
interface ApplicationWithArch extends Application {
|
||||
interface ApplicationWithArch {
|
||||
id: number;
|
||||
arch: string;
|
||||
is_for__device_type: [Pick<DeviceType, 'slug'>];
|
||||
application_type: [Pick<ApplicationType, 'slug' | 'supports_multicontainer'>];
|
||||
}
|
||||
|
||||
interface FlagsDef extends ComposeCliFlags, DockerCliFlags {
|
||||
@ -262,7 +260,7 @@ ${dockerignoreHelp}
|
||||
'../utils/compose_ts'
|
||||
);
|
||||
|
||||
const appType = (opts.app?.application_type as ApplicationType[])?.[0];
|
||||
const appType = opts.app.application_type[0];
|
||||
|
||||
try {
|
||||
const project = await loadProject(
|
||||
@ -319,7 +317,7 @@ ${dockerignoreHelp}
|
||||
projectName: project.name,
|
||||
composition: compositionToBuild,
|
||||
arch: opts.app.arch,
|
||||
deviceType: (opts.app?.is_for__device_type as DeviceType[])?.[0].slug,
|
||||
deviceType: opts.app.is_for__device_type[0].slug,
|
||||
emulated: opts.buildEmulated,
|
||||
buildOpts: opts.buildOpts,
|
||||
inlineLogs: composeOpts.inlineLogs,
|
||||
|
@ -124,7 +124,7 @@ export default class DeviceInitCmd extends Command {
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
// Get application and
|
||||
const application = (await getApplication(
|
||||
const application = await getApplication(
|
||||
balena,
|
||||
options.fleet ||
|
||||
(
|
||||
@ -137,7 +137,7 @@ export default class DeviceInitCmd extends Command {
|
||||
},
|
||||
},
|
||||
},
|
||||
)) as ApplicationWithDeviceType;
|
||||
);
|
||||
|
||||
// Register new device
|
||||
const deviceUuid = balena.models.device.generateUniqueKey();
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
import type { flags as flagsType } from '@oclif/command';
|
||||
import { flags } from '@oclif/command';
|
||||
import type { Release } from 'balena-sdk';
|
||||
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
@ -74,17 +73,12 @@ export default class FleetCmd extends Command {
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
const application = (await getApplication(balena, params.fleet, {
|
||||
const application = await getApplication(balena, params.fleet, {
|
||||
$expand: {
|
||||
is_for__device_type: { $select: 'slug' },
|
||||
should_be_running__release: { $select: 'commit' },
|
||||
},
|
||||
})) as ApplicationWithDeviceType & {
|
||||
should_be_running__release: [Release?];
|
||||
// For display purposes:
|
||||
device_type: string;
|
||||
commit?: string;
|
||||
};
|
||||
});
|
||||
|
||||
if (options.view) {
|
||||
const open = await import('open');
|
||||
@ -95,11 +89,14 @@ export default class FleetCmd extends Command {
|
||||
return;
|
||||
}
|
||||
|
||||
application.device_type = application.is_for__device_type[0].slug;
|
||||
application.commit = application.should_be_running__release[0]?.commit;
|
||||
const outputApplication = {
|
||||
...application,
|
||||
device_type: application.is_for__device_type[0].slug,
|
||||
commit: application.should_be_running__release[0]?.commit,
|
||||
};
|
||||
|
||||
await this.outputData(
|
||||
application,
|
||||
outputApplication,
|
||||
['app_name', 'id', 'device_type', 'slug', 'commit'],
|
||||
options,
|
||||
);
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import type { flags } from '@oclif/command';
|
||||
import type { ApplicationType } from 'balena-sdk';
|
||||
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
@ -91,7 +90,7 @@ export default class FleetRenameCmd extends Command {
|
||||
}
|
||||
|
||||
// Check app supports renaming
|
||||
const appType = (application.application_type as ApplicationType[])?.[0];
|
||||
const appType = application.application_type[0];
|
||||
if (appType.slug === 'legacy-v1' || appType.slug === 'legacy-v2') {
|
||||
throw new ExpectedError(
|
||||
`Fleet ${params.fleet} is of 'legacy' type, and cannot be renamed.`,
|
||||
|
@ -381,7 +381,9 @@ async function getOsVersionFromImage(
|
||||
*/
|
||||
async function checkDeviceTypeCompatibility(
|
||||
options: FlagsDef,
|
||||
app: ApplicationWithDeviceType,
|
||||
app: {
|
||||
is_for__device_type: [Pick<BalenaSdk.DeviceType, 'slug'>];
|
||||
},
|
||||
) {
|
||||
if (options['device-type']) {
|
||||
const helpers = await import('../../utils/helpers');
|
||||
|
@ -31,7 +31,14 @@ import { parseAsInteger } from '../utils/validation';
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import * as _ from 'lodash';
|
||||
import type { Application, BalenaSDK, PineExpand, Release } from 'balena-sdk';
|
||||
import type {
|
||||
Application,
|
||||
BalenaSDK,
|
||||
PineExpand,
|
||||
PineOptions,
|
||||
PineTypedResult,
|
||||
Release,
|
||||
} from 'balena-sdk';
|
||||
import type { Preloader } from 'balena-preload';
|
||||
|
||||
interface FlagsDef extends DockerConnectionCliFlags {
|
||||
@ -308,7 +315,7 @@ Can be repeated to add multiple certificates.\
|
||||
}
|
||||
}
|
||||
|
||||
readonly applicationExpandOptions: PineExpand<Application> = {
|
||||
readonly applicationExpandOptions = {
|
||||
owns__release: {
|
||||
$select: ['id', 'commit', 'end_timestamp', 'composition'],
|
||||
$expand: {
|
||||
@ -329,7 +336,7 @@ Can be repeated to add multiple certificates.\
|
||||
should_be_running__release: {
|
||||
$select: 'commit',
|
||||
},
|
||||
};
|
||||
} satisfies PineExpand<Application>;
|
||||
|
||||
isCurrentCommit(commit: string) {
|
||||
return commit === 'latest' || commit === 'current';
|
||||
@ -343,7 +350,7 @@ Can be repeated to add multiple certificates.\
|
||||
} catch {
|
||||
throw new Error(`Device type "${deviceTypeSlug}" not found in API query`);
|
||||
}
|
||||
return (await balena.models.application.getAllDirectlyAccessible({
|
||||
const options = {
|
||||
$select: ['id', 'slug', 'should_track_latest_release'],
|
||||
$expand: this.applicationExpandOptions,
|
||||
$filter: {
|
||||
@ -388,11 +395,10 @@ Can be repeated to add multiple certificates.\
|
||||
},
|
||||
},
|
||||
$orderby: 'slug asc',
|
||||
})) as Array<
|
||||
ApplicationWithDeviceType & {
|
||||
should_be_running__release: [Release?];
|
||||
}
|
||||
>;
|
||||
} satisfies PineOptions<Application>;
|
||||
return (await balena.models.application.getAllDirectlyAccessible(
|
||||
options,
|
||||
)) as Array<PineTypedResult<Application, typeof options>>;
|
||||
}
|
||||
|
||||
async selectApplication(deviceTypeSlug: string) {
|
||||
@ -442,7 +448,7 @@ Can be repeated to add multiple certificates.\
|
||||
}
|
||||
|
||||
async offerToDisableAutomaticUpdates(
|
||||
application: Application,
|
||||
application: Pick<Application, 'id' | 'should_track_latest_release'>,
|
||||
commit: string,
|
||||
pinDevice: boolean,
|
||||
) {
|
||||
@ -494,9 +500,9 @@ Would you like to disable automatic updates for this fleet now?\
|
||||
async getAppWithReleases(balenaSdk: BalenaSDK, slug: string) {
|
||||
const { getApplication } = await import('../utils/sdk');
|
||||
|
||||
return (await getApplication(balenaSdk, slug, {
|
||||
return await getApplication(balenaSdk, slug, {
|
||||
$expand: this.applicationExpandOptions,
|
||||
})) as Application & { should_be_running__release: [Release?] };
|
||||
});
|
||||
}
|
||||
|
||||
async prepareAndPreload(
|
||||
|
@ -59,7 +59,7 @@ export interface ImgConfig {
|
||||
}
|
||||
|
||||
export async function generateApplicationConfig(
|
||||
application: BalenaSdk.Application,
|
||||
application: Pick<BalenaSdk.Application, 'slug'>,
|
||||
options: {
|
||||
version: string;
|
||||
appUpdatePollInterval?: number;
|
||||
|
@ -180,11 +180,10 @@ export async function osProgressHandler(step: InitializeEmitter) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function getAppWithArch(
|
||||
applicationName: string,
|
||||
): Promise<ApplicationWithDeviceType & { arch: string }> {
|
||||
export async function getAppWithArch(applicationName: string) {
|
||||
const { getApplication } = await import('./sdk');
|
||||
const options: BalenaSdk.PineOptions<BalenaSdk.Application> = {
|
||||
const balena = getBalenaSdk();
|
||||
const app = await getApplication(balena, applicationName, {
|
||||
$expand: {
|
||||
application_type: {
|
||||
$select: ['name', 'slug', 'supports_multicontainer'],
|
||||
@ -198,20 +197,10 @@ export async function getAppWithArch(
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const balena = getBalenaSdk();
|
||||
const app = (await getApplication(
|
||||
balena,
|
||||
applicationName,
|
||||
options,
|
||||
)) as ApplicationWithDeviceType;
|
||||
const { getExpanded } = await import('./pine');
|
||||
|
||||
});
|
||||
return {
|
||||
...app,
|
||||
arch: getExpanded(
|
||||
getExpanded(app.is_for__device_type)!.is_of__cpu_architecture,
|
||||
)!.slug,
|
||||
arch: app.is_for__device_type[0].is_of__cpu_architecture[0].slug,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Application, BalenaSDK, Device, Organization } from 'balena-sdk';
|
||||
import type { BalenaSDK, Device, Organization } from 'balena-sdk';
|
||||
import _ = require('lodash');
|
||||
|
||||
import { instanceOf, NotLoggedInError, ExpectedError } from '../errors';
|
||||
@ -193,10 +193,11 @@ export function selectApplication(
|
||||
});
|
||||
}
|
||||
|
||||
export async function selectOrganization(organizations?: Organization[]) {
|
||||
export async function selectOrganization(
|
||||
organizations?: Array<Pick<Organization, 'handle' | 'name'>>,
|
||||
) {
|
||||
// Use either provided orgs (if e.g. already loaded) or load from cloud
|
||||
organizations =
|
||||
organizations || (await getBalenaSdk().models.organization.getAll());
|
||||
organizations ??= await getBalenaSdk().models.organization.getAll();
|
||||
return getCliForm().ask({
|
||||
message: 'Select an organization',
|
||||
type: 'list',
|
||||
@ -295,19 +296,20 @@ export async function getOnlineTargetDeviceUuid(
|
||||
}
|
||||
|
||||
// Not a device UUID, try application
|
||||
let application: Application;
|
||||
try {
|
||||
logger.logDebug(`Fetching fleet ${fleetOrDevice}`);
|
||||
const { getApplication } = await import('./sdk');
|
||||
application = await getApplication(sdk, fleetOrDevice);
|
||||
} catch (err) {
|
||||
const { BalenaApplicationNotFound } = await import('balena-errors');
|
||||
if (instanceOf(err, BalenaApplicationNotFound)) {
|
||||
throw new ExpectedError(`Fleet or Device not found: ${fleetOrDevice}`);
|
||||
} else {
|
||||
throw err;
|
||||
const application = await (async () => {
|
||||
try {
|
||||
logger.logDebug(`Fetching fleet ${fleetOrDevice}`);
|
||||
const { getApplication } = await import('./sdk');
|
||||
return await getApplication(sdk, fleetOrDevice);
|
||||
} catch (err) {
|
||||
const { BalenaApplicationNotFound } = await import('balena-errors');
|
||||
if (instanceOf(err, BalenaApplicationNotFound)) {
|
||||
throw new ExpectedError(`Fleet or Device not found: ${fleetOrDevice}`);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
// App found, load its devices
|
||||
const devices = await sdk.models.device.getAllByApplication(application.id, {
|
||||
|
@ -20,8 +20,18 @@ import type {
|
||||
BalenaSDK,
|
||||
Organization,
|
||||
PineOptions,
|
||||
PineTypedResult,
|
||||
} from 'balena-sdk';
|
||||
|
||||
export async function getApplication(
|
||||
sdk: BalenaSDK,
|
||||
nameOrSlugOrId: string | number,
|
||||
): Promise<Application>;
|
||||
export async function getApplication<TP extends PineOptions<Application>>(
|
||||
sdk: BalenaSDK,
|
||||
nameOrSlugOrId: string | number,
|
||||
options?: TP,
|
||||
): Promise<PineTypedResult<Application, TP>>;
|
||||
/**
|
||||
* Get a fleet object, disambiguating the fleet identifier which may be a
|
||||
* a fleet slug or name.
|
||||
@ -29,21 +39,24 @@ import type {
|
||||
*/
|
||||
export async function getApplication(
|
||||
sdk: BalenaSDK,
|
||||
nameOrSlug: string,
|
||||
nameOrSlugOrId: string | number,
|
||||
options?: PineOptions<Application>,
|
||||
): Promise<Application> {
|
||||
const { looksLikeFleetSlug } = await import('./validation');
|
||||
if (!looksLikeFleetSlug(nameOrSlug)) {
|
||||
if (
|
||||
typeof nameOrSlugOrId === 'string' &&
|
||||
!looksLikeFleetSlug(nameOrSlugOrId)
|
||||
) {
|
||||
// Not a slug: must be an app name.
|
||||
// TODO: revisit this logic when we add support for fleet UUIDs.
|
||||
return await sdk.models.application.getAppByName(
|
||||
nameOrSlug,
|
||||
nameOrSlugOrId,
|
||||
options,
|
||||
'directly_accessible',
|
||||
);
|
||||
}
|
||||
return await sdk.models.application.getDirectlyAccessible(
|
||||
nameOrSlug,
|
||||
nameOrSlugOrId,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user