diff --git a/docs/balena-cli.md b/docs/balena-cli.md index 3d5c2f4964..36cfafba84 100644 --- a/docs/balena-cli.md +++ b/docs/balena-cli.md @@ -1678,10 +1678,6 @@ note content device UUID -#### --dev DEV - - - ## device os-update ### Description diff --git a/src/commands/api-key/list.ts b/src/commands/api-key/list.ts index 8f802ff7f3..d7b8fa33e6 100644 --- a/src/commands/api-key/list.ts +++ b/src/commands/api-key/list.ts @@ -37,7 +37,7 @@ export default class APIKeyListCmd extends Command { char: 'u', description: 'show API keys for your user', }), - fleet: cf.fleet, + fleet: cf.fleet(), }; public static authenticated = true; diff --git a/src/commands/build/index.ts b/src/commands/build/index.ts index 66a8944fff..da2e0b6aee 100644 --- a/src/commands/build/index.ts +++ b/src/commands/build/index.ts @@ -86,12 +86,15 @@ ${dockerignoreHelp} arch: Flags.string({ description: 'the architecture to build for', char: 'A', + exclusive: ['fleet'], + dependsOn: ['deviceType'], }), deviceType: Flags.string({ description: 'the type of device this build is for', char: 'd', + exclusive: ['fleet'], }), - fleet: cf.fleet, + fleet: cf.fleet({ exclusive: ['deviceType', 'arch'] }), ...composeCliFlags, ...dockerCliFlags, }; @@ -148,17 +151,6 @@ ${dockerignoreHelp} } protected async validateOptions(opts: FlagsDef, sdk: BalenaSDK) { - // Validate option combinations - if ( - (opts.fleet == null && (opts.arch == null || opts.deviceType == null)) || - (opts.fleet != null && (opts.arch != null || opts.deviceType != null)) - ) { - const { ExpectedError } = await import('../../errors'); - throw new ExpectedError( - 'You must specify either a fleet (-f), or the device type (-d) and optionally the architecture (-A)', - ); - } - // Validate project directory const { validateProjectDirectory } = await import('../../utils/compose_ts'); const { dockerfilePath, registrySecrets } = await validateProjectDirectory( diff --git a/src/commands/config/generate.ts b/src/commands/config/generate.ts index 4376b53f24..9e368922fd 100644 --- a/src/commands/config/generate.ts +++ b/src/commands/config/generate.ts @@ -64,11 +64,11 @@ export default class ConfigGenerateCmd extends Command { description: 'a balenaOS version', required: true, }), - fleet: { ...cf.fleet, exclusive: ['device'] }, + fleet: cf.fleet({ exclusive: ['device'] }), dev: cf.dev, secureBoot: cf.secureBoot, device: { - ...cf.device, + ...cf.device(), exclusive: [ 'fleet', 'provisioning-key-name', @@ -83,6 +83,7 @@ export default class ConfigGenerateCmd extends Command { deviceType: Flags.string({ description: "device type slug (run 'balena device-type list' for possible values)", + dependsOn: ['fleet'], }), 'generate-device-api-key': Flags.boolean({ description: 'generate a fresh device key for the device', @@ -240,9 +241,6 @@ export default class ConfigGenerateCmd extends Command { $ balena help config generate `; - protected readonly deviceTypeNotAllowedMessage = - 'The --deviceType option can only be used alongside the --fleet option'; - protected async validateOptions( options: Interfaces.InferredFlags, ) { @@ -252,9 +250,6 @@ export default class ConfigGenerateCmd extends Command { throw new ExpectedError(this.missingDeviceOrAppMessage); } - if (!options.fleet && options.deviceType) { - throw new ExpectedError(this.deviceTypeNotAllowedMessage); - } const { normalizeOsVersion } = await import('../../utils/normalization'); options.version = normalizeOsVersion(options.version); const { validateDevOptionAndWarn } = await import('../../utils/config'); diff --git a/src/commands/device/deactivate.ts b/src/commands/device/deactivate.ts index f0a81631d2..51450f558c 100644 --- a/src/commands/device/deactivate.ts +++ b/src/commands/device/deactivate.ts @@ -47,13 +47,14 @@ export default class DeviceDeactivateCmd extends Command { public static authenticated = true; public async run() { - const { args: params, flags: options } = - await this.parse(DeviceDeactivateCmd); + const { + args: { uuid }, + flags: options, + } = await this.parse(DeviceDeactivateCmd); const balena = getBalenaSdk(); const patterns = await import('../../utils/patterns'); - const uuid = params.uuid; const deactivationWarning = ` Warning! Deactivating a device will charge a fee equivalent to the normal monthly cost for the device (e.g. $1 for an essentials device); diff --git a/src/commands/device/init.ts b/src/commands/device/init.ts index 81b907f4d7..077effffb6 100644 --- a/src/commands/device/init.ts +++ b/src/commands/device/init.ts @@ -73,7 +73,7 @@ export default class DeviceInitCmd extends Command { ]; public static flags = { - fleet: cf.fleet, + fleet: cf.fleet(), yes: cf.yes, advanced: Flags.boolean({ char: 'v', diff --git a/src/commands/device/list.ts b/src/commands/device/list.ts index 7eea1c1ed4..58a7bad758 100644 --- a/src/commands/device/list.ts +++ b/src/commands/device/list.ts @@ -57,7 +57,7 @@ export default class DeviceListCmd extends Command { ]; public static flags = { - fleet: cf.fleet, + fleet: cf.fleet(), json: cf.json, }; diff --git a/src/commands/device/move.ts b/src/commands/device/move.ts index 0300fe7045..17be42d0e0 100644 --- a/src/commands/device/move.ts +++ b/src/commands/device/move.ts @@ -54,7 +54,7 @@ export default class DeviceMoveCmd extends Command { }; public static flags = { - fleet: cf.fleet, + fleet: cf.fleet(), }; public static authenticated = true; diff --git a/src/commands/device/note.ts b/src/commands/device/note.ts index cedbdb8113..10dc08c064 100644 --- a/src/commands/device/note.ts +++ b/src/commands/device/note.ts @@ -15,8 +15,7 @@ * limitations under the License. */ -import { Flags, Args, Command } from '@oclif/core'; -import { ExpectedError } from '../../errors'; +import { Args, Command } from '@oclif/core'; import * as cf from '../../utils/common-flags'; import { getBalenaSdk, stripIndent } from '../../utils/lazy'; @@ -41,35 +40,24 @@ export default class DeviceNoteCmd extends Command { public static args = { note: Args.string({ description: 'note content', + required: true, }), }; public static flags = { - device: { exclusive: ['dev'], ...cf.device }, - dev: Flags.string({ - exclusive: ['device'], - hidden: true, - }), + device: cf.device({ required: true }), }; public static authenticated = true; public async run() { - const { args: params, flags: options } = await this.parse(DeviceNoteCmd); - - if (params.note?.length === 0) { - throw new ExpectedError('Missing note content'); - } - - options.device = options.device || options.dev; - delete options.dev; - - if (options.device == null || options.device.length === 0) { - throw new ExpectedError('Missing device UUID (--device)'); - } + const { + args: params, + flags: { device }, + } = await this.parse(DeviceNoteCmd); const balena = getBalenaSdk(); - return balena.models.device.setNote(options.device, params.note ?? ''); + return balena.models.device.setNote(device!, params.note!); } } diff --git a/src/commands/device/tunnel.ts b/src/commands/device/tunnel.ts index 38d877ea85..63f59aa166 100644 --- a/src/commands/device/tunnel.ts +++ b/src/commands/device/tunnel.ts @@ -16,11 +16,7 @@ */ import { Flags, Args, Command } from '@oclif/core'; -import { - NoPortsDefinedError, - InvalidPortMappingError, - ExpectedError, -} from '../../errors'; +import { InvalidPortMappingError, ExpectedError } from '../../errors'; import { getBalenaSdk, stripIndent } from '../../utils/lazy'; import { lowercaseIfSlug } from '../../utils/normalization'; @@ -85,6 +81,7 @@ export default class DeviceTunnelCmd extends Command { 'port mapping in the format [:[localIP:]localPort]', char: 'p', multiple: true, + required: true, }), }; @@ -117,10 +114,6 @@ export default class DeviceTunnelCmd extends Command { } }; - if (options.port === undefined) { - throw new NoPortsDefinedError(); - } - // Ascertain device uuid const { getOnlineTargetDeviceUuid } = await import('../../utils/patterns'); const uuid = await getOnlineTargetDeviceUuid(sdk, params.deviceOrFleet); diff --git a/src/commands/env/list.ts b/src/commands/env/list.ts index 42c122d564..5aa3c2ac52 100644 --- a/src/commands/env/list.ts +++ b/src/commands/env/list.ts @@ -97,14 +97,14 @@ export default class EnvListCmd extends Command { ]; public static flags = { - fleet: { ...cf.fleet, exclusive: ['device'] }, + fleet: { ...cf.fleet(), exclusive: ['device'] }, config: Flags.boolean({ default: false, char: 'c', description: 'show configuration variables only', exclusive: ['service'], }), - device: { ...cf.device, exclusive: ['fleet'] }, + device: { ...cf.device(), exclusive: ['fleet'] }, json: cf.json, service: { ...cf.service, exclusive: ['config'] }, }; diff --git a/src/commands/env/set.ts b/src/commands/env/set.ts index 6ad8d6a044..6d2780c511 100644 --- a/src/commands/env/set.ts +++ b/src/commands/env/set.ts @@ -95,8 +95,8 @@ export default class EnvSetCmd extends Command { public static strict = false; public static flags = { - fleet: { ...cf.fleet, exclusive: ['device'] }, - device: { ...cf.device, exclusive: ['fleet'] }, + fleet: { ...cf.fleet(), exclusive: ['device'] }, + device: { ...cf.device(), exclusive: ['fleet'] }, quiet: cf.quiet, service: cf.service, }; diff --git a/src/commands/join/index.ts b/src/commands/join/index.ts index 5427cb5762..c3d7d28675 100644 --- a/src/commands/join/index.ts +++ b/src/commands/join/index.ts @@ -60,7 +60,7 @@ export default class JoinCmd extends Command { }; public static flags = { - fleet: cf.fleet, + fleet: cf.fleet(), pollInterval: Flags.integer({ description: 'the interval in minutes to check for updates', char: 'i', diff --git a/src/commands/os/configure.ts b/src/commands/os/configure.ts index da497c361b..7573949a1c 100644 --- a/src/commands/os/configure.ts +++ b/src/commands/os/configure.ts @@ -97,7 +97,7 @@ export default class OsConfigureCmd extends Command { description: 'ask advanced configuration questions (when in interactive mode)', }), - fleet: { ...cf.fleet, exclusive: ['device'] }, + fleet: { ...cf.fleet(), exclusive: ['device'] }, config: Flags.string({ description: 'path to a pre-generated config.json file to be injected in the OS image', @@ -120,7 +120,7 @@ export default class OsConfigureCmd extends Command { dev: cf.dev, secureBoot: cf.secureBoot, device: { - ...cf.device, + ...cf.device(), exclusive: [ 'fleet', 'provisioning-key-name', diff --git a/src/commands/preload/index.ts b/src/commands/preload/index.ts index 0cdfc63b72..fe691c393a 100644 --- a/src/commands/preload/index.ts +++ b/src/commands/preload/index.ts @@ -79,7 +79,7 @@ export default class PreloadCmd extends Command { }; public static flags = { - fleet: cf.fleet, + fleet: cf.fleet(), commit: Flags.string({ description: `\ The commit hash of the release to preload. Use "current" to specify the current diff --git a/src/commands/support/index.ts b/src/commands/support/index.ts index 6c100a2472..b5b40dc2ef 100644 --- a/src/commands/support/index.ts +++ b/src/commands/support/index.ts @@ -57,7 +57,7 @@ export default class SupportCmd extends Command { char: 'd', }), fleet: { - ...cf.fleet, + ...cf.fleet(), description: 'comma-separated list (no spaces) of fleet names or slugs (preferred)', }, diff --git a/src/commands/tag/list.ts b/src/commands/tag/list.ts index 40ca940ef4..22dc9e8c22 100644 --- a/src/commands/tag/list.ts +++ b/src/commands/tag/list.ts @@ -43,11 +43,11 @@ export default class TagListCmd extends Command { public static flags = { fleet: { - ...cf.fleet, + ...cf.fleet(), exclusive: ['device', 'release'], }, device: { - ...cf.device, + ...cf.device(), exclusive: ['fleet', 'release'], }, release: { diff --git a/src/commands/tag/rm.ts b/src/commands/tag/rm.ts index 622b6f35a3..959c9db89d 100644 --- a/src/commands/tag/rm.ts +++ b/src/commands/tag/rm.ts @@ -46,11 +46,11 @@ export default class TagRmCmd extends Command { public static flags = { fleet: { - ...cf.fleet, + ...cf.fleet(), exclusive: ['device', 'release'], }, device: { - ...cf.device, + ...cf.device(), exclusive: ['fleet', 'release'], }, release: { diff --git a/src/commands/tag/set.ts b/src/commands/tag/set.ts index adb79a1eff..eb1fe11cd8 100644 --- a/src/commands/tag/set.ts +++ b/src/commands/tag/set.ts @@ -60,11 +60,11 @@ export default class TagSetCmd extends Command { public static flags = { fleet: { - ...cf.fleet, + ...cf.fleet(), exclusive: ['device', 'release'], }, device: { - ...cf.device, + ...cf.device(), exclusive: ['fleet', 'release'], }, release: { diff --git a/src/errors.ts b/src/errors.ts index f099305f91..871f6f96a1 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -39,12 +39,6 @@ export class InvalidPortMappingError extends ExpectedError { } } -export class NoPortsDefinedError extends ExpectedError { - constructor() { - super('No ports have been provided.'); - } -} - export class SIGINTError extends ExpectedError {} /** diff --git a/src/utils/common-flags.ts b/src/utils/common-flags.ts index ba84db1390..8f3fbbf452 100644 --- a/src/utils/common-flags.ts +++ b/src/utils/common-flags.ts @@ -19,16 +19,22 @@ import { Flags } from '@oclif/core'; import { stripIndent } from './lazy'; import { lowercaseIfSlug } from './normalization'; -export const fleet = Flags.string({ - char: 'f', - description: 'fleet name or slug (preferred)', - parse: lowercaseIfSlug, -}); +// eslint-disable-next-line id-denylist +export const fleet = (extraOpts?: Partial) => + Flags.string({ + char: 'f', + description: 'fleet name or slug (preferred)', + parse: lowercaseIfSlug, + ...extraOpts, + }); -export const device = Flags.string({ - char: 'd', - description: 'device UUID', -}); +// eslint-disable-next-line id-denylist +export const device = (extraOpts?: Partial) => + Flags.string({ + char: 'd', + description: 'device UUID', + ...extraOpts, + }); export const quiet = Flags.boolean({ char: 'q',