mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-24 07:46:39 +00:00
Add balena app create
command for creatings Apps
Change-type: minor
This commit is contained in:
parent
3a143fe413
commit
c5e8f0d6ea
@ -8,9 +8,10 @@ _balena() {
|
||||
local context state line curcontext="$curcontext"
|
||||
|
||||
# Valid top-level completions
|
||||
main_commands=( build deploy envs fleets join keys leave login logout logs note orgs preload push releases scan settings ssh support tags tunnel version whoami api-key api-keys config device device devices env fleet fleet internal key key local os release release tag util )
|
||||
main_commands=( build deploy envs fleets join keys leave login logout logs note orgs preload push releases scan settings ssh support tags tunnel version whoami api-key api-keys app config device device devices env fleet fleet internal key key local os release release tag util )
|
||||
# Sub-completions
|
||||
api_key_cmds=( generate )
|
||||
app_cmds=( create )
|
||||
config_cmds=( generate inject read reconfigure write )
|
||||
device_cmds=( deactivate identify init local-mode move os-update pin public-url purge reboot register rename restart rm shutdown track-fleet )
|
||||
devices_cmds=( supported )
|
||||
@ -43,6 +44,9 @@ _balena_sec_cmds() {
|
||||
"api-key")
|
||||
_describe -t api_key_cmds 'api-key_cmd' api_key_cmds "$@" && ret=0
|
||||
;;
|
||||
"app")
|
||||
_describe -t app_cmds 'app_cmd' app_cmds "$@" && ret=0
|
||||
;;
|
||||
"config")
|
||||
_describe -t config_cmds 'config_cmd' config_cmds "$@" && ret=0
|
||||
;;
|
||||
|
@ -7,9 +7,10 @@ _balena_complete()
|
||||
local cur prev
|
||||
|
||||
# Valid top-level completions
|
||||
main_commands="build deploy envs fleets join keys leave login logout logs note orgs preload push releases scan settings ssh support tags tunnel version whoami api-key api-keys config device device devices env fleet fleet internal key key local os release release tag util"
|
||||
main_commands="build deploy envs fleets join keys leave login logout logs note orgs preload push releases scan settings ssh support tags tunnel version whoami api-key api-keys app config device device devices env fleet fleet internal key key local os release release tag util"
|
||||
# Sub-completions
|
||||
api_key_cmds="generate"
|
||||
app_cmds="create"
|
||||
config_cmds="generate inject read reconfigure write"
|
||||
device_cmds="deactivate identify init local-mode move os-update pin public-url purge reboot register rename restart rm shutdown track-fleet"
|
||||
devices_cmds="supported"
|
||||
@ -37,6 +38,9 @@ _balena_complete()
|
||||
api-key)
|
||||
COMPREPLY=( $(compgen -W "$api_key_cmds" -- $cur) )
|
||||
;;
|
||||
app)
|
||||
COMPREPLY=( $(compgen -W "$app_cmds" -- $cur) )
|
||||
;;
|
||||
config)
|
||||
COMPREPLY=( $(compgen -W "$config_cmds" -- $cur) )
|
||||
;;
|
||||
|
150
lib/commands/app/create.ts
Normal file
150
lib/commands/app/create.ts
Normal file
@ -0,0 +1,150 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2016-2021 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* 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, stripIndent } from '../../utils/lazy';
|
||||
|
||||
interface FlagsDef {
|
||||
organization?: string;
|
||||
type?: string; // application device type
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export default class AppCreateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Create an app.
|
||||
|
||||
Create a new balena app.
|
||||
|
||||
You can specify the organization the app should belong to using
|
||||
the \`--organization\` option. The organization's handle, not its name,
|
||||
should be provided. Organization handles can be listed with the
|
||||
\`balena orgs\` command.
|
||||
|
||||
The app's default device type is specified with the \`--type\` option.
|
||||
The \`balena devices supported\` command can be used to list the available
|
||||
device types.
|
||||
|
||||
Interactive dropdowns will be shown for selection if no device type or
|
||||
organization is specified and there are multiple options to choose from.
|
||||
If there is a single option to choose from, it will be chosen automatically.
|
||||
This interactive behavior can be disabled by explicitly specifying a device
|
||||
type and organization.
|
||||
`;
|
||||
|
||||
public static examples = [
|
||||
'$ balena app create MyApp',
|
||||
'$ balena app create MyApp --organization mmyorg',
|
||||
'$ balena app create MyApp -o myorg --type raspberry-pi',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'name',
|
||||
description: 'app name',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
||||
public static usage = 'app create <name>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
organization: flags.string({
|
||||
char: 'o',
|
||||
description: 'handle of the organization the app should belong to',
|
||||
}),
|
||||
type: flags.string({
|
||||
char: 't',
|
||||
description:
|
||||
'app device type (Check available types with `balena devices supported`)',
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -115,7 +115,7 @@ export default class FleetCreateCmd extends Command {
|
||||
if ((err.message || '').toLowerCase().includes('unique')) {
|
||||
// BalenaRequestError: Request error: "organization" and "app_name" must be unique.
|
||||
throw new ExpectedError(
|
||||
`Error: fleet "${params.name}" already exists in organization "${organization}".`,
|
||||
`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
|
||||
|
Loading…
Reference in New Issue
Block a user