mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-06-24 18:45:07 +00:00
Compare commits
68 Commits
add-update
...
v17.1.4
Author | SHA1 | Date | |
---|---|---|---|
301d0ab3a0 | |||
efe0a018d7 | |||
fa2a232e5f | |||
da1f022df9 | |||
8e6a6b81d9 | |||
77906c4152 | |||
26bc68753b | |||
af6b263f7a | |||
a27e216e44 | |||
50e1efa448 | |||
519ac0383a | |||
3d0ef9bc4f | |||
49e23464f9 | |||
a1c9b4b80e | |||
2b1be3e5d9 | |||
e46378ec51 | |||
27ee9c85e7 | |||
21b6ec46e3 | |||
817ce5dc96 | |||
d9af28bca7 | |||
8646be7979 | |||
14ba287e0d | |||
1671e46d99 | |||
507333c463 | |||
8b320d3e9e | |||
e1be268749 | |||
1a0019e6d0 | |||
e79cdb671f | |||
f38e643cf0 | |||
b8e190cd1d | |||
9cca654bd5 | |||
35177e2d2f | |||
1a24b193e7 | |||
272915192b | |||
96774f4c52 | |||
a034f585ba | |||
365d95c36b | |||
c6313c08ae | |||
f5764c4659 | |||
aff094575b | |||
4aaaf64f8d | |||
7b88ce273f | |||
b011af89ad | |||
1bf8c1bfe7 | |||
2b39d5d111 | |||
98663af7f6 | |||
5628824bee | |||
d12d7996bc | |||
0dcf4cbff6 | |||
884e37d242 | |||
f4a24e26c3 | |||
122eccf3dc | |||
bd598788dc | |||
406482b4da | |||
a381c97ca9 | |||
8ce78ba33c | |||
f53f148c89 | |||
0086feb645 | |||
4ee55b049f | |||
90c6f121cc | |||
d3c27ae859 | |||
8f39c1de6c | |||
4df1831187 | |||
2bce761ace | |||
d78b76aceb | |||
f07f6b84d4 | |||
d297a10570 | |||
9d0b82122a |
4
.gitattributes
vendored
4
.gitattributes
vendored
@ -4,6 +4,10 @@
|
||||
*.* -eol
|
||||
|
||||
*.sh text eol=lf
|
||||
.dockerignore eol=lf
|
||||
Dockerfile eol=lf
|
||||
Dockerfile.* eol=lf
|
||||
* text=auto eol=lf
|
||||
|
||||
# lf for the docs as it's auto-generated and will otherwise trigger an uncommited error on windows
|
||||
docs/balena-cli.md text eol=lf
|
||||
|
2
.github/actions/publish/action.yml
vendored
2
.github/actions/publish/action.yml
vendored
@ -18,7 +18,7 @@ inputs:
|
||||
default: 'accounts+apple@balena.io'
|
||||
NODE_VERSION:
|
||||
type: string
|
||||
default: '16.x'
|
||||
default: '18.x'
|
||||
VERBOSE:
|
||||
type: string
|
||||
default: 'true'
|
||||
|
4
.github/actions/test/action.yml
vendored
4
.github/actions/test/action.yml
vendored
@ -15,7 +15,7 @@ inputs:
|
||||
# --- custom environment
|
||||
NODE_VERSION:
|
||||
type: string
|
||||
default: '16.x'
|
||||
default: '18.x'
|
||||
VERBOSE:
|
||||
type: string
|
||||
default: "true"
|
||||
@ -49,7 +49,7 @@ runs:
|
||||
|
||||
- name: Compress custom source
|
||||
shell: pwsh
|
||||
run: tar -acf ${{ runner.temp }}/custom.tgz .
|
||||
run: tar --exclude-vcs -acf ${{ runner.temp }}/custom.tgz .
|
||||
|
||||
- name: Upload custom artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
|
2
.github/workflows/flowzone.yml
vendored
2
.github/workflows/flowzone.yml
vendored
@ -11,7 +11,7 @@ on:
|
||||
jobs:
|
||||
flowzone:
|
||||
name: Flowzone
|
||||
uses: product-os/flowzone/.github/workflows/flowzone.yml@v4.7.1
|
||||
uses: product-os/flowzone/.github/workflows/flowzone.yml@master
|
||||
# prevent duplicate workflow executions for pull_request and pull_request_target
|
||||
if: |
|
||||
(
|
||||
|
File diff suppressed because it is too large
Load Diff
1283
CHANGELOG.md
1283
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@ -78,8 +78,8 @@ If you are a Node.js developer, you may wish to install the balena CLI via [npm]
|
||||
The npm installation involves building native (platform-specific) binary modules, which require
|
||||
some development tools to be installed first, as follows.
|
||||
|
||||
> **The balena CLI currently requires Node.js version 16.**
|
||||
> **Versions 17 and later are not yet fully supported.**
|
||||
> **The balena CLI currently requires Node.js version 18.**
|
||||
> **Versions 19 and later are not yet fully supported.**
|
||||
|
||||
### Install development tools
|
||||
|
||||
@ -89,7 +89,7 @@ some development tools to be installed first, as follows.
|
||||
$ sudo apt-get update && sudo apt-get -y install curl python3 git make g++
|
||||
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
|
||||
$ . ~/.bashrc
|
||||
$ nvm install 16
|
||||
$ nvm install 18
|
||||
```
|
||||
|
||||
The `curl` command line above uses
|
||||
@ -106,7 +106,7 @@ recommended.
|
||||
```sh
|
||||
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
|
||||
$ . ~/.bashrc
|
||||
$ nvm install 16
|
||||
$ nvm install 18
|
||||
```
|
||||
|
||||
#### **Windows** (not WSL)
|
||||
@ -114,7 +114,7 @@ $ nvm install 16
|
||||
Install:
|
||||
|
||||
* If you'd like the ability to switch between Node.js versions, install
|
||||
- Node.js v16 from the [Nodejs.org releases page](https://nodejs.org/en/download/releases/).
|
||||
- Node.js v18 from the [Nodejs.org releases page](https://nodejs.org/en/download/releases/).
|
||||
[nvm-windows](https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows)
|
||||
instead.
|
||||
* The [MSYS2 shell](https://www.msys2.org/), which provides `git`, `make`, `g++` and more:
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
import type { JsonVersions } from '../lib/commands/version';
|
||||
|
||||
import { run as oclifRun } from 'oclif';
|
||||
import { run as oclifRun } from '@oclif/core';
|
||||
import * as archiver from 'archiver';
|
||||
import * as Bluebird from 'bluebird';
|
||||
import { execFile } from 'child_process';
|
||||
@ -30,6 +30,7 @@ import * as path from 'path';
|
||||
import * as rimraf from 'rimraf';
|
||||
import * as semver from 'semver';
|
||||
import { promisify } from 'util';
|
||||
import { notarize } from '@electron/notarize';
|
||||
|
||||
import { stripIndent } from '../build/utils/lazy';
|
||||
import {
|
||||
@ -206,7 +207,6 @@ async function buildPkg() {
|
||||
const paths: Array<[string, string[], string[]]> = [
|
||||
// [platform, [source path], [destination path]]
|
||||
['*', ['open', 'xdg-open'], ['xdg-open']],
|
||||
['*', ['opn', 'xdg-open'], ['xdg-open-402']],
|
||||
['darwin', ['denymount', 'bin', 'denymount'], ['denymount']],
|
||||
];
|
||||
await Promise.all(
|
||||
@ -471,8 +471,6 @@ async function notarizeMacInstaller(): Promise<void> {
|
||||
const appleIdPassword = process.env.XCODE_APP_LOADER_PASSWORD;
|
||||
|
||||
if (appleIdPassword && teamId) {
|
||||
const { notarize } = await import('@electron/notarize');
|
||||
// https://github.com/electron/notarize#readme
|
||||
await notarize({
|
||||
tool: 'notarytool',
|
||||
teamId,
|
||||
@ -494,9 +492,10 @@ export async function buildOclifInstaller() {
|
||||
let packOpts = ['-r', ROOT];
|
||||
if (process.platform === 'darwin') {
|
||||
packOS = 'macos';
|
||||
packOpts = packOpts.concat('--targets', 'darwin-x64');
|
||||
} else if (process.platform === 'win32') {
|
||||
packOS = 'win';
|
||||
packOpts = packOpts.concat('-t', 'win32-x64');
|
||||
packOpts = packOpts.concat('--targets', 'win32-x64');
|
||||
}
|
||||
if (packOS) {
|
||||
console.log(`Building oclif installer for CLI ${version}`);
|
||||
@ -514,10 +513,11 @@ export async function buildOclifInstaller() {
|
||||
await signFilesForNotarization();
|
||||
}
|
||||
console.log('=======================================================');
|
||||
console.log(`oclif "${packCmd}" "${packOpts.join('" "')}"`);
|
||||
console.log(`oclif ${packCmd} ${packOpts.join(' ')}`);
|
||||
console.log(`cwd="${process.cwd()}" ROOT="${ROOT}"`);
|
||||
console.log('=======================================================');
|
||||
await oclifRun([packCmd].concat(...packOpts));
|
||||
const oclifPath = path.join(ROOT, 'node_modules', 'oclif');
|
||||
await oclifRun([packCmd].concat(...packOpts), oclifPath);
|
||||
await renameInstallerFiles();
|
||||
// The Windows installer is explicitly signed here (oclif doesn't do it).
|
||||
// The macOS installer is automatically signed by oclif (which runs the
|
||||
|
2
automation/capitanodoc/doc-types.d.ts
vendored
2
automation/capitanodoc/doc-types.d.ts
vendored
@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Command as OclifCommandClass } from '@oclif/command';
|
||||
import { Command as OclifCommandClass } from '@oclif/core';
|
||||
|
||||
type OclifCommand = typeof OclifCommandClass;
|
||||
|
||||
|
@ -62,12 +62,11 @@ class FakeHelpCommand {
|
||||
'$ balena help os download',
|
||||
];
|
||||
|
||||
args = [
|
||||
{
|
||||
name: 'command',
|
||||
args = {
|
||||
command: {
|
||||
description: 'command to show help for',
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
usage = 'help [command]';
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { flagUsages } from '@oclif/parser';
|
||||
import { Parser } from '@oclif/core';
|
||||
import * as ent from 'ent';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@ -37,8 +37,8 @@ function renderOclifCommand(command: OclifCommand): string[] {
|
||||
|
||||
if (!_.isEmpty(command.args)) {
|
||||
result.push('### Arguments');
|
||||
for (const arg of command.args!) {
|
||||
result.push(`#### ${arg.name.toUpperCase()}`, arg.description || '');
|
||||
for (const [name, arg] of Object.entries(command.args!)) {
|
||||
result.push(`#### ${name.toUpperCase()}`, arg.description || '');
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ function renderOclifCommand(command: OclifCommand): string[] {
|
||||
continue;
|
||||
}
|
||||
flag.name = name;
|
||||
const flagUsage = flagUsages([flag])
|
||||
const flagUsage = Parser.flagUsages([flag])
|
||||
.map(([usage, _description]) => usage)
|
||||
.join()
|
||||
.trim();
|
||||
|
@ -621,6 +621,10 @@ password
|
||||
|
||||
TCP port number of local HTTP login server (--web auth only)
|
||||
|
||||
#### -H, --hideExperimentalWarning
|
||||
|
||||
Hides warning for experimental features
|
||||
|
||||
## logout
|
||||
|
||||
Logout from your balena account.
|
||||
@ -1276,7 +1280,6 @@ Examples:
|
||||
$ balena envs --fleet myorg/myfleet
|
||||
$ balena envs --fleet MyFleet --json
|
||||
$ balena envs --fleet MyFleet --service MyService
|
||||
$ balena envs --fleet MyFleet --service MyService
|
||||
$ balena envs --fleet MyFleet --config
|
||||
$ balena envs --device 7cf02a6
|
||||
$ balena envs --device 7cf02a6 --json
|
||||
|
@ -24,6 +24,7 @@ import {
|
||||
} from './preparser';
|
||||
import { CliSettings } from './utils/bootstrap';
|
||||
import { onceAsync } from './utils/lazy';
|
||||
import { run as mainRun } from '@oclif/core';
|
||||
|
||||
/**
|
||||
* Sentry.io setup
|
||||
@ -114,10 +115,9 @@ async function oclifRun(command: string[], options: AppOptions) {
|
||||
}
|
||||
|
||||
const runPromise = (async function (shouldFlush: boolean) {
|
||||
const { CustomMain } = await import('./utils/oclif-utils');
|
||||
let isEEXIT = false;
|
||||
try {
|
||||
await CustomMain.run(command);
|
||||
await mainRun(command, options.configPath);
|
||||
} catch (error) {
|
||||
// oclif sometimes exits with ExitError code EEXIT 0 (not an error),
|
||||
// for example the `balena help` command.
|
||||
@ -130,7 +130,7 @@ async function oclifRun(command: string[], options: AppOptions) {
|
||||
}
|
||||
}
|
||||
if (shouldFlush) {
|
||||
await import('@oclif/command/flush');
|
||||
await import('@oclif/core/flush');
|
||||
}
|
||||
// TODO: figure out why we need to call fast-boot stop() here, in
|
||||
// addition to calling it in the main `run()` function in this file.
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Command from '@oclif/command';
|
||||
import { Command } from '@oclif/core';
|
||||
import {
|
||||
InsufficientPrivilegesError,
|
||||
NotAvailableInOfflineModeError,
|
||||
|
@ -15,20 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export default class GenerateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Generate a new balenaCloud API key.
|
||||
@ -41,24 +33,23 @@ export default class GenerateCmd extends Command {
|
||||
`;
|
||||
public static examples = ['$ balena api-key generate "Jenkins Key"'];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'name',
|
||||
public static args = {
|
||||
name: Args.string({
|
||||
description: 'the API key name',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'api-key generate <name>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(GenerateCmd);
|
||||
const { args: params } = await this.parse(GenerateCmd);
|
||||
|
||||
let key;
|
||||
try {
|
||||
|
@ -15,19 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
ids: string;
|
||||
}
|
||||
|
||||
export default class RevokeCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Revoke balenaCloud API keys.
|
||||
@ -42,24 +34,23 @@ export default class RevokeCmd extends Command {
|
||||
'$ balena api-key revoke 123,124,456',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'ids',
|
||||
public static args = {
|
||||
ids: Args.string({
|
||||
description: 'the API key ids',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'api-key revoke <ids>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(RevokeCmd);
|
||||
const { args: params } = await this.parse(RevokeCmd);
|
||||
|
||||
try {
|
||||
const apiKeyIds = params.ids.split(',');
|
||||
|
@ -15,17 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
user?: void;
|
||||
fleet?: string;
|
||||
}
|
||||
|
||||
export default class ApiKeysCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Print a list of balenaCloud API keys.
|
||||
@ -36,13 +30,11 @@ export default class ApiKeysCmd extends Command {
|
||||
`;
|
||||
public static examples = ['$ balena api-keys'];
|
||||
|
||||
public static args = [];
|
||||
|
||||
public static usage = 'api-keys';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
user: flags.boolean({
|
||||
user: Flags.boolean({
|
||||
char: 'u',
|
||||
description: 'show API keys for your user',
|
||||
}),
|
||||
@ -52,7 +44,7 @@ export default class ApiKeysCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(ApiKeysCmd);
|
||||
const { flags: options } = await this.parse(ApiKeysCmd);
|
||||
|
||||
try {
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
@ -62,7 +54,7 @@ export default class ApiKeysCmd extends Command {
|
||||
$select: 'actor',
|
||||
})
|
||||
).actor
|
||||
: await getBalenaSdk().auth.getUserActorId();
|
||||
: await getBalenaSdk().auth.getActorId();
|
||||
const keys = await getBalenaSdk().pine.get({
|
||||
resource: 'api_key',
|
||||
options: {
|
||||
|
@ -15,22 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
|
||||
import Command from '../../command';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
organization?: string;
|
||||
type?: string; // application device type
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
name: string;
|
||||
}
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class AppCreateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -60,22 +49,21 @@ export default class AppCreateCmd extends Command {
|
||||
'$ balena app create MyApp -o myorg --type raspberry-pi',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'name',
|
||||
public static args = {
|
||||
name: Args.string({
|
||||
description: 'app name',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'app create <name>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
organization: flags.string({
|
||||
public static flags = {
|
||||
organization: Flags.string({
|
||||
char: 'o',
|
||||
description: 'handle of the organization the app should belong to',
|
||||
}),
|
||||
type: flags.string({
|
||||
type: Flags.string({
|
||||
char: 't',
|
||||
description:
|
||||
'app device type (Check available types with `balena devices supported`)',
|
||||
@ -86,65 +74,10 @@ export default class AppCreateCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
AppCreateCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(AppCreateCmd);
|
||||
|
||||
// Ascertain device type
|
||||
const deviceType =
|
||||
options.type ||
|
||||
(await (await import('../../utils/patterns')).selectDeviceType());
|
||||
|
||||
// Ascertain organization
|
||||
const organization =
|
||||
options.organization?.toLowerCase() || (await this.getOrganization());
|
||||
|
||||
// Create application
|
||||
try {
|
||||
const application = await getBalenaSdk().models.application.create({
|
||||
name: params.name,
|
||||
deviceType,
|
||||
organization,
|
||||
applicationClass: 'app',
|
||||
});
|
||||
|
||||
// Output
|
||||
console.log(
|
||||
`App created: slug "${application.slug}", device type "${deviceType}"`,
|
||||
);
|
||||
} catch (err) {
|
||||
if ((err.message || '').toLowerCase().includes('unique')) {
|
||||
// BalenaRequestError: Request error: "organization" and "app_name" must be unique.
|
||||
throw new ExpectedError(
|
||||
`Error: An app or block or fleet with the name "${params.name}" already exists in organization "${organization}".`,
|
||||
);
|
||||
} else if ((err.message || '').toLowerCase().includes('unauthorized')) {
|
||||
// BalenaRequestError: Request error: Unauthorized
|
||||
throw new ExpectedError(
|
||||
`Error: You are not authorized to create apps in organization "${organization}".`,
|
||||
);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async getOrganization() {
|
||||
const { getOwnOrganizations } = await import('../../utils/sdk');
|
||||
const organizations = await getOwnOrganizations(getBalenaSdk(), {
|
||||
$select: ['name', 'handle'],
|
||||
});
|
||||
|
||||
if (organizations.length === 0) {
|
||||
// User is not a member of any organizations (should not happen).
|
||||
throw new Error('This account is not a member of any organizations');
|
||||
} else if (organizations.length === 1) {
|
||||
// User is a member of only one organization - use this.
|
||||
return organizations[0].handle;
|
||||
} else {
|
||||
// User is a member of multiple organizations -
|
||||
const { selectOrganization } = await import('../../utils/patterns');
|
||||
return selectOrganization(organizations);
|
||||
}
|
||||
await (
|
||||
await import('../../utils/application-create')
|
||||
).applicationCreateBase('app', options, params);
|
||||
}
|
||||
}
|
||||
|
@ -15,22 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
|
||||
import Command from '../../command';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
organization?: string;
|
||||
type?: string; // application device type
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
name: string;
|
||||
}
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class BlockCreateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -60,22 +49,21 @@ export default class BlockCreateCmd extends Command {
|
||||
'$ balena block create MyBlock -o myorg --type raspberry-pi',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'name',
|
||||
public static args = {
|
||||
name: Args.string({
|
||||
description: 'block name',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'block create <name>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
organization: flags.string({
|
||||
public static flags = {
|
||||
organization: Flags.string({
|
||||
char: 'o',
|
||||
description: 'handle of the organization the block should belong to',
|
||||
}),
|
||||
type: flags.string({
|
||||
type: Flags.string({
|
||||
char: 't',
|
||||
description:
|
||||
'block device type (Check available types with `balena devices supported`)',
|
||||
@ -86,65 +74,10 @@ export default class BlockCreateCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
BlockCreateCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(BlockCreateCmd);
|
||||
|
||||
// Ascertain device type
|
||||
const deviceType =
|
||||
options.type ||
|
||||
(await (await import('../../utils/patterns')).selectDeviceType());
|
||||
|
||||
// Ascertain organization
|
||||
const organization =
|
||||
options.organization?.toLowerCase() || (await this.getOrganization());
|
||||
|
||||
// Create application
|
||||
try {
|
||||
const application = await getBalenaSdk().models.application.create({
|
||||
name: params.name,
|
||||
deviceType,
|
||||
organization,
|
||||
applicationClass: 'block',
|
||||
});
|
||||
|
||||
// Output
|
||||
console.log(
|
||||
`Block created: slug "${application.slug}", device type "${deviceType}"`,
|
||||
);
|
||||
} catch (err) {
|
||||
if ((err.message || '').toLowerCase().includes('unique')) {
|
||||
// BalenaRequestError: Request error: "organization" and "app_name" must be unique.
|
||||
throw new ExpectedError(
|
||||
`Error: An app or block or fleet with the name "${params.name}" already exists in organization "${organization}".`,
|
||||
);
|
||||
} else if ((err.message || '').toLowerCase().includes('unauthorized')) {
|
||||
// BalenaRequestError: Request error: Unauthorized
|
||||
throw new ExpectedError(
|
||||
`Error: You are not authorized to create blocks in organization "${organization}".`,
|
||||
);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async getOrganization() {
|
||||
const { getOwnOrganizations } = await import('../../utils/sdk');
|
||||
const organizations = await getOwnOrganizations(getBalenaSdk(), {
|
||||
$select: ['name', 'handle'],
|
||||
});
|
||||
|
||||
if (organizations.length === 0) {
|
||||
// User is not a member of any organizations (should not happen).
|
||||
throw new Error('This account is not a member of any organizations');
|
||||
} else if (organizations.length === 1) {
|
||||
// User is a member of only one organization - use this.
|
||||
return organizations[0].handle;
|
||||
} else {
|
||||
// User is a member of multiple organizations -
|
||||
const { selectOrganization } = await import('../../utils/patterns');
|
||||
return selectOrganization(organizations);
|
||||
}
|
||||
await (
|
||||
await import('../../utils/application-create')
|
||||
).applicationCreateBase('block', options, params);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args, Flags } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import { getBalenaSdk } from '../utils/lazy';
|
||||
import * as cf from '../utils/common-flags';
|
||||
@ -31,6 +31,9 @@ import { buildProject, composeCliFlags } from '../utils/compose_ts';
|
||||
import type { BuildOpts, DockerCliFlags } from '../utils/docker';
|
||||
import { dockerCliFlags } from '../utils/docker';
|
||||
|
||||
// TODO: For this special one we can't use Interfaces.InferredFlags/InferredArgs
|
||||
// because of the 'registry-secrets' type which is defined in the actual code
|
||||
// as a path (string | undefined) but then the cli turns it into an object
|
||||
interface FlagsDef extends ComposeCliFlags, DockerCliFlags {
|
||||
arch?: string;
|
||||
deviceType?: string;
|
||||
@ -39,10 +42,6 @@ interface FlagsDef extends ComposeCliFlags, DockerCliFlags {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
source?: string;
|
||||
}
|
||||
|
||||
export default class BuildCmd extends Command {
|
||||
public static description = `\
|
||||
Build a project locally.
|
||||
@ -74,21 +73,18 @@ ${dockerignoreHelp}
|
||||
'$ balena build --dockerHost my.docker.host --dockerPort 2376 --ca ca.pem --key key.pem --cert cert.pem -f myFleet',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'source',
|
||||
description: 'path of project source directory',
|
||||
},
|
||||
];
|
||||
public static args = {
|
||||
source: Args.string({ description: 'path of project source directory' }),
|
||||
};
|
||||
|
||||
public static usage = 'build [source]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
arch: flags.string({
|
||||
public static flags = {
|
||||
arch: Flags.string({
|
||||
description: 'the architecture to build for',
|
||||
char: 'A',
|
||||
}),
|
||||
deviceType: flags.string({
|
||||
deviceType: Flags.string({
|
||||
description: 'the type of device this build is for',
|
||||
char: 'd',
|
||||
}),
|
||||
@ -97,15 +93,13 @@ ${dockerignoreHelp}
|
||||
...dockerCliFlags,
|
||||
// NOTE: Not supporting -h for help, because of clash with -h in DockerCliFlags
|
||||
// Revisit this in future release.
|
||||
help: flags.help({}),
|
||||
help: Flags.help({}),
|
||||
};
|
||||
|
||||
public static primary = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
BuildCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(BuildCmd);
|
||||
|
||||
await Command.checkLoggedInIf(!!options.fleet);
|
||||
|
||||
|
@ -15,7 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags } from '@oclif/core';
|
||||
import type { Interfaces } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getCliForm, stripIndent } from '../../utils/lazy';
|
||||
@ -26,26 +27,6 @@ import {
|
||||
} from '../../utils/messages';
|
||||
import type { BalenaSDK, PineDeferred } from 'balena-sdk';
|
||||
|
||||
interface FlagsDef {
|
||||
version: string; // OS version
|
||||
fleet?: string;
|
||||
dev?: boolean; // balenaOS development variant
|
||||
secureBoot?: boolean;
|
||||
device?: string;
|
||||
deviceApiKey?: string;
|
||||
deviceType?: string;
|
||||
'generate-device-api-key': boolean;
|
||||
output?: string;
|
||||
// Options for non-interactive configuration
|
||||
network?: string;
|
||||
wifiSsid?: string;
|
||||
wifiKey?: string;
|
||||
appUpdatePollInterval?: string;
|
||||
'provisioning-key-name'?: string;
|
||||
'provisioning-key-expiry-date'?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
export default class ConfigGenerateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Generate a config.json file.
|
||||
@ -81,8 +62,8 @@ export default class ConfigGenerateCmd extends Command {
|
||||
|
||||
public static usage = 'config generate';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
version: flags.string({
|
||||
public static flags = {
|
||||
version: Flags.string({
|
||||
description: 'a balenaOS version',
|
||||
required: true,
|
||||
}),
|
||||
@ -97,44 +78,44 @@ export default class ConfigGenerateCmd extends Command {
|
||||
'provisioning-key-expiry-date',
|
||||
],
|
||||
},
|
||||
deviceApiKey: flags.string({
|
||||
deviceApiKey: Flags.string({
|
||||
description:
|
||||
'custom device key - note that this is only supported on balenaOS 2.0.3+',
|
||||
char: 'k',
|
||||
}),
|
||||
deviceType: flags.string({
|
||||
deviceType: Flags.string({
|
||||
description:
|
||||
"device type slug (run 'balena devices supported' for possible values)",
|
||||
}),
|
||||
'generate-device-api-key': flags.boolean({
|
||||
'generate-device-api-key': Flags.boolean({
|
||||
description: 'generate a fresh device key for the device',
|
||||
}),
|
||||
output: flags.string({
|
||||
output: Flags.string({
|
||||
description: 'path of output file',
|
||||
char: 'o',
|
||||
}),
|
||||
// Options for non-interactive configuration
|
||||
network: flags.string({
|
||||
network: Flags.string({
|
||||
description: 'the network type to use: ethernet or wifi',
|
||||
options: ['ethernet', 'wifi'],
|
||||
}),
|
||||
wifiSsid: flags.string({
|
||||
wifiSsid: Flags.string({
|
||||
description:
|
||||
'the wifi ssid to use (used only if --network is set to wifi)',
|
||||
}),
|
||||
wifiKey: flags.string({
|
||||
wifiKey: Flags.string({
|
||||
description:
|
||||
'the wifi key to use (used only if --network is set to wifi)',
|
||||
}),
|
||||
appUpdatePollInterval: flags.string({
|
||||
appUpdatePollInterval: Flags.string({
|
||||
description:
|
||||
'supervisor cloud polling interval in minutes (e.g. for device variables)',
|
||||
}),
|
||||
'provisioning-key-name': flags.string({
|
||||
'provisioning-key-name': Flags.string({
|
||||
description: 'custom key name assigned to generated provisioning api key',
|
||||
exclusive: ['device'],
|
||||
}),
|
||||
'provisioning-key-expiry-date': flags.string({
|
||||
'provisioning-key-expiry-date': Flags.string({
|
||||
description:
|
||||
'expiry date assigned to generated provisioning api key (format: YYYY-MM-DD)',
|
||||
exclusive: ['device'],
|
||||
@ -155,7 +136,7 @@ export default class ConfigGenerateCmd extends Command {
|
||||
}
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(ConfigGenerateCmd);
|
||||
const { flags: options } = await this.parse(ConfigGenerateCmd);
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
await this.validateOptions(options);
|
||||
@ -266,7 +247,9 @@ export default class ConfigGenerateCmd extends Command {
|
||||
protected readonly deviceTypeNotAllowedMessage =
|
||||
'The --deviceType option can only be used alongside the --fleet option';
|
||||
|
||||
protected async validateOptions(options: FlagsDef) {
|
||||
protected async validateOptions(
|
||||
options: Interfaces.InferredFlags<typeof ConfigGenerateCmd.flags>,
|
||||
) {
|
||||
const { ExpectedError } = await import('../../errors');
|
||||
|
||||
if (options.device == null && options.fleet == null) {
|
||||
|
@ -15,21 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getVisuals, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
type?: string;
|
||||
drive?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
file: string;
|
||||
}
|
||||
|
||||
export default class ConfigInjectCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Inject a config.json file to a balenaOS image or attached media.
|
||||
@ -46,17 +36,16 @@ export default class ConfigInjectCmd extends Command {
|
||||
'$ balena config inject my/config.json --drive /dev/disk2',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'file',
|
||||
public static args = {
|
||||
file: Args.string({
|
||||
description: 'the path to the config.json file to inject',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'config inject <file>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
drive: cf.driveOrImg,
|
||||
help: cf.help,
|
||||
};
|
||||
@ -65,9 +54,7 @@ export default class ConfigInjectCmd extends Command {
|
||||
public static offlineCompatible = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
ConfigInjectCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(ConfigInjectCmd);
|
||||
|
||||
const { safeUmount } = await import('../../utils/umount');
|
||||
|
||||
|
@ -15,18 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getVisuals, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
type?: string;
|
||||
drive?: string;
|
||||
help: void;
|
||||
json: boolean;
|
||||
}
|
||||
|
||||
export default class ConfigReadCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Read the config.json file of a balenaOS image or attached media.
|
||||
@ -46,7 +38,7 @@ export default class ConfigReadCmd extends Command {
|
||||
|
||||
public static usage = 'config read';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
drive: cf.driveOrImg,
|
||||
help: cf.help,
|
||||
json: cf.json,
|
||||
@ -56,7 +48,7 @@ export default class ConfigReadCmd extends Command {
|
||||
public static offlineCompatible = true;
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(ConfigReadCmd);
|
||||
const { flags: options } = await this.parse(ConfigReadCmd);
|
||||
|
||||
const { safeUmount } = await import('../../utils/umount');
|
||||
|
||||
|
@ -15,19 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getVisuals, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
type?: string;
|
||||
drive?: string;
|
||||
advanced: boolean;
|
||||
help: void;
|
||||
version?: string;
|
||||
}
|
||||
|
||||
export default class ConfigReconfigureCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Interactively reconfigure a balenaOS image file or attached media.
|
||||
@ -49,14 +41,14 @@ export default class ConfigReconfigureCmd extends Command {
|
||||
|
||||
public static usage = 'config reconfigure';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
drive: cf.driveOrImg,
|
||||
advanced: flags.boolean({
|
||||
advanced: Flags.boolean({
|
||||
description: 'show advanced commands',
|
||||
char: 'v',
|
||||
}),
|
||||
help: cf.help,
|
||||
version: flags.string({
|
||||
version: Flags.string({
|
||||
description: 'balenaOS version, for example "2.32.0" or "2.44.0+rev1"',
|
||||
}),
|
||||
};
|
||||
@ -65,7 +57,7 @@ export default class ConfigReconfigureCmd extends Command {
|
||||
public static root = true;
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(ConfigReconfigureCmd);
|
||||
const { flags: options } = await this.parse(ConfigReconfigureCmd);
|
||||
|
||||
const { safeUmount } = await import('../../utils/umount');
|
||||
|
||||
|
@ -15,22 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getVisuals, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
type?: string;
|
||||
drive?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export default class ConfigWriteCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Write a key-value pair to the config.json file of an OS image or attached media.
|
||||
@ -48,22 +37,20 @@ export default class ConfigWriteCmd extends Command {
|
||||
'$ balena config write --drive balena.img os.network.connectivity.interval 300',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'key',
|
||||
public static args = {
|
||||
key: Args.string({
|
||||
description: 'the key of the config parameter to write',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
}),
|
||||
value: Args.string({
|
||||
description: 'the value of the config parameter to write',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'config write <key> <value>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
drive: cf.driveOrImg,
|
||||
help: cf.help,
|
||||
};
|
||||
@ -72,9 +59,7 @@ export default class ConfigWriteCmd extends Command {
|
||||
public static offlineCompatible = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
ConfigWriteCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(ConfigWriteCmd);
|
||||
|
||||
const { denyMount, safeUmount } = await import('../../utils/umount');
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args, Flags } from '@oclif/core';
|
||||
import type { ImageDescriptor } from '@balena/compose/dist/parse';
|
||||
|
||||
import Command from '../command';
|
||||
@ -52,6 +52,9 @@ interface ApplicationWithArch {
|
||||
application_type: [Pick<ApplicationType, 'slug' | 'supports_multicontainer'>];
|
||||
}
|
||||
|
||||
// TODO: For this special one we can't use Interfaces.InferredFlags/InferredArgs
|
||||
// because of the 'registry-secrets' type which is defined in the actual code
|
||||
// as a path (string | undefined) but then the cli turns it into an object
|
||||
interface FlagsDef extends ComposeCliFlags, DockerCliFlags {
|
||||
source?: string;
|
||||
build: boolean;
|
||||
@ -62,11 +65,6 @@ interface FlagsDef extends ComposeCliFlags, DockerCliFlags {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
fleet: string;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
export default class DeployCmd extends Command {
|
||||
public static description = `\
|
||||
Deploy a single image or a multicontainer project to a balena fleet.
|
||||
@ -105,31 +103,28 @@ ${dockerignoreHelp}
|
||||
'$ balena deploy myFleet myRepo/myImage --release-tag key1 "" key2 "value2 with spaces"',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
ca.fleetRequired,
|
||||
{
|
||||
name: 'image',
|
||||
description: 'the image to deploy',
|
||||
},
|
||||
];
|
||||
public static args = {
|
||||
fleet: ca.fleetRequired,
|
||||
image: Args.string({ description: 'the image to deploy' }),
|
||||
};
|
||||
|
||||
public static usage = 'deploy <fleet> [image]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
source: flags.string({
|
||||
public static flags = {
|
||||
source: Flags.string({
|
||||
description:
|
||||
'specify an alternate source directory; default is the working directory',
|
||||
char: 's',
|
||||
}),
|
||||
build: flags.boolean({
|
||||
build: Flags.boolean({
|
||||
description: 'force a rebuild before deploy',
|
||||
char: 'b',
|
||||
}),
|
||||
nologupload: flags.boolean({
|
||||
nologupload: Flags.boolean({
|
||||
description:
|
||||
"don't upload build logs to the dashboard with image (if building)",
|
||||
}),
|
||||
'release-tag': flags.string({
|
||||
'release-tag': Flags.string({
|
||||
description: stripIndent`
|
||||
Set release tags if the image deployment is successful. Multiple
|
||||
arguments may be provided, alternating tag keys and values (see examples).
|
||||
@ -137,7 +132,7 @@ ${dockerignoreHelp}
|
||||
`,
|
||||
multiple: true,
|
||||
}),
|
||||
draft: flags.boolean({
|
||||
draft: Flags.boolean({
|
||||
description: stripIndent`
|
||||
Deploy the release as a draft. Draft releases are ignored
|
||||
by the 'track latest' release policy but can be used through release pinning.
|
||||
@ -145,12 +140,12 @@ ${dockerignoreHelp}
|
||||
as final by default unless this option is given.`,
|
||||
default: false,
|
||||
}),
|
||||
note: flags.string({ description: 'The notes for this release' }),
|
||||
note: Flags.string({ description: 'The notes for this release' }),
|
||||
...composeCliFlags,
|
||||
...dockerCliFlags,
|
||||
// NOTE: Not supporting -h for help, because of clash with -h in DockerCliFlags
|
||||
// Revisit this in future release.
|
||||
help: flags.help({}),
|
||||
help: Flags.help({}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
@ -158,9 +153,7 @@ ${dockerignoreHelp}
|
||||
public static primary = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
DeployCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(DeployCmd);
|
||||
|
||||
(await import('events')).defaultMaxListeners = 1000;
|
||||
|
||||
@ -190,7 +183,7 @@ ${dockerignoreHelp}
|
||||
);
|
||||
|
||||
if (image) {
|
||||
options['registry-secrets'] = await getRegistrySecrets(
|
||||
(options as FlagsDef)['registry-secrets'] = await getRegistrySecrets(
|
||||
sdk,
|
||||
options['registry-secrets'],
|
||||
);
|
||||
@ -203,7 +196,7 @@ ${dockerignoreHelp}
|
||||
registrySecretsPath: options['registry-secrets'],
|
||||
});
|
||||
options.dockerfile = dockerfilePath;
|
||||
options['registry-secrets'] = registrySecrets;
|
||||
(options as FlagsDef)['registry-secrets'] = registrySecrets;
|
||||
}
|
||||
|
||||
const helpers = await import('../utils/helpers');
|
||||
@ -212,7 +205,7 @@ ${dockerignoreHelp}
|
||||
const dockerUtils = await import('../utils/docker');
|
||||
const [docker, buildOpts, composeOpts] = await Promise.all([
|
||||
dockerUtils.getDocker(options),
|
||||
dockerUtils.generateBuildOpts(options),
|
||||
dockerUtils.generateBuildOpts(options as FlagsDef),
|
||||
compose.generateOpts(options),
|
||||
]);
|
||||
|
||||
@ -346,9 +339,9 @@ ${dockerignoreHelp}
|
||||
);
|
||||
logger.logWarn(msg);
|
||||
|
||||
const [token, username, url, options] = await Promise.all([
|
||||
const [token, { username }, url, options] = await Promise.all([
|
||||
sdk.auth.getToken(),
|
||||
sdk.auth.whoami(),
|
||||
sdk.auth.getUserInfo(),
|
||||
sdk.settings.get('balenaUrl'),
|
||||
{
|
||||
// opts.appName may be prefixed by 'owner/', unlike opts.app.app_name
|
||||
@ -371,8 +364,8 @@ ${dockerignoreHelp}
|
||||
$select: ['commit'],
|
||||
});
|
||||
} else {
|
||||
const [userId, auth, apiEndpoint] = await Promise.all([
|
||||
sdk.auth.getUserId(),
|
||||
const [{ id: userId }, auth, apiEndpoint] = await Promise.all([
|
||||
sdk.auth.getUserInfo(),
|
||||
sdk.auth.getToken(),
|
||||
sdk.settings.get('apiUrl'),
|
||||
]);
|
||||
|
@ -15,21 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
yes: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DeviceDeactivateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Deactivate a device.
|
||||
@ -44,17 +34,16 @@ export default class DeviceDeactivateCmd extends Command {
|
||||
'$ balena device deactivate 7cf02a6 --yes',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: 'the UUID of the device to be deactivated',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device deactivate <uuid>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
@ -62,7 +51,7 @@ export default class DeviceDeactivateCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
const { args: params, flags: options } = await this.parse(
|
||||
DeviceDeactivateCmd,
|
||||
);
|
||||
|
||||
|
@ -15,21 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { ExpectedError } from '../../errors';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DeviceIdentifyCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Identify a device.
|
||||
@ -38,24 +29,23 @@ export default class DeviceIdentifyCmd extends Command {
|
||||
`;
|
||||
public static examples = ['$ balena device identify 23c73a1'];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: 'the uuid of the device to identify',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device identify <uuid>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(DeviceIdentifyCmd);
|
||||
const { args: params } = await this.parse(DeviceIdentifyCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,8 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { IArg } from '@oclif/parser/lib/args';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { expandForAppName } from '../../utils/helpers';
|
||||
@ -41,15 +40,6 @@ interface ExtendedDevice extends DeviceWithDeviceType {
|
||||
undervoltage_detected?: boolean;
|
||||
}
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
view: boolean;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DeviceCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Show info about a single device.
|
||||
@ -61,19 +51,18 @@ export default class DeviceCmd extends Command {
|
||||
'$ balena device 7cf02a6 --view',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: 'the device uuid',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device <uuid>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
view: flags.boolean({
|
||||
view: Flags.boolean({
|
||||
default: false,
|
||||
description: 'open device dashboard page',
|
||||
}),
|
||||
@ -83,9 +72,7 @@ export default class DeviceCmd extends Command {
|
||||
public static primary = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
DeviceCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(DeviceCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
@ -76,14 +76,14 @@ export default class DeviceInitCmd extends Command {
|
||||
|
||||
public static usage = 'device init';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
fleet: cf.fleet,
|
||||
yes: cf.yes,
|
||||
advanced: flags.boolean({
|
||||
advanced: Flags.boolean({
|
||||
char: 'v',
|
||||
description: 'show advanced configuration options',
|
||||
}),
|
||||
'os-version': flags.string({
|
||||
'os-version': Flags.string({
|
||||
description: stripIndent`
|
||||
exact version number, or a valid semver range,
|
||||
or 'latest' (includes pre-releases),
|
||||
@ -93,13 +93,13 @@ export default class DeviceInitCmd extends Command {
|
||||
`,
|
||||
}),
|
||||
drive: cf.drive,
|
||||
config: flags.string({
|
||||
config: Flags.string({
|
||||
description: 'path to the config JSON file, see `balena os build-config`',
|
||||
}),
|
||||
'provisioning-key-name': flags.string({
|
||||
'provisioning-key-name': Flags.string({
|
||||
description: 'custom key name assigned to generated provisioning api key',
|
||||
}),
|
||||
'provisioning-key-expiry-date': flags.string({
|
||||
'provisioning-key-expiry-date': Flags.string({
|
||||
description:
|
||||
'expiry date assigned to generated provisioning api key (format: YYYY-MM-DD)',
|
||||
}),
|
||||
@ -109,7 +109,7 @@ export default class DeviceInitCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(DeviceInitCmd);
|
||||
const { flags: options } = await this.parse(DeviceInitCmd);
|
||||
|
||||
// Imports
|
||||
const { promisify } = await import('util');
|
||||
|
@ -15,23 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
enable: boolean;
|
||||
disable: boolean;
|
||||
status: boolean;
|
||||
help?: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string | number;
|
||||
}
|
||||
|
||||
export default class DeviceLocalModeCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Get or manage the local mode status for a device.
|
||||
@ -47,26 +35,25 @@ export default class DeviceLocalModeCmd extends Command {
|
||||
'$ balena device local-mode 23c73a1 --status',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: 'the uuid of the device to manage',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device local-mode <uuid>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
enable: flags.boolean({
|
||||
public static flags = {
|
||||
enable: Flags.boolean({
|
||||
description: 'enable local mode',
|
||||
exclusive: ['disable', 'status'],
|
||||
}),
|
||||
disable: flags.boolean({
|
||||
disable: Flags.boolean({
|
||||
description: 'disable local mode',
|
||||
exclusive: ['enable', 'status'],
|
||||
}),
|
||||
status: flags.boolean({
|
||||
status: Flags.boolean({
|
||||
description: 'output boolean indicating local mode status',
|
||||
exclusive: ['enable', 'disable'],
|
||||
}),
|
||||
@ -76,7 +63,7 @@ export default class DeviceLocalModeCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
const { args: params, flags: options } = await this.parse(
|
||||
DeviceLocalModeCmd,
|
||||
);
|
||||
|
||||
|
@ -15,12 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import type {
|
||||
BalenaSDK,
|
||||
Device,
|
||||
DeviceType,
|
||||
PineOptions,
|
||||
PineTypedResult,
|
||||
} from 'balena-sdk';
|
||||
@ -30,15 +28,6 @@ import { ExpectedError } from '../../errors';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
|
||||
interface FlagsDef {
|
||||
fleet?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DeviceMoveCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Move one or more devices to another fleet.
|
||||
@ -57,18 +46,17 @@ export default class DeviceMoveCmd extends Command {
|
||||
'$ balena device move 7cf02a6 -f myorg/mynewfleet',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description:
|
||||
'comma-separated list (no blank spaces) of device UUIDs to be moved',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device move <uuid(s)>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
fleet: cf.fleet,
|
||||
help: cf.help,
|
||||
};
|
||||
@ -103,9 +91,7 @@ export default class DeviceMoveCmd extends Command {
|
||||
}
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
DeviceMoveCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(DeviceMoveCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
@ -138,7 +124,6 @@ export default class DeviceMoveCmd extends Command {
|
||||
balena: BalenaSDK,
|
||||
devices: Awaited<ReturnType<typeof this.getDevices>>,
|
||||
) {
|
||||
const { getExpandedProp } = await import('../../utils/pine');
|
||||
// deduplicate the slugs
|
||||
const deviceCpuArchs = Array.from(
|
||||
new Set(
|
||||
@ -148,48 +133,44 @@ export default class DeviceMoveCmd extends Command {
|
||||
),
|
||||
);
|
||||
|
||||
const deviceTypeOptions = {
|
||||
$select: 'slug',
|
||||
$expand: {
|
||||
is_of__cpu_architecture: {
|
||||
$select: 'slug',
|
||||
},
|
||||
const allCpuArches = await balena.pine.get({
|
||||
resource: 'cpu_architecture',
|
||||
options: {
|
||||
$select: ['id', 'slug'],
|
||||
},
|
||||
} satisfies PineOptions<DeviceType>;
|
||||
const deviceTypes = (await balena.models.deviceType.getAllSupported(
|
||||
deviceTypeOptions,
|
||||
)) as Array<PineTypedResult<DeviceType, typeof deviceTypeOptions>>;
|
||||
});
|
||||
|
||||
const compatibleDeviceTypeSlugs = new Set(
|
||||
deviceTypes
|
||||
.filter((deviceType) => {
|
||||
const deviceTypeArch = getExpandedProp(
|
||||
deviceType.is_of__cpu_architecture,
|
||||
'slug',
|
||||
)!;
|
||||
return deviceCpuArchs.every((deviceCpuArch) =>
|
||||
balena.models.os.isArchitectureCompatibleWith(
|
||||
deviceCpuArch,
|
||||
deviceTypeArch,
|
||||
),
|
||||
);
|
||||
})
|
||||
.map((deviceType) => deviceType.slug),
|
||||
);
|
||||
const compatibleCpuArchIds = allCpuArches
|
||||
.filter((cpuArch) => {
|
||||
return deviceCpuArchs.every((deviceCpuArch) =>
|
||||
balena.models.os.isArchitectureCompatibleWith(
|
||||
deviceCpuArch,
|
||||
cpuArch.slug,
|
||||
),
|
||||
);
|
||||
})
|
||||
.map((deviceType) => deviceType.id);
|
||||
|
||||
const patterns = await import('../../utils/patterns');
|
||||
try {
|
||||
const application = await patterns.selectApplication(
|
||||
(app) =>
|
||||
compatibleDeviceTypeSlugs.has(app.is_for__device_type[0].slug) &&
|
||||
devices.some(
|
||||
(device) => device.belongs_to__application.__id !== app.id,
|
||||
),
|
||||
{
|
||||
is_for__device_type: {
|
||||
$any: {
|
||||
$alias: 'dt',
|
||||
$expr: {
|
||||
dt: {
|
||||
is_of__cpu_architecture: { $in: compatibleCpuArchIds },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
);
|
||||
return application;
|
||||
} catch (err) {
|
||||
if (!compatibleDeviceTypeSlugs.size) {
|
||||
if (!compatibleCpuArchIds.length) {
|
||||
throw new ExpectedError(
|
||||
`${err.message}\nDo all devices have a compatible architecture?`,
|
||||
);
|
||||
|
@ -15,24 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy';
|
||||
import type { Device } from 'balena-sdk';
|
||||
import { ExpectedError } from '../../errors';
|
||||
|
||||
interface FlagsDef {
|
||||
version?: string;
|
||||
yes: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DeviceOsUpdateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Start a Host OS update for a device.
|
||||
@ -50,18 +39,17 @@ export default class DeviceOsUpdateCmd extends Command {
|
||||
'$ balena device os-update 23c73a1 --version 2.31.0+rev1.prod',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: 'the uuid of the device to update',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device os-update <uuid>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
version: flags.string({
|
||||
public static flags = {
|
||||
version: Flags.string({
|
||||
description: 'a balenaOS version',
|
||||
}),
|
||||
yes: cf.yes,
|
||||
@ -71,7 +59,7 @@ export default class DeviceOsUpdateCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
const { args: params, flags: options } = await this.parse(
|
||||
DeviceOsUpdateCmd,
|
||||
);
|
||||
|
||||
|
@ -15,22 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { getExpandedProp } from '../../utils/pine';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
releaseToPinTo?: string;
|
||||
}
|
||||
|
||||
export default class DevicePinCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Pin a device to a release.
|
||||
@ -44,28 +34,26 @@ export default class DevicePinCmd extends Command {
|
||||
'$ balena device pin 7cf02a6 91165e5',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: 'the uuid of the device to pin to a release',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'releaseToPinTo',
|
||||
}),
|
||||
releaseToPinTo: Args.string({
|
||||
description: 'the commit of the release for the device to get pinned to',
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device pin <uuid> [releaseToPinTo]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(DevicePinCmd);
|
||||
const { args: params } = await this.parse(DevicePinCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,24 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
enable: boolean;
|
||||
disable: boolean;
|
||||
status: boolean;
|
||||
help?: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DevicePublicUrlCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Get or manage the public URL for a device.
|
||||
@ -49,26 +37,25 @@ export default class DevicePublicUrlCmd extends Command {
|
||||
'$ balena device public-url 23c73a1 --status',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: 'the uuid of the device to manage',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device public-url <uuid>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
enable: flags.boolean({
|
||||
public static flags = {
|
||||
enable: Flags.boolean({
|
||||
description: 'enable the public URL',
|
||||
exclusive: ['disable', 'status'],
|
||||
}),
|
||||
disable: flags.boolean({
|
||||
disable: Flags.boolean({
|
||||
description: 'disable the public URL',
|
||||
exclusive: ['enable', 'status'],
|
||||
}),
|
||||
status: flags.boolean({
|
||||
status: Flags.boolean({
|
||||
description: 'determine if public URL is enabled',
|
||||
exclusive: ['enable', 'disable'],
|
||||
}),
|
||||
@ -78,7 +65,7 @@ export default class DevicePublicUrlCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
const { args: params, flags: options } = await this.parse(
|
||||
DevicePublicUrlCmd,
|
||||
);
|
||||
|
||||
|
@ -15,20 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DevicePurgeCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Purge data from a device.
|
||||
@ -46,22 +37,21 @@ export default class DevicePurgeCmd extends Command {
|
||||
|
||||
public static usage = 'device purge <uuid>';
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: 'comma-separated list (no blank spaces) of device UUIDs',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(DevicePurgeCmd);
|
||||
const { args: params } = await this.parse(DevicePurgeCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
const ux = getCliUx();
|
||||
|
@ -15,21 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
force: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DeviceRebootCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Restart a device.
|
||||
@ -38,17 +28,16 @@ export default class DeviceRebootCmd extends Command {
|
||||
`;
|
||||
public static examples = ['$ balena device reboot 23c73a1'];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: 'the uuid of the device to reboot',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device reboot <uuid>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
force: cf.force,
|
||||
help: cf.help,
|
||||
};
|
||||
@ -56,9 +45,7 @@ export default class DeviceRebootCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
DeviceRebootCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(DeviceRebootCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,24 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Flags } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import * as ca from '../../utils/common-args';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
|
||||
interface FlagsDef {
|
||||
uuid?: string;
|
||||
deviceType?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
fleet: string;
|
||||
}
|
||||
|
||||
export default class DeviceRegisterCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Register a new device.
|
||||
@ -51,16 +40,18 @@ export default class DeviceRegisterCmd extends Command {
|
||||
'$ balena device register myorg/myfleet --uuid <uuid> --deviceType <deviceTypeSlug>',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [ca.fleetRequired];
|
||||
public static args = {
|
||||
fleet: ca.fleetRequired,
|
||||
};
|
||||
|
||||
public static usage = 'device register <fleet>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
uuid: flags.string({
|
||||
public static flags = {
|
||||
uuid: Flags.string({
|
||||
description: 'custom uuid',
|
||||
char: 'u',
|
||||
}),
|
||||
deviceType: flags.string({
|
||||
deviceType: Flags.string({
|
||||
description:
|
||||
"device type slug (run 'balena devices supported' for possible values)",
|
||||
}),
|
||||
@ -70,7 +61,7 @@ export default class DeviceRegisterCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
const { args: params, flags: options } = await this.parse(
|
||||
DeviceRegisterCmd,
|
||||
);
|
||||
|
||||
|
@ -15,21 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
newName?: string;
|
||||
}
|
||||
|
||||
export default class DeviceRenameCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Rename a device.
|
||||
@ -43,28 +33,26 @@ export default class DeviceRenameCmd extends Command {
|
||||
'$ balena device rename 7cf02a6 MyPi',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: 'the uuid of the device to rename',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'newName',
|
||||
}),
|
||||
newName: Args.string({
|
||||
description: 'the new name for the device',
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device rename <uuid> [newName]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(DeviceRenameCmd);
|
||||
const { args: params } = await this.parse(DeviceRenameCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,8 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy';
|
||||
@ -26,15 +25,6 @@ import type {
|
||||
CurrentServiceWithCommit,
|
||||
} from 'balena-sdk';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
service?: string;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DeviceRestartCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Restart containers on a device.
|
||||
@ -55,19 +45,18 @@ export default class DeviceRestartCmd extends Command {
|
||||
'$ balena device restart 23c73a1 -s myService1,myService2',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description:
|
||||
'comma-separated list (no blank spaces) of device UUIDs to restart',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device restart <uuid>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
service: flags.string({
|
||||
public static flags = {
|
||||
service: Flags.string({
|
||||
description:
|
||||
'comma-separated list (no blank spaces) of service names to restart',
|
||||
char: 's',
|
||||
@ -78,9 +67,7 @@ export default class DeviceRestartCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
DeviceRestartCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(DeviceRestartCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
const ux = getCliUx();
|
||||
|
@ -15,21 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
yes: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DeviceRmCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Remove one or more devices.
|
||||
@ -45,18 +35,17 @@ export default class DeviceRmCmd extends Command {
|
||||
'$ balena device rm 7cf02a6 --yes',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description:
|
||||
'comma-separated list (no blank spaces) of device UUIDs to be removed',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device rm <uuid(s)>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
@ -64,9 +53,7 @@ export default class DeviceRmCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
DeviceRmCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(DeviceRmCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
const patterns = await import('../../utils/patterns');
|
||||
|
@ -15,22 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { ExpectedError } from '../../errors';
|
||||
|
||||
interface FlagsDef {
|
||||
force: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DeviceShutdownCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Shutdown a device.
|
||||
@ -39,17 +29,16 @@ export default class DeviceShutdownCmd extends Command {
|
||||
`;
|
||||
public static examples = ['$ balena device shutdown 23c73a1'];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: 'the uuid of the device to shutdown',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device shutdown <uuid>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
force: cf.force,
|
||||
help: cf.help,
|
||||
};
|
||||
@ -57,7 +46,7 @@ export default class DeviceShutdownCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
const { args: params, flags: options } = await this.parse(
|
||||
DeviceShutdownCmd,
|
||||
);
|
||||
|
||||
|
@ -15,20 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export default class DeviceTrackFleetCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Make a device track the fleet's pinned release.
|
||||
@ -37,24 +28,23 @@ export default class DeviceTrackFleetCmd extends Command {
|
||||
`;
|
||||
public static examples = ['$ balena device track-fleet 7cf02a6'];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'uuid',
|
||||
public static args = {
|
||||
uuid: Args.string({
|
||||
description: "the uuid of the device to make track the fleet's release",
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'device track-fleet <uuid>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(DeviceTrackFleetCmd);
|
||||
const { args: params } = await this.parse(DeviceTrackFleetCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { expandForAppName } from '../../utils/helpers';
|
||||
@ -24,12 +23,6 @@ import { applicationIdInfo, jsonInfo } from '../../utils/messages';
|
||||
|
||||
import type { Device, PineOptions } from 'balena-sdk';
|
||||
|
||||
interface FlagsDef {
|
||||
fleet?: string;
|
||||
help: void;
|
||||
json: boolean;
|
||||
}
|
||||
|
||||
const devicesSelectFields = {
|
||||
$select: [
|
||||
'id',
|
||||
@ -62,7 +55,7 @@ export default class DevicesCmd extends Command {
|
||||
|
||||
public static usage = 'devices';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
fleet: cf.fleet,
|
||||
json: cf.json,
|
||||
help: cf.help,
|
||||
@ -73,7 +66,7 @@ export default class DevicesCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(DevicesCmd);
|
||||
const { flags: options } = await this.parse(DevicesCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
const devicesOptions = {
|
||||
|
@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags } from '@oclif/core';
|
||||
import type * as BalenaSdk from 'balena-sdk';
|
||||
import * as _ from 'lodash';
|
||||
import Command from '../../command';
|
||||
@ -23,11 +23,6 @@ import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
|
||||
import { CommandHelp } from '../../utils/oclif-utils';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
json?: boolean;
|
||||
}
|
||||
|
||||
export default class DevicesSupportedCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
List the supported device types (like 'raspberrypi3' or 'intel-nuc').
|
||||
@ -50,16 +45,16 @@ export default class DevicesSupportedCmd extends Command {
|
||||
new CommandHelp({ args: DevicesSupportedCmd.args }).defaultUsage()
|
||||
).trim();
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
json: flags.boolean({
|
||||
json: Flags.boolean({
|
||||
char: 'j',
|
||||
description: 'produce JSON output instead of tabular output',
|
||||
}),
|
||||
};
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(DevicesSupportedCmd);
|
||||
const { flags: options } = await this.parse(DevicesSupportedCmd);
|
||||
const pineOptions = {
|
||||
$select: ['slug', 'name'],
|
||||
$expand: {
|
||||
|
23
lib/commands/env/add.ts
vendored
23
lib/commands/env/add.ts
vendored
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import type * as BalenaSdk from 'balena-sdk';
|
||||
import Command from '../../command';
|
||||
import { ExpectedError } from '../../errors';
|
||||
@ -78,23 +78,21 @@ export default class EnvAddCmd extends Command {
|
||||
'$ balena env add EDITOR vim --device 7cf02a6,d6f1433 --service MyService,MyService2',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'name',
|
||||
public static args = {
|
||||
name: Args.string({
|
||||
required: true,
|
||||
description: 'environment or config variable name',
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
}),
|
||||
value: Args.string({
|
||||
required: false,
|
||||
description:
|
||||
"variable value; if omitted, use value from this process' environment",
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'env add <name> [value]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
fleet: { ...cf.fleet, exclusive: ['device'] },
|
||||
device: { ...cf.device, exclusive: ['fleet'] },
|
||||
help: cf.help,
|
||||
@ -103,9 +101,7 @@ export default class EnvAddCmd extends Command {
|
||||
};
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
EnvAddCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(EnvAddCmd);
|
||||
const cmd = this;
|
||||
|
||||
if (!options.fleet && !options.device) {
|
||||
@ -268,6 +264,7 @@ async function getServiceIdForApp(
|
||||
): Promise<number> {
|
||||
let serviceId: number | undefined;
|
||||
const services = await sdk.models.service.getAllByApplication(appSlug, {
|
||||
$select: 'id',
|
||||
$filter: { service_name: serviceName },
|
||||
});
|
||||
if (services.length > 0) {
|
||||
|
38
lib/commands/env/rename.ts
vendored
38
lib/commands/env/rename.ts
vendored
@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
|
||||
import * as cf from '../../utils/common-flags';
|
||||
@ -22,20 +22,6 @@ import * as ec from '../../utils/env-common';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { parseAsInteger } from '../../utils/validation';
|
||||
|
||||
type IArg<T> = import('@oclif/parser').args.IArg<T>;
|
||||
|
||||
interface FlagsDef {
|
||||
config: boolean;
|
||||
device: boolean;
|
||||
service: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
id: number;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export default class EnvRenameCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Change the value of a config or env var for a fleet, device or service.
|
||||
@ -54,24 +40,22 @@ export default class EnvRenameCmd extends Command {
|
||||
'$ balena env rename 678678 1 --device --config',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'id',
|
||||
public static args = {
|
||||
id: Args.integer({
|
||||
required: true,
|
||||
description: "variable's numeric database ID",
|
||||
parse: (input) => parseAsInteger(input, 'id'),
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
parse: async (input) => parseAsInteger(input, 'id'),
|
||||
}),
|
||||
value: Args.string({
|
||||
required: true,
|
||||
description:
|
||||
"variable value; if omitted, use value from this process' environment",
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'env rename <id> <value>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
config: ec.booleanConfig,
|
||||
device: ec.booleanDevice,
|
||||
service: ec.booleanService,
|
||||
@ -79,9 +63,7 @@ export default class EnvRenameCmd extends Command {
|
||||
};
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: opt } = this.parse<FlagsDef, ArgsDef>(
|
||||
EnvRenameCmd,
|
||||
);
|
||||
const { args: params, flags: opt } = await this.parse(EnvRenameCmd);
|
||||
|
||||
await Command.checkLoggedIn();
|
||||
|
||||
|
34
lib/commands/env/rm.ts
vendored
34
lib/commands/env/rm.ts
vendored
@ -15,26 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
|
||||
import * as ec from '../../utils/env-common';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { parseAsInteger } from '../../utils/validation';
|
||||
|
||||
type IArg<T> = import('@oclif/parser').args.IArg<T>;
|
||||
|
||||
interface FlagsDef {
|
||||
config: boolean;
|
||||
device: boolean;
|
||||
service: boolean;
|
||||
yes: boolean;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export default class EnvRmCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Remove a config or env var from a fleet, device or service.
|
||||
@ -57,22 +44,21 @@ export default class EnvRmCmd extends Command {
|
||||
'$ balena env rm 789789 --device --service --yes',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'id',
|
||||
public static args = {
|
||||
id: Args.integer({
|
||||
required: true,
|
||||
description: "variable's numeric database ID",
|
||||
parse: (input) => parseAsInteger(input, 'id'),
|
||||
},
|
||||
];
|
||||
parse: async (input) => parseAsInteger(input, 'id'),
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'env rm <id>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
config: ec.booleanConfig,
|
||||
device: ec.booleanDevice,
|
||||
service: ec.booleanService,
|
||||
yes: flags.boolean({
|
||||
yes: Flags.boolean({
|
||||
char: 'y',
|
||||
description:
|
||||
'do not prompt for confirmation before deleting the variable',
|
||||
@ -81,9 +67,7 @@ export default class EnvRmCmd extends Command {
|
||||
};
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: opt } = this.parse<FlagsDef, ArgsDef>(
|
||||
EnvRmCmd,
|
||||
);
|
||||
const { args: params, flags: opt } = await this.parse(EnvRmCmd);
|
||||
|
||||
await Command.checkLoggedIn();
|
||||
|
||||
|
@ -14,7 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags } from '@oclif/core';
|
||||
import type { Interfaces } from '@oclif/core';
|
||||
import type * as SDK from 'balena-sdk';
|
||||
import * as _ from 'lodash';
|
||||
import Command from '../command';
|
||||
@ -23,14 +24,7 @@ import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../utils/lazy';
|
||||
import { applicationIdInfo } from '../utils/messages';
|
||||
|
||||
interface FlagsDef {
|
||||
fleet?: string;
|
||||
config: boolean;
|
||||
device?: string; // device UUID
|
||||
json: boolean;
|
||||
help: void;
|
||||
service?: string; // service name
|
||||
}
|
||||
type FlagsDef = Interfaces.InferredFlags<typeof EnvsCmd.flags>;
|
||||
|
||||
interface EnvironmentVariableInfo extends SDK.EnvironmentVariableBase {
|
||||
fleet?: string | null; // fleet slug
|
||||
@ -93,7 +87,6 @@ export default class EnvsCmd extends Command {
|
||||
'$ balena envs --fleet myorg/myfleet',
|
||||
'$ balena envs --fleet MyFleet --json',
|
||||
'$ balena envs --fleet MyFleet --service MyService',
|
||||
'$ balena envs --fleet MyFleet --service MyService',
|
||||
'$ balena envs --fleet MyFleet --config',
|
||||
'$ balena envs --device 7cf02a6',
|
||||
'$ balena envs --device 7cf02a6 --json',
|
||||
@ -103,9 +96,9 @@ export default class EnvsCmd extends Command {
|
||||
|
||||
public static usage = 'envs';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
fleet: { ...cf.fleet, exclusive: ['device'] },
|
||||
config: flags.boolean({
|
||||
config: Flags.boolean({
|
||||
default: false,
|
||||
char: 'c',
|
||||
description: 'show configuration variables only',
|
||||
@ -118,7 +111,7 @@ export default class EnvsCmd extends Command {
|
||||
};
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(EnvsCmd);
|
||||
const { flags: options } = await this.parse(EnvsCmd);
|
||||
|
||||
const variables: EnvironmentVariableInfo[] = [];
|
||||
|
||||
@ -209,6 +202,7 @@ async function validateServiceName(
|
||||
fleetSlug: string,
|
||||
) {
|
||||
const services = await sdk.models.service.getAllByApplication(fleetSlug, {
|
||||
$select: 'id',
|
||||
$filter: { service_name: serviceName },
|
||||
});
|
||||
if (services.length === 0) {
|
||||
|
@ -15,22 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
|
||||
import Command from '../../command';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
organization?: string;
|
||||
type?: string; // application device type
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
name: string;
|
||||
}
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class FleetCreateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -60,22 +49,21 @@ export default class FleetCreateCmd extends Command {
|
||||
'$ balena fleet create MyFleet -o myorg --type raspberry-pi',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'name',
|
||||
public static args = {
|
||||
name: Args.string({
|
||||
description: 'fleet name',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'fleet create <name>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
organization: flags.string({
|
||||
public static flags = {
|
||||
organization: Flags.string({
|
||||
char: 'o',
|
||||
description: 'handle of the organization the fleet should belong to',
|
||||
}),
|
||||
type: flags.string({
|
||||
type: Flags.string({
|
||||
char: 't',
|
||||
description:
|
||||
'fleet device type (Check available types with `balena devices supported`)',
|
||||
@ -86,64 +74,10 @@ export default class FleetCreateCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
FleetCreateCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(FleetCreateCmd);
|
||||
|
||||
// Ascertain device type
|
||||
const deviceType =
|
||||
options.type ||
|
||||
(await (await import('../../utils/patterns')).selectDeviceType());
|
||||
|
||||
// Ascertain organization
|
||||
const organization =
|
||||
options.organization?.toLowerCase() || (await this.getOrganization());
|
||||
|
||||
// Create application
|
||||
try {
|
||||
const application = await getBalenaSdk().models.application.create({
|
||||
name: params.name,
|
||||
deviceType,
|
||||
organization,
|
||||
});
|
||||
|
||||
// Output
|
||||
console.log(
|
||||
`Fleet created: slug "${application.slug}", device type "${deviceType}"`,
|
||||
);
|
||||
} catch (err) {
|
||||
if ((err.message || '').toLowerCase().includes('unique')) {
|
||||
// BalenaRequestError: Request error: "organization" and "app_name" must be unique.
|
||||
throw new ExpectedError(
|
||||
`Error: An app or block or fleet with the name "${params.name}" already exists in organization "${organization}".`,
|
||||
);
|
||||
} else if ((err.message || '').toLowerCase().includes('unauthorized')) {
|
||||
// BalenaRequestError: Request error: Unauthorized
|
||||
throw new ExpectedError(
|
||||
`Error: You are not authorized to create fleets in organization "${organization}".`,
|
||||
);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async getOrganization() {
|
||||
const { getOwnOrganizations } = await import('../../utils/sdk');
|
||||
const organizations = await getOwnOrganizations(getBalenaSdk(), {
|
||||
$select: ['name', 'handle'],
|
||||
});
|
||||
|
||||
if (organizations.length === 0) {
|
||||
// User is not a member of any organizations (should not happen).
|
||||
throw new Error('This account is not a member of any organizations');
|
||||
} else if (organizations.length === 1) {
|
||||
// User is a member of only one organization - use this.
|
||||
return organizations[0].handle;
|
||||
} else {
|
||||
// User is a member of multiple organizations -
|
||||
const { selectOrganization } = await import('../../utils/patterns');
|
||||
return selectOrganization(organizations);
|
||||
}
|
||||
await (
|
||||
await import('../../utils/application-create')
|
||||
).applicationCreateBase('fleet', options, params);
|
||||
}
|
||||
}
|
||||
|
@ -15,24 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { flags as flagsType } from '@oclif/command';
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags } from '@oclif/core';
|
||||
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import * as ca from '../../utils/common-args';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
import type { DataOutputOptions } from '../../framework';
|
||||
|
||||
interface FlagsDef extends DataOutputOptions {
|
||||
help: void;
|
||||
view: boolean;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
fleet: string;
|
||||
}
|
||||
|
||||
export default class FleetCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -48,13 +37,15 @@ export default class FleetCmd extends Command {
|
||||
'$ balena fleet myorg/myfleet --view',
|
||||
];
|
||||
|
||||
public static args = [ca.fleetRequired];
|
||||
public static args = {
|
||||
fleet: ca.fleetRequired,
|
||||
};
|
||||
|
||||
public static usage = 'fleet <fleet>';
|
||||
|
||||
public static flags: flagsType.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
view: flags.boolean({
|
||||
view: Flags.boolean({
|
||||
default: false,
|
||||
description: 'open fleet dashboard page',
|
||||
}),
|
||||
@ -65,9 +56,7 @@ export default class FleetCmd extends Command {
|
||||
public static primary = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
FleetCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(FleetCmd);
|
||||
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
|
||||
|
@ -15,22 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { getExpandedProp } from '../../utils/pine';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
slug: string;
|
||||
releaseToPinTo?: string;
|
||||
}
|
||||
|
||||
export default class FleetPinCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Pin a fleet to a release.
|
||||
@ -44,28 +34,26 @@ export default class FleetPinCmd extends Command {
|
||||
'$ balena fleet pin myorg/myfleet 91165e5',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'slug',
|
||||
public static args = {
|
||||
slug: Args.string({
|
||||
description: 'the slug of the fleet to pin to a release',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'releaseToPinTo',
|
||||
}),
|
||||
releaseToPinTo: Args.string({
|
||||
description: 'the commit of the release for the fleet to get pinned to',
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'fleet pin <slug> [releaseToPinTo]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(FleetPinCmd);
|
||||
const { args: params } = await this.parse(FleetPinCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,22 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { flags } from '@oclif/command';
|
||||
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import * as ca from '../../utils/common-args';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
fleet: string;
|
||||
}
|
||||
|
||||
export default class FleetPurgeCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Purge data from a fleet.
|
||||
@ -46,18 +36,20 @@ export default class FleetPurgeCmd extends Command {
|
||||
'$ balena fleet purge myorg/myfleet',
|
||||
];
|
||||
|
||||
public static args = [ca.fleetRequired];
|
||||
public static args = {
|
||||
fleet: ca.fleetRequired,
|
||||
};
|
||||
|
||||
public static usage = 'fleet purge <fleet>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(FleetPurgeCmd);
|
||||
const { args: params } = await this.parse(FleetPurgeCmd);
|
||||
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
@ -23,15 +23,6 @@ import * as ca from '../../utils/common-args';
|
||||
import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
fleet: string;
|
||||
newName?: string;
|
||||
}
|
||||
|
||||
export default class FleetRenameCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Rename a fleet.
|
||||
@ -50,24 +41,23 @@ export default class FleetRenameCmd extends Command {
|
||||
'$ balena fleet rename myorg/oldname NewName',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
ca.fleetRequired,
|
||||
{
|
||||
name: 'newName',
|
||||
public static args = {
|
||||
fleet: ca.fleetRequired,
|
||||
newName: Args.string({
|
||||
description: 'the new name for the fleet',
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'fleet rename <fleet> [newName]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(FleetRenameCmd);
|
||||
const { args: params } = await this.parse(FleetRenameCmd);
|
||||
|
||||
const { validateApplicationName } = await import('../../utils/validation');
|
||||
const { ExpectedError } = await import('../../errors');
|
||||
|
@ -15,22 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { flags } from '@oclif/command';
|
||||
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import * as ca from '../../utils/common-args';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
fleet: string;
|
||||
}
|
||||
|
||||
export default class FleetRestartCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Restart a fleet.
|
||||
@ -45,18 +35,20 @@ export default class FleetRestartCmd extends Command {
|
||||
'$ balena fleet restart myorg/myfleet',
|
||||
];
|
||||
|
||||
public static args = [ca.fleetRequired];
|
||||
public static args = {
|
||||
fleet: ca.fleetRequired,
|
||||
};
|
||||
|
||||
public static usage = 'fleet restart <fleet>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(FleetRestartCmd);
|
||||
const { args: params } = await this.parse(FleetRestartCmd);
|
||||
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
|
||||
|
@ -15,23 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { flags } from '@oclif/command';
|
||||
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import * as ca from '../../utils/common-args';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
|
||||
interface FlagsDef {
|
||||
yes: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
fleet: string;
|
||||
}
|
||||
|
||||
export default class FleetRmCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Remove a fleet.
|
||||
@ -49,11 +38,13 @@ export default class FleetRmCmd extends Command {
|
||||
'$ balena fleet rm myorg/myfleet',
|
||||
];
|
||||
|
||||
public static args = [ca.fleetRequired];
|
||||
public static args = {
|
||||
fleet: ca.fleetRequired,
|
||||
};
|
||||
|
||||
public static usage = 'fleet rm <fleet>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
@ -61,9 +52,7 @@ export default class FleetRmCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
FleetRmCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(FleetRmCmd);
|
||||
|
||||
const { confirm } = await import('../../utils/patterns');
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
|
@ -15,20 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type { IArg } from '@oclif/parser/lib/args';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
slug: string;
|
||||
}
|
||||
|
||||
export default class FleetTrackLatestCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Make this fleet track the latest release.
|
||||
@ -40,24 +31,23 @@ export default class FleetTrackLatestCmd extends Command {
|
||||
'$ balena fleet track-latest myfleet',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'slug',
|
||||
public static args = {
|
||||
slug: Args.string({
|
||||
description: 'the slug of the fleet to make track the latest release',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'fleet track-latest <slug>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(FleetTrackLatestCmd);
|
||||
const { args: params } = await this.parse(FleetTrackLatestCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,24 +15,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import type * as BalenaSdk from 'balena-sdk';
|
||||
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../utils/lazy';
|
||||
import type { DataSetOutputOptions } from '../framework';
|
||||
|
||||
interface ExtendedApplication extends ApplicationWithDeviceType {
|
||||
interface ExtendedApplication extends ApplicationWithDeviceTypeSlug {
|
||||
device_count: number;
|
||||
online_devices: number;
|
||||
device_type?: string;
|
||||
}
|
||||
|
||||
interface FlagsDef extends DataSetOutputOptions {
|
||||
help: void;
|
||||
verbose?: boolean;
|
||||
}
|
||||
|
||||
export default class FleetsCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
List all fleets.
|
||||
@ -47,7 +41,7 @@ export default class FleetsCmd extends Command {
|
||||
|
||||
public static usage = 'fleets';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
...cf.dataSetOutputFlags,
|
||||
help: cf.help,
|
||||
};
|
||||
@ -56,19 +50,24 @@ export default class FleetsCmd extends Command {
|
||||
public static primary = true;
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(FleetsCmd);
|
||||
const { flags: options } = await this.parse(FleetsCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
const pineOptions = {
|
||||
$select: ['id', 'app_name', 'slug'],
|
||||
$expand: {
|
||||
is_for__device_type: { $select: 'slug' },
|
||||
owns__device: { $select: 'is_online' },
|
||||
},
|
||||
} satisfies BalenaSdk.PineOptions<BalenaSdk.Application>;
|
||||
// Get applications
|
||||
const applications =
|
||||
(await balena.models.application.getAllDirectlyAccessible({
|
||||
$select: ['id', 'app_name', 'slug'],
|
||||
$expand: {
|
||||
is_for__device_type: { $select: 'slug' },
|
||||
owns__device: { $select: 'is_online' },
|
||||
},
|
||||
})) as ExtendedApplication[];
|
||||
(await balena.models.application.getAllDirectlyAccessible(
|
||||
pineOptions,
|
||||
)) as Array<
|
||||
BalenaSdk.PineTypedResult<BalenaSdk.Application, typeof pineOptions>
|
||||
> as ExtendedApplication[];
|
||||
|
||||
// Add extended properties
|
||||
applications.forEach((application) => {
|
||||
|
@ -15,6 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
import { CommandHelp } from '../../utils/oclif-utils';
|
||||
@ -27,12 +28,6 @@ import { CommandHelp } from '../../utils/oclif-utils';
|
||||
// - https://github.com/balena-io/balena-cli/pull/1455#discussion_r334308357
|
||||
// - https://github.com/balena-io/balena-cli/pull/1455#discussion_r334308526
|
||||
|
||||
interface ArgsDef {
|
||||
image: string;
|
||||
type: string;
|
||||
config: string;
|
||||
}
|
||||
|
||||
export default class OsinitCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Do actual init of the device with the preconfigured os image.
|
||||
@ -41,20 +36,17 @@ export default class OsinitCmd extends Command {
|
||||
Use \`balena os initialize <image>\` instead.
|
||||
`;
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'image',
|
||||
public static args = {
|
||||
image: Args.string({
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'type',
|
||||
}),
|
||||
type: Args.string({
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'config',
|
||||
}),
|
||||
config: Args.string({
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = (
|
||||
'internal osinit ' +
|
||||
@ -66,7 +58,7 @@ export default class OsinitCmd extends Command {
|
||||
public static offlineCompatible = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<{}, ArgsDef>(OsinitCmd);
|
||||
const { args: params } = await this.parse(OsinitCmd);
|
||||
|
||||
const config = JSON.parse(params.config);
|
||||
|
||||
|
@ -15,23 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args, Flags } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../utils/lazy';
|
||||
import { applicationIdInfo } from '../utils/messages';
|
||||
import { parseAsLocalHostnameOrIp } from '../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
fleet?: string;
|
||||
pollInterval?: number;
|
||||
help?: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
deviceIpOrHostname?: string;
|
||||
}
|
||||
|
||||
export default class JoinCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Move a local device to a fleet on another balena server.
|
||||
@ -63,20 +53,19 @@ export default class JoinCmd extends Command {
|
||||
'$ balena join 192.168.1.25 --fleet MyFleet',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'deviceIpOrHostname',
|
||||
public static args = {
|
||||
deviceIpOrHostname: Args.string({
|
||||
description: 'the IP or hostname of device',
|
||||
parse: parseAsLocalHostnameOrIp,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
// Hardcoded to preserve camelcase
|
||||
public static usage = 'join [deviceIpOrHostname]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
fleet: cf.fleet,
|
||||
pollInterval: flags.integer({
|
||||
pollInterval: Flags.integer({
|
||||
description: 'the interval in minutes to check for updates',
|
||||
char: 'i',
|
||||
}),
|
||||
@ -87,9 +76,7 @@ export default class JoinCmd extends Command {
|
||||
public static primary = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
JoinCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(JoinCmd);
|
||||
|
||||
const promote = await import('../utils/promote');
|
||||
const sdk = getBalenaSdk();
|
||||
|
@ -15,21 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
name: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export default class KeyAddCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Add an SSH key to balenaCloud.
|
||||
@ -60,21 +51,19 @@ export default class KeyAddCmd extends Command {
|
||||
'$ balena key add Main %userprofile%.sshid_rsa.pub',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'name',
|
||||
public static args = {
|
||||
name: Args.string({
|
||||
description: 'the SSH key name',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: `path`,
|
||||
}),
|
||||
path: Args.string({
|
||||
description: `the path to the public key file`,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'key add <name> [path]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
@ -83,7 +72,7 @@ export default class KeyAddCmd extends Command {
|
||||
public static readStdin = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(KeyAddCmd);
|
||||
const { args: params } = await this.parse(KeyAddCmd);
|
||||
|
||||
let key: string;
|
||||
if (params.path != null) {
|
||||
|
@ -15,22 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
|
||||
import { parseAsInteger } from '../../utils/validation';
|
||||
|
||||
type IArg<T> = import('@oclif/parser').args.IArg<T>;
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export default class KeyCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Display an SSH key.
|
||||
@ -40,25 +30,24 @@ export default class KeyCmd extends Command {
|
||||
|
||||
public static examples = ['$ balena key 17'];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'id',
|
||||
public static args = {
|
||||
id: Args.integer({
|
||||
description: 'balenaCloud ID for the SSH key',
|
||||
parse: (x) => parseAsInteger(x, 'id'),
|
||||
parse: async (x) => parseAsInteger(x, 'id'),
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'key <id>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<{}, ArgsDef>(KeyCmd);
|
||||
const { args: params } = await this.parse(KeyCmd);
|
||||
|
||||
const key = await getBalenaSdk().models.key.get(params.id);
|
||||
|
||||
|
@ -15,23 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { parseAsInteger } from '../../utils/validation';
|
||||
|
||||
type IArg<T> = import('@oclif/parser').args.IArg<T>;
|
||||
|
||||
interface FlagsDef {
|
||||
yes: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export default class KeyRmCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Remove an SSH key from balenaCloud.
|
||||
@ -43,18 +32,17 @@ export default class KeyRmCmd extends Command {
|
||||
|
||||
public static examples = ['$ balena key rm 17', '$ balena key rm 17 --yes'];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'id',
|
||||
public static args = {
|
||||
id: Args.integer({
|
||||
description: 'balenaCloud ID for the SSH key',
|
||||
parse: (x) => parseAsInteger(x, 'id'),
|
||||
parse: async (x) => parseAsInteger(x, 'id'),
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'key rm <id>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
@ -62,9 +50,7 @@ export default class KeyRmCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
KeyRmCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(KeyRmCmd);
|
||||
|
||||
const patterns = await import('../../utils/patterns');
|
||||
|
||||
|
@ -15,15 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
export default class KeysCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
List the SSH keys in balenaCloud.
|
||||
@ -34,14 +29,14 @@ export default class KeysCmd extends Command {
|
||||
|
||||
public static usage = 'keys';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
this.parse<FlagsDef, {}>(KeysCmd);
|
||||
await this.parse(KeysCmd);
|
||||
|
||||
const keys = await getBalenaSdk().models.key.getAll();
|
||||
|
||||
|
@ -15,20 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { stripIndent } from '../utils/lazy';
|
||||
import { parseAsLocalHostnameOrIp } from '../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
help?: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
deviceIpOrHostname?: string;
|
||||
}
|
||||
|
||||
export default class LeaveCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Remove a local device from its balena fleet.
|
||||
@ -51,17 +43,16 @@ export default class LeaveCmd extends Command {
|
||||
'$ balena leave 192.168.1.25',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'deviceIpOrHostname',
|
||||
public static args = {
|
||||
deviceIpOrHostname: Args.string({
|
||||
description: 'the device IP or hostname',
|
||||
parse: parseAsLocalHostnameOrIp,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'leave [deviceIpOrHostname]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
@ -69,7 +60,7 @@ export default class LeaveCmd extends Command {
|
||||
public static primary = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(LeaveCmd);
|
||||
const { args: params } = await this.parse(LeaveCmd);
|
||||
|
||||
const promote = await import('../utils/promote');
|
||||
const logger = await Command.getLogger();
|
||||
|
@ -15,20 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import { promisify } from 'util';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
target: string;
|
||||
}
|
||||
|
||||
export default class LocalConfigureCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
(Re)configure a balenaOS drive or image.
|
||||
@ -41,17 +33,16 @@ export default class LocalConfigureCmd extends Command {
|
||||
'$ balena local configure path/to/image.img',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'target',
|
||||
public static args = {
|
||||
target: Args.string({
|
||||
description: 'path of drive or image to configure',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'local configure <target>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
@ -59,7 +50,7 @@ export default class LocalConfigureCmd extends Command {
|
||||
public static offlineCompatible = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(LocalConfigureCmd);
|
||||
const { args: params } = await this.parse(LocalConfigureCmd);
|
||||
|
||||
const reconfix = await import('reconfix');
|
||||
const { denyMount, safeUmount } = await import('../../utils/umount');
|
||||
|
@ -15,23 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import type { BlockDevice } from 'etcher-sdk/build/source-destination';
|
||||
import Command from '../../command';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getChalk, getVisuals, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
yes: boolean;
|
||||
drive?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
image: string;
|
||||
}
|
||||
|
||||
export default class LocalFlashCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Flash an image to a drive.
|
||||
@ -49,17 +39,16 @@ export default class LocalFlashCmd extends Command {
|
||||
'$ balena local flash path/to/balenaos.img --drive /dev/disk2 --yes',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'image',
|
||||
public static args = {
|
||||
image: Args.string({
|
||||
description: 'path to OS image',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'local flash <image>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
drive: cf.drive,
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
@ -68,9 +57,7 @@ export default class LocalFlashCmd extends Command {
|
||||
public static offlineCompatible = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
LocalFlashCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(LocalFlashCmd);
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
const { promisify } = await import('util');
|
||||
|
@ -15,11 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent, getCliForm } from '../utils/lazy';
|
||||
import { ExpectedError } from '../errors';
|
||||
import type { WhoamiResult } from 'balena-sdk';
|
||||
|
||||
interface FlagsDef {
|
||||
token: boolean;
|
||||
@ -30,10 +31,7 @@ interface FlagsDef {
|
||||
password?: string;
|
||||
port?: number;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
token?: string;
|
||||
hideExperimentalWarning: boolean;
|
||||
}
|
||||
|
||||
export default class LoginCmd extends Command {
|
||||
@ -59,37 +57,34 @@ export default class LoginCmd extends Command {
|
||||
'$ balena login --credentials --email johndoe@gmail.com --password secret',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
// Capitano allowed -t to be type boolean|string, which oclif does not.
|
||||
// So -t is now bool, and we check first arg for token content.
|
||||
name: 'token',
|
||||
public static args = {
|
||||
token: Args.string({
|
||||
hidden: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'login';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
web: flags.boolean({
|
||||
public static flags = {
|
||||
web: Flags.boolean({
|
||||
default: false,
|
||||
char: 'w',
|
||||
description: 'web-based login',
|
||||
exclusive: ['token', 'credentials'],
|
||||
}),
|
||||
token: flags.boolean({
|
||||
token: Flags.boolean({
|
||||
default: false,
|
||||
char: 't',
|
||||
description: 'session token or API key',
|
||||
exclusive: ['web', 'credentials'],
|
||||
}),
|
||||
credentials: flags.boolean({
|
||||
credentials: Flags.boolean({
|
||||
default: false,
|
||||
char: 'c',
|
||||
description: 'credential-based login',
|
||||
exclusive: ['web', 'token'],
|
||||
}),
|
||||
email: flags.string({
|
||||
email: Flags.string({
|
||||
char: 'e',
|
||||
description: 'email',
|
||||
exclusive: ['user'],
|
||||
@ -97,32 +92,35 @@ export default class LoginCmd extends Command {
|
||||
}),
|
||||
// Capitano version of this command had a second alias for email, 'u'.
|
||||
// Using an oclif hidden flag to support the same behaviour.
|
||||
user: flags.string({
|
||||
user: Flags.string({
|
||||
char: 'u',
|
||||
hidden: true,
|
||||
exclusive: ['email'],
|
||||
dependsOn: ['credentials'],
|
||||
}),
|
||||
password: flags.string({
|
||||
password: Flags.string({
|
||||
char: 'p',
|
||||
description: 'password',
|
||||
dependsOn: ['credentials'],
|
||||
}),
|
||||
port: flags.integer({
|
||||
port: Flags.integer({
|
||||
char: 'P',
|
||||
description:
|
||||
'TCP port number of local HTTP login server (--web auth only)',
|
||||
dependsOn: ['web'],
|
||||
}),
|
||||
hideExperimentalWarning: Flags.boolean({
|
||||
char: 'H',
|
||||
default: false,
|
||||
description: 'Hides warning for experimental features',
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static primary = true;
|
||||
|
||||
public async run() {
|
||||
const { flags: options, args: params } = this.parse<FlagsDef, ArgsDef>(
|
||||
LoginCmd,
|
||||
);
|
||||
const { flags: options, args: params } = await this.parse(LoginCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
const messages = await import('../utils/messages');
|
||||
@ -137,9 +135,24 @@ export default class LoginCmd extends Command {
|
||||
console.log(`\nLogging in to ${balenaUrl}`);
|
||||
await this.doLogin(options, balenaUrl, params.token);
|
||||
|
||||
const username = await balena.auth.whoami();
|
||||
// We can safely assume this won't be undefined as doLogin will throw if this call fails
|
||||
// We also don't need to worry too much about the amount of calls to whoami
|
||||
// as these are cached by the SDK
|
||||
const whoamiResult = (await balena.auth.whoami()) as WhoamiResult;
|
||||
|
||||
console.info(`Successfully logged in as: ${username}`);
|
||||
if (whoamiResult.actorType !== 'user' && !options.hideExperimentalWarning) {
|
||||
console.info(stripIndent`
|
||||
----------------------------------------------------------------------------------------
|
||||
You are logging in with a ${whoamiResult.actorType} key.
|
||||
This is an experimental feature and many features of the CLI might not work as expected.
|
||||
We sure hope you know what you are doing.
|
||||
----------------------------------------------------------------------------------------
|
||||
`);
|
||||
}
|
||||
|
||||
console.info(
|
||||
`Successfully logged in as: ${this.getLoggedInMessage(whoamiResult)}`,
|
||||
);
|
||||
console.info(`\
|
||||
|
||||
Find out about the available commands by running:
|
||||
@ -149,6 +162,16 @@ Find out about the available commands by running:
|
||||
${messages.reachingOut}`);
|
||||
}
|
||||
|
||||
private getLoggedInMessage(whoami: WhoamiResult): string {
|
||||
if (whoami.actorType === 'user') {
|
||||
return whoami.username;
|
||||
}
|
||||
|
||||
const identifier =
|
||||
whoami.actorType === 'device' ? whoami.uuid : whoami.slug;
|
||||
return `${whoami.actorType} ${identifier}`;
|
||||
}
|
||||
|
||||
async doLogin(
|
||||
loginOptions: FlagsDef,
|
||||
balenaUrl: string = 'balena-cloud.com',
|
||||
@ -165,7 +188,14 @@ ${messages.reachingOut}`);
|
||||
}
|
||||
const balena = getBalenaSdk();
|
||||
await balena.auth.loginWithToken(token!);
|
||||
if (!(await balena.auth.whoami())) {
|
||||
try {
|
||||
if (!(await balena.auth.whoami())) {
|
||||
throw new ExpectedError('Token authentication failed');
|
||||
}
|
||||
} catch (err) {
|
||||
if (process.env.DEBUG) {
|
||||
console.error(`Get user info failed with: ${err.message}`);
|
||||
}
|
||||
throw new ExpectedError('Token authentication failed');
|
||||
}
|
||||
return;
|
||||
|
@ -29,7 +29,7 @@ export default class LogoutCmd extends Command {
|
||||
public static usage = 'logout';
|
||||
|
||||
public async run() {
|
||||
this.parse<{}, {}>(LogoutCmd);
|
||||
await this.parse(LogoutCmd);
|
||||
await getBalenaSdk().auth.logout();
|
||||
}
|
||||
}
|
||||
|
@ -15,24 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../utils/lazy';
|
||||
import { LogMessage } from 'balena-sdk';
|
||||
import { IArg } from '@oclif/parser/lib/args';
|
||||
|
||||
interface FlagsDef {
|
||||
'max-retry'?: number;
|
||||
tail?: boolean;
|
||||
service?: string[];
|
||||
system?: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
device: string;
|
||||
}
|
||||
|
||||
const MAX_RETRY = 1000;
|
||||
|
||||
@ -67,35 +54,34 @@ export default class LogsCmd extends Command {
|
||||
'$ balena logs 23c73a1.local --system --service my-service',
|
||||
];
|
||||
|
||||
public static args: Array<IArg<any>> = [
|
||||
{
|
||||
name: 'device',
|
||||
public static args = {
|
||||
device: Args.string({
|
||||
description: 'device UUID, IP, or .local address',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'logs <device>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
'max-retry': flags.integer({
|
||||
public static flags = {
|
||||
'max-retry': Flags.integer({
|
||||
description: stripIndent`
|
||||
Maximum number of reconnection attempts on "connection lost" errors
|
||||
(use 0 to disable auto reconnection).`,
|
||||
}),
|
||||
tail: flags.boolean({
|
||||
tail: Flags.boolean({
|
||||
default: false,
|
||||
description: 'continuously stream output',
|
||||
char: 't',
|
||||
}),
|
||||
service: flags.string({
|
||||
service: Flags.string({
|
||||
description: stripIndent`
|
||||
Reject logs not originating from this service.
|
||||
This can be used in combination with --system or other --service flags.`,
|
||||
char: 's',
|
||||
multiple: true,
|
||||
}),
|
||||
system: flags.boolean({
|
||||
system: Flags.boolean({
|
||||
default: false,
|
||||
description:
|
||||
'Only show system logs. This can be used in combination with --service.',
|
||||
@ -107,9 +93,7 @@ export default class LogsCmd extends Command {
|
||||
public static primary = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
LogsCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(LogsCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
const { serviceIdToName } = await import('../utils/cloud');
|
||||
|
@ -15,22 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import { ExpectedError } from '../errors';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
device?: string; // device UUID
|
||||
dev?: string; // Alias for device.
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
note: string;
|
||||
}
|
||||
|
||||
export default class NoteCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Set a device note.
|
||||
@ -46,18 +36,17 @@ export default class NoteCmd extends Command {
|
||||
'$ cat note.txt | balena note --device 7cf02a6',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'note',
|
||||
public static args = {
|
||||
note: Args.string({
|
||||
description: 'note content',
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'note <|note>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
device: { exclusive: ['dev'], ...cf.device },
|
||||
dev: flags.string({
|
||||
dev: Flags.string({
|
||||
exclusive: ['device'],
|
||||
hidden: true,
|
||||
}),
|
||||
@ -69,9 +58,7 @@ export default class NoteCmd extends Command {
|
||||
public static readStdin = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
NoteCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(NoteCmd);
|
||||
|
||||
params.note = params.note || this.stdin;
|
||||
|
||||
|
@ -15,15 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
export default class OrgsCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
List all organizations.
|
||||
@ -34,14 +29,14 @@ export default class OrgsCmd extends Command {
|
||||
|
||||
public static usage = 'orgs';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
this.parse<FlagsDef, {}>(OrgsCmd);
|
||||
await this.parse(OrgsCmd);
|
||||
|
||||
const { getOwnOrganizations } = await import('../utils/sdk');
|
||||
|
||||
|
@ -15,24 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getCliForm, stripIndent } from '../../utils/lazy';
|
||||
import * as _ from 'lodash';
|
||||
import type { DeviceTypeJson } from 'balena-sdk';
|
||||
|
||||
interface FlagsDef {
|
||||
advanced: boolean;
|
||||
output: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
image: string;
|
||||
'device-type': string;
|
||||
}
|
||||
|
||||
export default class OsBuildConfigCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Prepare a configuration file for use by the 'os configure' command.
|
||||
@ -46,27 +35,25 @@ export default class OsBuildConfigCmd extends Command {
|
||||
'$ balena os configure ../path/rpi3.img --device 7cf02a6 --config rpi3-config.json',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'image',
|
||||
public static args = {
|
||||
image: Args.string({
|
||||
description: 'os image',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'device-type',
|
||||
}),
|
||||
'device-type': Args.string({
|
||||
description: 'device type',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'os build-config <image> <device-type>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
advanced: flags.boolean({
|
||||
public static flags = {
|
||||
advanced: Flags.boolean({
|
||||
description: 'show advanced configuration options',
|
||||
char: 'v',
|
||||
}),
|
||||
output: flags.string({
|
||||
output: Flags.string({
|
||||
description: 'path to output JSON file',
|
||||
char: 'o',
|
||||
required: true,
|
||||
@ -77,9 +64,7 @@ export default class OsBuildConfigCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
OsBuildConfigCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(OsBuildConfigCmd);
|
||||
|
||||
const { writeFile } = (await import('fs')).promises;
|
||||
|
||||
|
@ -15,7 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import type { Interfaces } from '@oclif/core';
|
||||
import type * as BalenaSdk from 'balena-sdk';
|
||||
import { promisify } from 'util';
|
||||
import * as _ from 'lodash';
|
||||
@ -31,29 +32,7 @@ import {
|
||||
|
||||
const CONNECTIONS_FOLDER = '/system-connections';
|
||||
|
||||
interface FlagsDef {
|
||||
advanced?: boolean;
|
||||
fleet?: string;
|
||||
config?: string;
|
||||
'config-app-update-poll-interval'?: number;
|
||||
'config-network'?: string;
|
||||
'config-wifi-key'?: string;
|
||||
'config-wifi-ssid'?: string;
|
||||
dev?: boolean; // balenaOS development variant
|
||||
secureBoot?: boolean;
|
||||
device?: string; // device UUID
|
||||
'device-type'?: string;
|
||||
help?: void;
|
||||
version?: string;
|
||||
'system-connection': string[];
|
||||
'initial-device-name'?: string;
|
||||
'provisioning-key-name'?: string;
|
||||
'provisioning-key-expiry-date'?: string;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
image: string;
|
||||
}
|
||||
type FlagsDef = Interfaces.InferredFlags<typeof OsConfigureCmd.flags>;
|
||||
|
||||
interface Answers {
|
||||
appUpdatePollInterval: number; // in minutes
|
||||
@ -111,40 +90,39 @@ export default class OsConfigureCmd extends Command {
|
||||
'$ balena os configure ../path/rpi3.img -f MyFinFleet --device-type raspberrypi3 --config myWifiConfig.json',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'image',
|
||||
public static args = {
|
||||
image: Args.string({
|
||||
required: true,
|
||||
description: 'path to a balenaOS image file, e.g. "rpi3.img"',
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'os configure <image>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
advanced: flags.boolean({
|
||||
public static flags = {
|
||||
advanced: Flags.boolean({
|
||||
char: 'v',
|
||||
description:
|
||||
'ask advanced configuration questions (when in interactive mode)',
|
||||
}),
|
||||
fleet: { ...cf.fleet, exclusive: ['device'] },
|
||||
config: flags.string({
|
||||
config: Flags.string({
|
||||
description:
|
||||
'path to a pre-generated config.json file to be injected in the OS image',
|
||||
exclusive: ['provisioning-key-name', 'provisioning-key-expiry-date'],
|
||||
}),
|
||||
'config-app-update-poll-interval': flags.integer({
|
||||
'config-app-update-poll-interval': Flags.integer({
|
||||
description:
|
||||
'supervisor cloud polling interval in minutes (e.g. for variable updates)',
|
||||
}),
|
||||
'config-network': flags.string({
|
||||
'config-network': Flags.string({
|
||||
description: 'device network type (non-interactive configuration)',
|
||||
options: ['ethernet', 'wifi'],
|
||||
}),
|
||||
'config-wifi-key': flags.string({
|
||||
'config-wifi-key': Flags.string({
|
||||
description: 'WiFi key (password) (non-interactive configuration)',
|
||||
}),
|
||||
'config-wifi-ssid': flags.string({
|
||||
'config-wifi-ssid': Flags.string({
|
||||
description: 'WiFi SSID (network name) (non-interactive configuration)',
|
||||
}),
|
||||
dev: cf.dev,
|
||||
@ -157,29 +135,29 @@ export default class OsConfigureCmd extends Command {
|
||||
'provisioning-key-expiry-date',
|
||||
],
|
||||
},
|
||||
'device-type': flags.string({
|
||||
'device-type': Flags.string({
|
||||
description:
|
||||
'device type slug (e.g. "raspberrypi3") to override the fleet device type',
|
||||
}),
|
||||
'initial-device-name': flags.string({
|
||||
'initial-device-name': Flags.string({
|
||||
description:
|
||||
'This option will set the device name when the device provisions',
|
||||
}),
|
||||
version: flags.string({
|
||||
version: Flags.string({
|
||||
description: 'balenaOS version, for example "2.32.0" or "2.44.0+rev1"',
|
||||
}),
|
||||
'system-connection': flags.string({
|
||||
'system-connection': Flags.string({
|
||||
multiple: true,
|
||||
char: 'c',
|
||||
required: false,
|
||||
description:
|
||||
"paths to local files to place into the 'system-connections' directory",
|
||||
}),
|
||||
'provisioning-key-name': flags.string({
|
||||
'provisioning-key-name': Flags.string({
|
||||
description: 'custom key name assigned to generated provisioning api key',
|
||||
exclusive: ['config', 'device'],
|
||||
}),
|
||||
'provisioning-key-expiry-date': flags.string({
|
||||
'provisioning-key-expiry-date': Flags.string({
|
||||
description:
|
||||
'expiry date assigned to generated provisioning api key (format: YYYY-MM-DD)',
|
||||
exclusive: ['config', 'device'],
|
||||
@ -190,9 +168,7 @@ export default class OsConfigureCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
OsConfigureCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(OsConfigureCmd);
|
||||
|
||||
await validateOptions(options);
|
||||
|
||||
@ -204,7 +180,7 @@ export default class OsConfigureCmd extends Command {
|
||||
const helpers = await import('../../utils/helpers');
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
|
||||
let app: ApplicationWithDeviceType | undefined;
|
||||
let app: ApplicationWithDeviceTypeSlug | undefined;
|
||||
let device;
|
||||
let deviceTypeSlug: string;
|
||||
|
||||
@ -223,7 +199,7 @@ export default class OsConfigureCmd extends Command {
|
||||
$expand: {
|
||||
is_for__device_type: { $select: 'slug' },
|
||||
},
|
||||
})) as ApplicationWithDeviceType;
|
||||
})) as ApplicationWithDeviceTypeSlug;
|
||||
await checkDeviceTypeCompatibility(options, app);
|
||||
deviceTypeSlug =
|
||||
options['device-type'] || app.is_for__device_type[0].slug;
|
||||
|
@ -15,21 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
output: string;
|
||||
version?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
type: string;
|
||||
}
|
||||
|
||||
export default class OsDownloadCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Download an unconfigured OS image.
|
||||
@ -65,23 +55,22 @@ export default class OsDownloadCmd extends Command {
|
||||
'$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img --version menu-esr',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'type',
|
||||
public static args = {
|
||||
type: Args.string({
|
||||
description: 'the device type',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'os download <type>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
output: flags.string({
|
||||
public static flags = {
|
||||
output: Flags.string({
|
||||
description: 'output path',
|
||||
char: 'o',
|
||||
required: true,
|
||||
}),
|
||||
version: flags.string({
|
||||
version: Flags.string({
|
||||
description: stripIndent`
|
||||
version number (ESR or non-ESR versions),
|
||||
or semver range (non-ESR versions only),
|
||||
@ -96,9 +85,7 @@ export default class OsDownloadCmd extends Command {
|
||||
};
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
OsDownloadCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(OsDownloadCmd);
|
||||
|
||||
// balenaOS ESR versions require user authentication
|
||||
if (options.version) {
|
||||
|
@ -15,22 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getCliForm, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
type: string;
|
||||
drive?: string;
|
||||
yes: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
image: string;
|
||||
}
|
||||
|
||||
const INIT_WARNING_MESSAGE = `
|
||||
|
||||
Note: Initializing the device may ask for administrative permissions
|
||||
@ -52,17 +41,16 @@ export default class OsInitializeCmd extends Command {
|
||||
'$ balena os initialize ../path/rpi.img --type raspberry-pi',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'image',
|
||||
public static args = {
|
||||
image: Args.string({
|
||||
description: 'path to OS image',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'os initialize <image>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
type: cf.deviceType,
|
||||
drive: cf.drive,
|
||||
yes: cf.yes,
|
||||
@ -72,9 +60,7 @@ export default class OsInitializeCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
OsInitializeCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(OsInitializeCmd);
|
||||
|
||||
const { getManifest, sudo } = await import('../../utils/helpers');
|
||||
|
||||
|
@ -15,20 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
esr?: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
type: string;
|
||||
}
|
||||
|
||||
export default class OsVersionsCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Show available balenaOS versions for the given device type.
|
||||
@ -42,28 +33,25 @@ export default class OsVersionsCmd extends Command {
|
||||
|
||||
public static examples = ['$ balena os versions raspberrypi3'];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'type',
|
||||
public static args = {
|
||||
type: Args.string({
|
||||
description: 'device type',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'os versions <type>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
esr: flags.boolean({
|
||||
esr: Flags.boolean({
|
||||
description: 'select balenaOS ESR versions',
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
OsVersionsCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(OsVersionsCmd);
|
||||
|
||||
const { formatOsVersion, getOsVersions } = await import(
|
||||
'../../utils/cloud'
|
||||
|
@ -25,11 +25,10 @@ import {
|
||||
stripIndent,
|
||||
} from '../utils/lazy';
|
||||
import { applicationIdInfo } from '../utils/messages';
|
||||
import type { DockerConnectionCliFlags } from '../utils/docker';
|
||||
import { dockerConnectionCliFlags } from '../utils/docker';
|
||||
import { parseAsInteger } from '../utils/validation';
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import * as _ from 'lodash';
|
||||
import type {
|
||||
Application,
|
||||
@ -41,21 +40,6 @@ import type {
|
||||
} from 'balena-sdk';
|
||||
import type { Preloader } from 'balena-preload';
|
||||
|
||||
interface FlagsDef extends DockerConnectionCliFlags {
|
||||
fleet?: string;
|
||||
commit?: string;
|
||||
'splash-image'?: string;
|
||||
'dont-check-arch': boolean;
|
||||
'pin-device-to-release': boolean;
|
||||
'additional-space'?: number;
|
||||
'add-certificate'?: string[];
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
image: string;
|
||||
}
|
||||
|
||||
export default class PreloadCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Preload a release on a disk image (or Edison zip archive).
|
||||
@ -89,19 +73,18 @@ export default class PreloadCmd extends Command {
|
||||
'$ balena preload balena.img',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'image',
|
||||
public static args = {
|
||||
image: Args.string({
|
||||
description: 'the image file path',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'preload <image>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
fleet: cf.fleet,
|
||||
commit: flags.string({
|
||||
commit: Flags.string({
|
||||
description: `\
|
||||
The commit hash of the release to preload. Use "current" to specify the current
|
||||
release (ignored if no appId is given). The current release is usually also the
|
||||
@ -112,27 +95,27 @@ https://github.com/balena-io-examples/staged-releases\
|
||||
`,
|
||||
char: 'c',
|
||||
}),
|
||||
'splash-image': flags.string({
|
||||
'splash-image': Flags.string({
|
||||
description: 'path to a png image to replace the splash screen',
|
||||
char: 's',
|
||||
}),
|
||||
'dont-check-arch': flags.boolean({
|
||||
'dont-check-arch': Flags.boolean({
|
||||
default: false,
|
||||
description:
|
||||
'disable architecture compatibility check between image and fleet',
|
||||
}),
|
||||
'pin-device-to-release': flags.boolean({
|
||||
default: false,
|
||||
'pin-device-to-release': Flags.boolean({
|
||||
allowNo: true,
|
||||
description:
|
||||
'pin the preloaded device to the preloaded release on provision',
|
||||
char: 'p',
|
||||
}),
|
||||
'additional-space': flags.integer({
|
||||
'additional-space': Flags.integer({
|
||||
description:
|
||||
'expand the image by this amount of bytes instead of automatically estimating the required amount',
|
||||
parse: (x) => parseAsInteger(x, 'additional-space'),
|
||||
parse: async (x) => parseAsInteger(x, 'additional-space'),
|
||||
}),
|
||||
'add-certificate': flags.string({
|
||||
'add-certificate': Flags.string({
|
||||
description: `\
|
||||
Add the given certificate (in PEM format) to /etc/ssl/certs in the preloading container.
|
||||
The file name must end with '.crt' and must not be already contained in the preloader's
|
||||
@ -144,14 +127,14 @@ Can be repeated to add multiple certificates.\
|
||||
...dockerConnectionCliFlags,
|
||||
// Redefining --dockerPort here (defined already in dockerConnectionCliFlags)
|
||||
// without -p alias, to avoid clash with -p alias of pin-device-to-release
|
||||
dockerPort: flags.integer({
|
||||
dockerPort: Flags.integer({
|
||||
description:
|
||||
'Docker daemon TCP port number (hint: 2375 for balena devices)',
|
||||
parse: (p) => parseAsInteger(p, 'dockerPort'),
|
||||
parse: async (p) => parseAsInteger(p, 'dockerPort'),
|
||||
}),
|
||||
// Not supporting -h for help, because of clash with -h in DockerCliFlags
|
||||
// Revisit this in future release.
|
||||
help: flags.help({}),
|
||||
help: Flags.help({}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
@ -159,9 +142,7 @@ Can be repeated to add multiple certificates.\
|
||||
public static primary = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
PreloadCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(PreloadCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
const balenaPreload = await import('balena-preload');
|
||||
@ -230,7 +211,7 @@ Can be repeated to add multiple certificates.\
|
||||
const splashImage = options['splash-image'];
|
||||
const additionalSpace = options['additional-space'];
|
||||
const dontCheckArch = options['dont-check-arch'] || false;
|
||||
const pinDevice = options['pin-device-to-release'] || false;
|
||||
const pinDevice = options['pin-device-to-release'];
|
||||
|
||||
if (dontCheckArch && !fleetSlug) {
|
||||
throw new ExpectedError(
|
||||
@ -257,7 +238,7 @@ Can be repeated to add multiple certificates.\
|
||||
splashImage,
|
||||
undefined, // TODO: Currently always undefined, investigate approach in ssh command.
|
||||
dontCheckArch,
|
||||
pinDevice,
|
||||
pinDevice ?? false,
|
||||
certificates,
|
||||
additionalSpace,
|
||||
);
|
||||
@ -450,14 +431,14 @@ Can be repeated to add multiple certificates.\
|
||||
async offerToDisableAutomaticUpdates(
|
||||
application: Pick<Application, 'id' | 'should_track_latest_release'>,
|
||||
commit: string,
|
||||
pinDevice: boolean,
|
||||
pinDevice: boolean | undefined,
|
||||
) {
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
if (
|
||||
this.isCurrentCommit(commit) ||
|
||||
!application.should_track_latest_release ||
|
||||
pinDevice
|
||||
pinDevice != null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@ -476,8 +457,9 @@ through the web dashboard or programatically through the balena API / SDK.
|
||||
Documentation about release policies and pinning can be found at:
|
||||
https://www.balena.io/docs/learn/deploy/release-strategy/release-policy/
|
||||
|
||||
Alternatively, the --pin-device-to-release flag may be used to pin only the
|
||||
preloaded device to the selected release.
|
||||
Alternatively, the --pin-device-to-release or --no-pin-device-to-release flags may be used
|
||||
to avoid this interactive confirmation and pin only the preloaded device to the selected release
|
||||
or keep it unpinned respectively.
|
||||
|
||||
Would you like to disable automatic updates for this fleet now?\
|
||||
`;
|
||||
@ -511,7 +493,7 @@ Would you like to disable automatic updates for this fleet now?\
|
||||
options: {
|
||||
slug?: string;
|
||||
commit?: string;
|
||||
pinDevice: boolean;
|
||||
pinDevice?: boolean;
|
||||
},
|
||||
) {
|
||||
await preloader.prepare();
|
||||
|
@ -15,7 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import type { Interfaces } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../utils/lazy';
|
||||
@ -34,30 +35,7 @@ enum BuildTarget {
|
||||
Device,
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
fleetOrDevice: string;
|
||||
}
|
||||
|
||||
interface FlagsDef {
|
||||
source: string;
|
||||
emulated: boolean;
|
||||
dockerfile?: string; // DeviceDeployOptions.dockerfilePath (alternative Dockerfile)
|
||||
nocache: boolean;
|
||||
pull: boolean;
|
||||
'noparent-check': boolean;
|
||||
'registry-secrets'?: string;
|
||||
nolive: boolean;
|
||||
detached: boolean;
|
||||
service?: string[];
|
||||
system: boolean;
|
||||
env?: string[];
|
||||
'noconvert-eol': boolean;
|
||||
'multi-dockerignore': boolean;
|
||||
'release-tag'?: string[];
|
||||
draft: boolean;
|
||||
note?: string;
|
||||
help: void;
|
||||
}
|
||||
type FlagsDef = Interfaces.InferredFlags<typeof PushCmd.flags>;
|
||||
|
||||
export default class PushCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -112,27 +90,26 @@ export default class PushCmd extends Command {
|
||||
'$ balena push 23c73a1.local --system --service my-service',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'fleetOrDevice',
|
||||
public static args = {
|
||||
fleetOrDevice: Args.string({
|
||||
description:
|
||||
'fleet name or slug, or local device IP address or ".local" hostname',
|
||||
required: true,
|
||||
parse: lowercaseIfSlug,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'push <fleetOrDevice>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
source: flags.string({
|
||||
public static flags = {
|
||||
source: Flags.string({
|
||||
description: stripIndent`
|
||||
Source directory to be sent to balenaCloud or balenaOS device
|
||||
(default: current working dir)`,
|
||||
char: 's',
|
||||
default: '.',
|
||||
}),
|
||||
emulated: flags.boolean({
|
||||
emulated: Flags.boolean({
|
||||
description: stripIndent`
|
||||
Don't use the faster, native balenaCloud ARM builders; force slower QEMU ARM
|
||||
emulation on Intel x86-64 builders. This flag is sometimes used to investigate
|
||||
@ -140,11 +117,11 @@ export default class PushCmd extends Command {
|
||||
char: 'e',
|
||||
default: false,
|
||||
}),
|
||||
dockerfile: flags.string({
|
||||
dockerfile: Flags.string({
|
||||
description:
|
||||
'Alternative Dockerfile name/path, relative to the source folder',
|
||||
}),
|
||||
nocache: flags.boolean({
|
||||
nocache: Flags.boolean({
|
||||
description: stripIndent`
|
||||
Don't use cached layers of previously built images for this project. This
|
||||
ensures that the latest base image and packages are pulled. Note that build
|
||||
@ -155,18 +132,18 @@ export default class PushCmd extends Command {
|
||||
char: 'c',
|
||||
default: false,
|
||||
}),
|
||||
pull: flags.boolean({
|
||||
pull: Flags.boolean({
|
||||
description: stripIndent`
|
||||
When pushing to a local device, force the base images to be pulled again.
|
||||
Currently this option is ignored when pushing to the balenaCloud builders.`,
|
||||
default: false,
|
||||
}),
|
||||
'noparent-check': flags.boolean({
|
||||
'noparent-check': Flags.boolean({
|
||||
description: stripIndent`
|
||||
Disable project validation check of 'docker-compose.yml' file in parent folder`,
|
||||
default: false,
|
||||
}),
|
||||
'registry-secrets': flags.string({
|
||||
'registry-secrets': Flags.string({
|
||||
description: stripIndent`
|
||||
Path to a local YAML or JSON file containing Docker registry passwords used
|
||||
to pull base images. Note that if registry-secrets are not provided on the
|
||||
@ -174,7 +151,7 @@ export default class PushCmd extends Command {
|
||||
used (usually $HOME/.balena/secrets.yml|.json)`,
|
||||
char: 'R',
|
||||
}),
|
||||
nolive: flags.boolean({
|
||||
nolive: Flags.boolean({
|
||||
description: stripIndent`
|
||||
Don't run a live session on this push. The filesystem will not be monitored,
|
||||
and changes will not be synchronized to any running containers. Note that both
|
||||
@ -182,7 +159,7 @@ export default class PushCmd extends Command {
|
||||
initial build has completed.`,
|
||||
default: false,
|
||||
}),
|
||||
detached: flags.boolean({
|
||||
detached: Flags.boolean({
|
||||
description: stripIndent`
|
||||
When pushing to the cloud, this option will cause the build to start, then
|
||||
return execution back to the shell, with the status and release ID (if
|
||||
@ -191,20 +168,20 @@ export default class PushCmd extends Command {
|
||||
char: 'd',
|
||||
default: false,
|
||||
}),
|
||||
service: flags.string({
|
||||
service: Flags.string({
|
||||
description: stripIndent`
|
||||
Reject logs not originating from this service.
|
||||
This can be used in combination with --system and other --service flags.
|
||||
Only valid when pushing to a local mode device.`,
|
||||
multiple: true,
|
||||
}),
|
||||
system: flags.boolean({
|
||||
system: Flags.boolean({
|
||||
description: stripIndent`
|
||||
Only show system logs. This can be used in combination with --service.
|
||||
Only valid when pushing to a local mode device.`,
|
||||
default: false,
|
||||
}),
|
||||
env: flags.string({
|
||||
env: Flags.string({
|
||||
description: stripIndent`
|
||||
When performing a push to device, run the built containers with environment
|
||||
variables provided with this argument. Environment variables can be applied
|
||||
@ -216,17 +193,17 @@ export default class PushCmd extends Command {
|
||||
`,
|
||||
multiple: true,
|
||||
}),
|
||||
'noconvert-eol': flags.boolean({
|
||||
'noconvert-eol': Flags.boolean({
|
||||
description: `Don't convert line endings from CRLF (Windows format) to LF (Unix format).`,
|
||||
default: false,
|
||||
}),
|
||||
'multi-dockerignore': flags.boolean({
|
||||
'multi-dockerignore': Flags.boolean({
|
||||
description:
|
||||
'Have each service use its own .dockerignore file. See "balena help push".',
|
||||
char: 'm',
|
||||
default: false,
|
||||
}),
|
||||
'release-tag': flags.string({
|
||||
'release-tag': Flags.string({
|
||||
description: stripIndent`
|
||||
Set release tags if the image build is successful (balenaCloud only). Multiple
|
||||
arguments may be provided, alternating tag keys and values (see examples).
|
||||
@ -235,7 +212,7 @@ export default class PushCmd extends Command {
|
||||
multiple: true,
|
||||
exclusive: ['detached'],
|
||||
}),
|
||||
draft: flags.boolean({
|
||||
draft: Flags.boolean({
|
||||
description: stripIndent`
|
||||
Instruct the builder to create the release as a draft. Draft releases are ignored
|
||||
by the 'track latest' release policy but can be used through release pinning.
|
||||
@ -243,16 +220,14 @@ export default class PushCmd extends Command {
|
||||
as final by default unless this option is given.`,
|
||||
default: false,
|
||||
}),
|
||||
note: flags.string({ description: 'The notes for this release' }),
|
||||
note: Flags.string({ description: 'The notes for this release' }),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static primary = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
PushCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(PushCmd);
|
||||
|
||||
const logger = await Command.getLogger();
|
||||
logger.logDebug(`Using build source directory: ${options.source} `);
|
||||
|
@ -15,19 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { commitOrIdArg } from '.';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { tryAsInteger } from '../../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
commitOrId: string | number;
|
||||
}
|
||||
|
||||
export default class ReleaseFinalizeCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -51,23 +42,21 @@ export default class ReleaseFinalizeCmd extends Command {
|
||||
|
||||
public static usage = 'release finalize <commitOrId>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'commitOrId',
|
||||
public static args = {
|
||||
commitOrId: commitOrIdArg({
|
||||
description: 'the commit or ID of the release to finalize',
|
||||
required: true,
|
||||
parse: (commitOrId: string) => tryAsInteger(commitOrId),
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(ReleaseFinalizeCmd);
|
||||
const { args: params } = await this.parse(ReleaseFinalizeCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
|
||||
@ -23,14 +23,9 @@ import type * as BalenaSdk from 'balena-sdk';
|
||||
import jsyaml = require('js-yaml');
|
||||
import { tryAsInteger } from '../../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
composition?: boolean;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
commitOrId: string | number;
|
||||
}
|
||||
export const commitOrIdArg = Args.custom({
|
||||
parse: async (commitOrId: string) => tryAsInteger(commitOrId),
|
||||
});
|
||||
|
||||
export default class ReleaseCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -43,30 +38,26 @@ export default class ReleaseCmd extends Command {
|
||||
|
||||
public static usage = 'release <commitOrId>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
composition: flags.boolean({
|
||||
composition: Flags.boolean({
|
||||
default: false,
|
||||
char: 'c',
|
||||
description: 'Return the release composition',
|
||||
}),
|
||||
};
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'commitOrId',
|
||||
public static args = {
|
||||
commitOrId: commitOrIdArg({
|
||||
description: 'the commit or ID of the release to get information',
|
||||
required: true,
|
||||
parse: (commitOrId: string) => tryAsInteger(commitOrId),
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
ReleaseCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(ReleaseCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
if (options.composition) {
|
||||
|
@ -15,19 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { commitOrIdArg } from '.';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { tryAsInteger } from '../../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
commitOrId: string | number;
|
||||
}
|
||||
|
||||
export default class ReleaseInvalidateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -46,25 +37,21 @@ export default class ReleaseInvalidateCmd extends Command {
|
||||
|
||||
public static usage = 'release invalidate <commitOrId>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'commitOrId',
|
||||
public static args = {
|
||||
commitOrId: commitOrIdArg({
|
||||
description: 'the commit or ID of the release to invalidate',
|
||||
required: true,
|
||||
parse: (commitOrId: string) => tryAsInteger(commitOrId),
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(
|
||||
ReleaseInvalidateCmd,
|
||||
);
|
||||
const { args: params } = await this.parse(ReleaseInvalidateCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,19 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { commitOrIdArg } from '.';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { tryAsInteger } from '../../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
commitOrId: string | number;
|
||||
}
|
||||
|
||||
export default class ReleaseValidateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -45,23 +36,21 @@ export default class ReleaseValidateCmd extends Command {
|
||||
|
||||
public static usage = 'release validate <commitOrId>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'commitOrId',
|
||||
public static args = {
|
||||
commitOrId: commitOrIdArg({
|
||||
description: 'the commit or ID of the release to validate',
|
||||
required: true,
|
||||
parse: (commitOrId: string) => tryAsInteger(commitOrId),
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(ReleaseValidateCmd);
|
||||
const { args: params } = await this.parse(ReleaseValidateCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,21 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../utils/lazy';
|
||||
import { applicationNameNote } from '../utils/messages';
|
||||
import type * as BalenaSdk from 'balena-sdk';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
fleet: string;
|
||||
}
|
||||
|
||||
export default class ReleasesCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
List all releases of a fleet.
|
||||
@ -42,22 +34,21 @@ export default class ReleasesCmd extends Command {
|
||||
|
||||
public static usage = 'releases <fleet>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'fleet',
|
||||
public static args = {
|
||||
fleet: Args.string({
|
||||
description: 'fleet name or slug (preferred)',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(ReleasesCmd);
|
||||
const { args: params } = await this.parse(ReleasesCmd);
|
||||
|
||||
const fields: Array<keyof BalenaSdk.Release> = [
|
||||
'id',
|
||||
|
@ -15,18 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getCliUx, stripIndent } from '../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
json?: boolean;
|
||||
verbose: boolean;
|
||||
timeout?: number;
|
||||
help: void;
|
||||
}
|
||||
|
||||
export default class ScanCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Scan for balenaOS devices on your local network.
|
||||
@ -47,18 +40,18 @@ export default class ScanCmd extends Command {
|
||||
|
||||
public static usage = 'scan';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
verbose: flags.boolean({
|
||||
public static flags = {
|
||||
verbose: Flags.boolean({
|
||||
default: false,
|
||||
char: 'v',
|
||||
description: 'display full info',
|
||||
}),
|
||||
timeout: flags.integer({
|
||||
timeout: Flags.integer({
|
||||
char: 't',
|
||||
description: 'scan timeout in seconds',
|
||||
}),
|
||||
help: cf.help,
|
||||
json: flags.boolean({
|
||||
json: Flags.boolean({
|
||||
default: false,
|
||||
char: 'j',
|
||||
description: 'produce JSON output instead of tabular output',
|
||||
@ -78,7 +71,7 @@ export default class ScanCmd extends Command {
|
||||
const dockerPort = 2375;
|
||||
const dockerTimeout = 2000;
|
||||
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(ScanCmd);
|
||||
const { flags: options } = await this.parse(ScanCmd);
|
||||
|
||||
const discoverTimeout =
|
||||
options.timeout != null ? options.timeout * 1000 : undefined;
|
||||
|
@ -15,15 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
export default class SettingsCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Print current settings.
|
||||
@ -34,12 +29,12 @@ export default class SettingsCmd extends Command {
|
||||
|
||||
public static usage = 'settings';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public async run() {
|
||||
this.parse<FlagsDef, {}>(SettingsCmd);
|
||||
await this.parse(SettingsCmd);
|
||||
|
||||
const settings = await getBalenaSdk().settings.getAll();
|
||||
|
||||
|
@ -15,25 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../utils/lazy';
|
||||
import { parseAsInteger, validateLocalHostnameOrIp } from '../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
port?: number;
|
||||
tty: boolean;
|
||||
verbose: boolean;
|
||||
noproxy: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
fleetOrDevice: string;
|
||||
service?: string;
|
||||
}
|
||||
|
||||
export default class SshCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Open a SSH prompt on a device's host OS or service container.
|
||||
@ -73,41 +60,39 @@ export default class SshCmd extends Command {
|
||||
'$ echo "uptime; exit;" | balena ssh 192.168.0.1 myService',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'fleetOrDevice',
|
||||
public static args = {
|
||||
fleetOrDevice: Args.string({
|
||||
description: 'fleet name/slug, device uuid, or address of local device',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'service',
|
||||
}),
|
||||
service: Args.string({
|
||||
description: 'service name, if connecting to a container',
|
||||
required: false,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'ssh <fleetOrDevice> [service]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
port: flags.integer({
|
||||
public static flags = {
|
||||
port: Flags.integer({
|
||||
description: stripIndent`
|
||||
SSH server port number (default 22222) if the target is an IP address or .local
|
||||
hostname. Otherwise, port number for the balenaCloud gateway (default 22).`,
|
||||
char: 'p',
|
||||
parse: (p) => parseAsInteger(p, 'port'),
|
||||
parse: async (p) => parseAsInteger(p, 'port'),
|
||||
}),
|
||||
tty: flags.boolean({
|
||||
tty: Flags.boolean({
|
||||
default: false,
|
||||
description:
|
||||
'force pseudo-terminal allocation (bypass TTY autodetection for stdin)',
|
||||
char: 't',
|
||||
}),
|
||||
verbose: flags.boolean({
|
||||
verbose: Flags.boolean({
|
||||
default: false,
|
||||
description: 'increase verbosity',
|
||||
char: 'v',
|
||||
}),
|
||||
noproxy: flags.boolean({
|
||||
noproxy: Flags.boolean({
|
||||
default: false,
|
||||
description: 'bypass global proxy configuration for the ssh connection',
|
||||
}),
|
||||
@ -118,9 +103,7 @@ export default class SshCmd extends Command {
|
||||
public static offlineCompatible = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
SshCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(SshCmd);
|
||||
|
||||
// Local connection
|
||||
if (validateLocalHostnameOrIp(params.fleetOrDevice)) {
|
||||
@ -152,9 +135,9 @@ export default class SshCmd extends Command {
|
||||
|
||||
const { which } = await import('../utils/which');
|
||||
|
||||
const [whichProxytunnel, username, proxyUrl] = await Promise.all([
|
||||
const [whichProxytunnel, { username }, proxyUrl] = await Promise.all([
|
||||
useProxy ? which('proxytunnel', false) : undefined,
|
||||
sdk.auth.whoami(),
|
||||
sdk.auth.getUserInfo(),
|
||||
// note that `proxyUrl` refers to the balenaCloud "resin-proxy"
|
||||
// service, currently "balena-devices.com", rather than some
|
||||
// local proxy server URL
|
||||
@ -208,7 +191,7 @@ export default class SshCmd extends Command {
|
||||
port: options.port || 'cloud',
|
||||
proxyCommand,
|
||||
service: params.service,
|
||||
username: username!,
|
||||
username,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -15,24 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import { ExpectedError } from '../errors';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, getCliUx, stripIndent } from '../utils/lazy';
|
||||
import { applicationIdInfo } from '../utils/messages';
|
||||
|
||||
interface FlagsDef {
|
||||
fleet?: string;
|
||||
device?: string;
|
||||
duration?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
action: string;
|
||||
}
|
||||
|
||||
export default class SupportCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Grant or revoke support access for devices or fleets.
|
||||
@ -56,18 +45,17 @@ export default class SupportCmd extends Command {
|
||||
'balena support disable -f myorg/myfleet',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'action',
|
||||
public static args = {
|
||||
action: Args.string({
|
||||
description: 'enable|disable support access',
|
||||
options: ['enable', 'disable'],
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'support <action>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
device: flags.string({
|
||||
public static flags = {
|
||||
device: Flags.string({
|
||||
description: 'comma-separated list (no spaces) of device UUIDs',
|
||||
char: 'd',
|
||||
}),
|
||||
@ -76,7 +64,7 @@ export default class SupportCmd extends Command {
|
||||
description:
|
||||
'comma-separated list (no spaces) of fleet names or slugs (preferred)',
|
||||
},
|
||||
duration: flags.string({
|
||||
duration: Flags.string({
|
||||
description:
|
||||
'length of time to enable support for, in (h)ours or (d)ays, e.g. 12h, 2d',
|
||||
char: 't',
|
||||
@ -87,9 +75,7 @@ export default class SupportCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
SupportCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(SupportCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
const ux = getCliUx();
|
||||
|
@ -15,23 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
|
||||
interface FlagsDef {
|
||||
fleet?: string;
|
||||
device?: string;
|
||||
release?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
tagKey: string;
|
||||
}
|
||||
|
||||
export default class TagRmCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Remove a tag from a fleet, device or release.
|
||||
@ -49,17 +38,16 @@ export default class TagRmCmd extends Command {
|
||||
'$ balena tag rm myTagKey --release b376b0e544e9429483b656490e5b9443b4349bd6',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'tagKey',
|
||||
public static args = {
|
||||
tagKey: Args.string({
|
||||
description: 'the key string of the tag',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'tag rm <tagKey>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
fleet: {
|
||||
...cf.fleet,
|
||||
exclusive: ['device', 'release'],
|
||||
@ -78,9 +66,7 @@ export default class TagRmCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
TagRmCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(TagRmCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,24 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
|
||||
interface FlagsDef {
|
||||
fleet?: string;
|
||||
device?: string;
|
||||
release?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
tagKey: string;
|
||||
value?: string;
|
||||
}
|
||||
|
||||
export default class TagSetCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Set a tag on a fleet, device or release.
|
||||
@ -57,22 +45,20 @@ export default class TagSetCmd extends Command {
|
||||
'$ balena tag set myCompositeTag --release b376b0e544e9429483b656490e5b9443b4349bd6',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'tagKey',
|
||||
public static args = {
|
||||
tagKey: Args.string({
|
||||
description: 'the key string of the tag',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
}),
|
||||
value: Args.string({
|
||||
description: 'the optional value associated with the tag',
|
||||
required: false,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'tag set <tagKey> [value]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
fleet: {
|
||||
...cf.fleet,
|
||||
exclusive: ['device', 'release'],
|
||||
@ -91,9 +77,7 @@ export default class TagSetCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
TagSetCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(TagSetCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,20 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import Command from '../command';
|
||||
import { ExpectedError } from '../errors';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../utils/lazy';
|
||||
import { applicationIdInfo } from '../utils/messages';
|
||||
|
||||
interface FlagsDef {
|
||||
fleet?: string;
|
||||
device?: string;
|
||||
release?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
export default class TagsCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
List all tags for a fleet, device or release.
|
||||
@ -48,7 +40,7 @@ export default class TagsCmd extends Command {
|
||||
|
||||
public static usage = 'tags';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
fleet: {
|
||||
...cf.fleet,
|
||||
exclusive: ['device', 'release'],
|
||||
@ -67,7 +59,7 @@ export default class TagsCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(TagsCmd);
|
||||
const { flags: options } = await this.parse(TagsCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags, Args } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import {
|
||||
NoPortsDefinedError,
|
||||
@ -28,15 +28,6 @@ import { lowercaseIfSlug } from '../utils/normalization';
|
||||
|
||||
import type { Server, Socket } from 'net';
|
||||
|
||||
interface FlagsDef {
|
||||
port: string[];
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
deviceOrFleet: string;
|
||||
}
|
||||
|
||||
export default class TunnelCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Tunnel local ports to your balenaOS device.
|
||||
@ -79,19 +70,18 @@ export default class TunnelCmd extends Command {
|
||||
'$ balena tunnel myFleet -p 8080:3000 -p 8081:9000',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'deviceOrFleet',
|
||||
public static args = {
|
||||
deviceOrFleet: Args.string({
|
||||
description: 'device UUID or fleet name/slug',
|
||||
required: true,
|
||||
parse: lowercaseIfSlug,
|
||||
},
|
||||
];
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'tunnel <deviceOrFleet>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
port: flags.string({
|
||||
public static flags = {
|
||||
port: Flags.string({
|
||||
description:
|
||||
'port mapping in the format <remotePort>[:[localIP:]localPort]',
|
||||
char: 'p',
|
||||
@ -104,9 +94,7 @@ export default class TunnelCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
TunnelCmd,
|
||||
);
|
||||
const { args: params, flags: options } = await this.parse(TunnelCmd);
|
||||
|
||||
const logger = await Command.getLogger();
|
||||
const sdk = getBalenaSdk();
|
||||
|
@ -15,15 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { stripIndent, getChalk, getVisuals } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
export default class UtilAvailableDrivesCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
List available drives.
|
||||
@ -34,14 +29,14 @@ export default class UtilAvailableDrivesCmd extends Command {
|
||||
|
||||
public static usage = 'util available-drives';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static offlineCompatible = true;
|
||||
|
||||
public async run() {
|
||||
this.parse<FlagsDef, {}>(UtilAvailableDrivesCmd);
|
||||
await this.parse(UtilAvailableDrivesCmd);
|
||||
|
||||
const sdk = await import('etcher-sdk');
|
||||
|
||||
|
@ -15,16 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import { Flags } from '@oclif/core';
|
||||
import Command from '../command';
|
||||
import { stripIndent } from '../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
all: boolean;
|
||||
json: boolean;
|
||||
help: void;
|
||||
}
|
||||
|
||||
export interface JsonVersions {
|
||||
'balena-cli': string;
|
||||
'Node.js': string;
|
||||
@ -59,24 +53,24 @@ export default class VersionCmd extends Command {
|
||||
|
||||
public static offlineCompatible = true;
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
all: flags.boolean({
|
||||
public static flags = {
|
||||
all: Flags.boolean({
|
||||
default: false,
|
||||
char: 'a',
|
||||
description:
|
||||
'include version information for additional components (Node.js)',
|
||||
}),
|
||||
json: flags.boolean({
|
||||
json: Flags.boolean({
|
||||
default: false,
|
||||
char: 'j',
|
||||
description:
|
||||
'output version information in JSON format for programmatic use',
|
||||
}),
|
||||
help: flags.help({ char: 'h' }),
|
||||
help: Flags.help({ char: 'h' }),
|
||||
};
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(VersionCmd);
|
||||
const { flags: options } = await this.parse(VersionCmd);
|
||||
const versions: JsonVersions = {
|
||||
'balena-cli': (await import('../../package.json')).version,
|
||||
'Node.js':
|
||||
|
@ -32,22 +32,41 @@ export default class WhoamiCmd extends Command {
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
this.parse<{}, {}>(WhoamiCmd);
|
||||
await this.parse(WhoamiCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
const [username, email, url] = await Promise.all([
|
||||
const [whoamiResult, url] = await Promise.all([
|
||||
balena.auth.whoami(),
|
||||
balena.auth.getEmail(),
|
||||
balena.settings.get('balenaUrl'),
|
||||
]);
|
||||
console.log(
|
||||
getVisuals().table.vertical({ username, email, url }, [
|
||||
'$account information$',
|
||||
'username',
|
||||
'email',
|
||||
'url',
|
||||
]),
|
||||
);
|
||||
|
||||
if (whoamiResult?.actorType === 'user') {
|
||||
const { username, email } = whoamiResult;
|
||||
console.log(
|
||||
getVisuals().table.vertical({ username, email, url }, [
|
||||
'$account information$',
|
||||
'username',
|
||||
'email',
|
||||
'url',
|
||||
]),
|
||||
);
|
||||
} else if (whoamiResult?.actorType === 'device') {
|
||||
console.log(
|
||||
getVisuals().table.vertical({ device: whoamiResult.uuid, url }, [
|
||||
'$account information$',
|
||||
'device',
|
||||
'url',
|
||||
]),
|
||||
);
|
||||
} else if (whoamiResult?.actorType === 'application') {
|
||||
console.log(
|
||||
getVisuals().table.vertical({ application: whoamiResult.slug, url }, [
|
||||
'$account information$',
|
||||
'application',
|
||||
'url',
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { BalenaSettingsStorage } from 'balena-settings-storage';
|
||||
|
||||
export interface ReleaseTimestampsByVersion {
|
||||
[version: string]: string; // e.g. { '12.0.0': '2021-06-16T12:54:52.000Z' }
|
||||
lastFetched: string; // ISO 8601 timestamp, e.g. '2021-06-27T16:46:10.000Z'
|
||||
@ -46,7 +48,7 @@ export class DeprecationChecker {
|
||||
readonly cacheFile = 'cachedReleaseTimestamps';
|
||||
readonly now = new Date().getTime();
|
||||
private initialized = false;
|
||||
storage: ReturnType<typeof import('balena-settings-storage')>;
|
||||
storage: BalenaSettingsStorage;
|
||||
cachedTimestamps: ReleaseTimestampsByVersion;
|
||||
nextMajorVersion: string; // semver without the 'v' prefix
|
||||
|
||||
@ -63,7 +65,7 @@ export class DeprecationChecker {
|
||||
this.initialized = true;
|
||||
|
||||
const settings = await import('balena-settings-client');
|
||||
const getStorage = await import('balena-settings-storage');
|
||||
const { getStorage } = await import('balena-settings-storage');
|
||||
const dataDirectory = settings.get<string>('dataDirectory');
|
||||
this.storage = getStorage({ dataDirectory });
|
||||
let stored: ReleaseTimestampsByVersion | undefined;
|
||||
|
26
lib/help.ts
26
lib/help.ts
@ -14,11 +14,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import Help from '@oclif/plugin-help';
|
||||
import { Help } from '@oclif/core';
|
||||
import * as indent from 'indent-string';
|
||||
import { getChalk } from './utils/lazy';
|
||||
import { renderList } from '@oclif/plugin-help/lib/list';
|
||||
import { ExpectedError } from './errors';
|
||||
|
||||
// Partially overrides standard implementation of help plugin
|
||||
// https://github.com/oclif/plugin-help/blob/master/src/index.ts
|
||||
@ -41,7 +39,7 @@ function getHelpSubject(args: string[]): string | undefined {
|
||||
export default class BalenaHelp extends Help {
|
||||
public static usage: 'help [command]';
|
||||
|
||||
public showHelp(argv: string[]) {
|
||||
public async showHelp(argv: string[]) {
|
||||
const chalk = getChalk();
|
||||
const subject = getHelpSubject(argv);
|
||||
if (!subject) {
|
||||
@ -52,15 +50,20 @@ export default class BalenaHelp extends Help {
|
||||
|
||||
const command = this.config.findCommand(subject);
|
||||
if (command) {
|
||||
this.showCommandHelp(command);
|
||||
await this.showCommandHelp(await command.load());
|
||||
return;
|
||||
}
|
||||
|
||||
// If they've typed a topic (e.g. `balena os`) that isn't also a command (e.g. `balena device`)
|
||||
// then list the associated commands.
|
||||
const topicCommands = this.config.commands.filter((c) => {
|
||||
return c.id.startsWith(`${subject}:`);
|
||||
});
|
||||
const topicCommands = await Promise.all(
|
||||
this.config.commands
|
||||
.filter((c) => {
|
||||
return c.id.startsWith(`${subject}:`);
|
||||
})
|
||||
.map((topic) => topic.load()),
|
||||
);
|
||||
|
||||
if (topicCommands.length > 0) {
|
||||
console.log(`${chalk.yellow(subject)} commands include:`);
|
||||
console.log(this.formatCommands(topicCommands));
|
||||
@ -77,7 +80,7 @@ export default class BalenaHelp extends Help {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ExpectedError(`command ${chalk.cyan.bold(subject)} not found`);
|
||||
console.log(`command ${chalk.cyan.bold(subject)} not found`);
|
||||
}
|
||||
|
||||
getCustomRootHelp(showAllCommands: boolean): string {
|
||||
@ -187,14 +190,15 @@ See: https://git.io/JRHUW#deprecation-policy`,
|
||||
return '';
|
||||
}
|
||||
|
||||
const body = renderList(
|
||||
const body = this.renderList(
|
||||
commands
|
||||
.filter((c) => c.usage != null && c.usage !== '')
|
||||
.map((c) => [c.usage, this.formatDescription(c.description)]),
|
||||
{
|
||||
spacer: '\n',
|
||||
stripAnsi: this.opts.stripAnsi,
|
||||
maxWidth: this.opts.maxWidth - 2,
|
||||
indentation: 2,
|
||||
multiline: false,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -15,8 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Hook } from '@oclif/config';
|
||||
import type { IConfig } from '@oclif/config';
|
||||
import type { Hook, Interfaces } from '@oclif/core';
|
||||
import { getChalk } from '../../utils/lazy';
|
||||
|
||||
/*
|
||||
A modified version of the command-not-found plugin logic,
|
||||
@ -27,11 +27,11 @@ import type { IConfig } from '@oclif/config';
|
||||
*/
|
||||
|
||||
const hook: Hook<'command-not-found'> = async function (
|
||||
opts: object & { config: IConfig; id?: string; argv?: string[] },
|
||||
opts: object & { config: Interfaces.Config; id?: string; argv?: string[] },
|
||||
) {
|
||||
const Levenshtein = await import('fast-levenshtein');
|
||||
const _ = await import('lodash');
|
||||
const { color } = await import('@oclif/color');
|
||||
const chalk = getChalk();
|
||||
|
||||
const commandId = opts.id || '';
|
||||
const command = opts.id?.replace(':', ' ') || '';
|
||||
@ -60,17 +60,19 @@ const hook: Hook<'command-not-found'> = async function (
|
||||
|
||||
// Output suggestions
|
||||
console.error(
|
||||
`${color.yellow(command)} is not a recognized balena command.\n`,
|
||||
`${chalk.yellow(command)} is not a recognized balena command.\n`,
|
||||
);
|
||||
console.error(`Did you mean: ? `);
|
||||
suggestions.forEach((s) => {
|
||||
console.error(` ${color.cmd(s)}`);
|
||||
console.error(` ${chalk.cyan.bold(s)}`);
|
||||
});
|
||||
console.error(
|
||||
`\nRun ${color.cmd('balena help -v')} for a list of available commands,`,
|
||||
`\nRun ${chalk.cyan.bold(
|
||||
'balena help -v',
|
||||
)} for a list of available commands,`,
|
||||
);
|
||||
console.error(
|
||||
` or ${color.cmd(
|
||||
` or ${chalk.cyan.bold(
|
||||
'balena help <command>',
|
||||
)} for detailed help on a specific command.`,
|
||||
);
|
||||
|
@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import type { Hook } from '@oclif/config';
|
||||
import type { Hook } from '@oclif/core';
|
||||
|
||||
let trackResolve: (result: Promise<any>) => void;
|
||||
|
||||
|
@ -20,6 +20,7 @@ export let unsupportedFlag = false;
|
||||
export interface AppOptions {
|
||||
// Prevent the default behavior of flushing stdout after running a command
|
||||
noFlush?: boolean;
|
||||
configPath?: string;
|
||||
}
|
||||
|
||||
export async function preparseArgs(argv: string[]): Promise<string[]> {
|
||||
@ -133,7 +134,6 @@ Please use "balena ${alternative}" instead.`);
|
||||
'local stop': [removed, stopAlternative, 'v11.0.0'],
|
||||
app: [replaced, 'fleet', 'v13.0.0'],
|
||||
apps: [replaced, 'fleets', 'v13.0.0'],
|
||||
'app create': [replaced, 'fleet create', 'v13.0.0'],
|
||||
'app purge': [replaced, 'fleet purge', 'v13.0.0'],
|
||||
'app rename': [replaced, 'fleet rename', 'v13.0.0'],
|
||||
'app restart': [replaced, 'fleet restart', 'v13.0.0'],
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user