mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-02-20 17:33:18 +00:00
Merge pull request #1841 from balena-io/convert-tags
Convert `tags`, `tag set`, `tag rm` to oclif.
This commit is contained in:
commit
ac3a688d46
@ -66,7 +66,11 @@ const capitanoDoc = {
|
||||
},
|
||||
{
|
||||
title: 'Tags',
|
||||
files: ['build/actions/tags.js'],
|
||||
files: [
|
||||
'build/actions-oclif/tags.js',
|
||||
'build/actions-oclif/tag/rm.js',
|
||||
'build/actions-oclif/tag/set.js',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Help and Version',
|
||||
|
100
doc/cli.markdown
100
doc/cli.markdown
@ -194,8 +194,8 @@ Users are encouraged to regularly update the balena CLI to the latest version.
|
||||
- Tags
|
||||
|
||||
- [tags](#tags)
|
||||
- [tag set <tagKey> [value]](#tag-set-tagkey-value)
|
||||
- [tag rm <tagKey>](#tag-rm-tagkey)
|
||||
- [tag rm <tagkey>](#tag-rm-tagkey)
|
||||
- [tag set <tagkey> [value]](#tag-set-tagkey-value)
|
||||
|
||||
- Help and Version
|
||||
|
||||
@ -991,12 +991,10 @@ select a service variable (may be used together with the --device option)
|
||||
|
||||
## tags
|
||||
|
||||
Use this command to list all tags for
|
||||
a particular application, device or release.
|
||||
List all tags and their values for a particular application,
|
||||
device or release.
|
||||
|
||||
This command lists all application/device/release tags.
|
||||
|
||||
Example:
|
||||
Examples:
|
||||
|
||||
$ balena tags --application MyApp
|
||||
$ balena tags --device 7cf02a6
|
||||
@ -1005,24 +1003,63 @@ Example:
|
||||
|
||||
### Options
|
||||
|
||||
#### --application, -a, --app <application>
|
||||
#### -a, --application APPLICATION
|
||||
|
||||
application name
|
||||
|
||||
#### --device, -d <device>
|
||||
#### -d, --device DEVICE
|
||||
|
||||
device uuid
|
||||
device UUID
|
||||
|
||||
#### --release, -r <release>
|
||||
#### -r, --release RELEASE
|
||||
|
||||
release id
|
||||
|
||||
#### --app APP
|
||||
|
||||
same as '--application'
|
||||
|
||||
## tag rm <tagKey>
|
||||
|
||||
Remove a tag from an application, device or release.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena tag rm myTagKey --application MyApp
|
||||
$ balena tag rm myTagKey --device 7cf02a6
|
||||
$ balena tag rm myTagKey --release 1234
|
||||
$ balena tag rm myTagKey --release b376b0e544e9429483b656490e5b9443b4349bd6
|
||||
|
||||
### Arguments
|
||||
|
||||
#### TAGKEY
|
||||
|
||||
the key string of the tag
|
||||
|
||||
### Options
|
||||
|
||||
#### -a, --application APPLICATION
|
||||
|
||||
application name
|
||||
|
||||
#### -d, --device DEVICE
|
||||
|
||||
device UUID
|
||||
|
||||
#### -r, --release RELEASE
|
||||
|
||||
release id
|
||||
|
||||
#### --app APP
|
||||
|
||||
same as '--application'
|
||||
|
||||
## tag set <tagKey> [value]
|
||||
|
||||
Use this command to set a tag to an application, device or release.
|
||||
Set a tag on an application, device or release.
|
||||
|
||||
You can optionally provide a value to be associated with the created
|
||||
tag, as an extra argument after the tag key. When the value isn't
|
||||
tag, as an extra argument after the tag key. If a value isn't
|
||||
provided, a tag with an empty value is created.
|
||||
|
||||
Examples:
|
||||
@ -1035,45 +1072,34 @@ Examples:
|
||||
$ balena tag set myCompositeTag --release 1234
|
||||
$ balena tag set myCompositeTag --release b376b0e544e9429483b656490e5b9443b4349bd6
|
||||
|
||||
### Options
|
||||
### Arguments
|
||||
|
||||
#### --application, -a, --app <application>
|
||||
#### TAGKEY
|
||||
|
||||
application name
|
||||
the key string of the tag
|
||||
|
||||
#### --device, -d <device>
|
||||
#### VALUE
|
||||
|
||||
device uuid
|
||||
|
||||
#### --release, -r <release>
|
||||
|
||||
release id
|
||||
|
||||
## tag rm <tagKey>
|
||||
|
||||
Use this command to remove a tag from an application, device or release.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena tag rm myTagKey --application MyApp
|
||||
$ balena tag rm myTagKey --device 7cf02a6
|
||||
$ balena tag rm myTagKey --release 1234
|
||||
$ balena tag rm myTagKey --release b376b0e544e9429483b656490e5b9443b4349bd6
|
||||
the optional value associated with the tag
|
||||
|
||||
### Options
|
||||
|
||||
#### --application, -a, --app <application>
|
||||
#### -a, --application APPLICATION
|
||||
|
||||
application name
|
||||
|
||||
#### --device, -d <device>
|
||||
#### -d, --device DEVICE
|
||||
|
||||
device uuid
|
||||
device UUID
|
||||
|
||||
#### --release, -r <release>
|
||||
#### -r, --release RELEASE
|
||||
|
||||
release id
|
||||
|
||||
#### --app APP
|
||||
|
||||
same as '--application'
|
||||
|
||||
# Help and Version
|
||||
|
||||
## help [command...]
|
||||
|
134
lib/actions-oclif/tag/rm.ts
Normal file
134
lib/actions-oclif/tag/rm.ts
Normal file
@ -0,0 +1,134 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2016-2020 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 { stripIndent } from 'common-tags';
|
||||
import Command from '../../command';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk } from '../../utils/lazy';
|
||||
import { disambiguateReleaseParam } from '../../utils/normalization';
|
||||
import { tryAsInteger } from '../../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
application?: string;
|
||||
device?: string;
|
||||
release?: string;
|
||||
help: void;
|
||||
app?: string;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
tagKey: string;
|
||||
}
|
||||
|
||||
export default class TagRmCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Remove a tag from an application, device or release.
|
||||
|
||||
Remove a tag from an application, device or release.
|
||||
`;
|
||||
|
||||
public static examples = [
|
||||
'$ balena tag rm myTagKey --application MyApp',
|
||||
'$ balena tag rm myTagKey --device 7cf02a6',
|
||||
'$ balena tag rm myTagKey --release 1234',
|
||||
'$ balena tag rm myTagKey --release b376b0e544e9429483b656490e5b9443b4349bd6',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'tagKey',
|
||||
description: 'the key string of the tag',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
||||
public static usage = 'tag rm <tagKey>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
application: {
|
||||
...cf.application,
|
||||
exclusive: ['app', 'device', 'release'],
|
||||
},
|
||||
device: {
|
||||
...cf.device,
|
||||
exclusive: ['app', 'application', 'release'],
|
||||
},
|
||||
release: {
|
||||
...cf.release,
|
||||
exclusive: ['app', 'application', 'device'],
|
||||
},
|
||||
help: cf.help,
|
||||
app: flags.string({
|
||||
description: "same as '--application'",
|
||||
exclusive: ['application', 'device', 'release'],
|
||||
}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
TagRmCmd,
|
||||
);
|
||||
|
||||
// Prefer options.application over options.app
|
||||
options.application = options.application || options.app;
|
||||
delete options.app;
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
// Check user has specified one of application/device/release
|
||||
if (!options.application && !options.device && !options.release) {
|
||||
throw new ExpectedError(TagRmCmd.missingResourceMessage);
|
||||
}
|
||||
|
||||
if (options.application) {
|
||||
return balena.models.application.tags.remove(
|
||||
tryAsInteger(options.application),
|
||||
params.tagKey,
|
||||
);
|
||||
}
|
||||
if (options.device) {
|
||||
return balena.models.device.tags.remove(
|
||||
tryAsInteger(options.device),
|
||||
params.tagKey,
|
||||
);
|
||||
}
|
||||
if (options.release) {
|
||||
const releaseParam = await disambiguateReleaseParam(
|
||||
balena,
|
||||
options.release,
|
||||
);
|
||||
|
||||
return balena.models.release.tags.remove(releaseParam, params.tagKey);
|
||||
}
|
||||
}
|
||||
|
||||
protected static missingResourceMessage = stripIndent`
|
||||
To remove a resource tag, you must provide exactly one of:
|
||||
|
||||
* An application, with --application <appname>
|
||||
* A device, with --device <uuid>
|
||||
* A release, with --release <id or commit>
|
||||
|
||||
See the help page for examples:
|
||||
|
||||
$ balena help tag rm
|
||||
`;
|
||||
}
|
157
lib/actions-oclif/tag/set.ts
Normal file
157
lib/actions-oclif/tag/set.ts
Normal file
@ -0,0 +1,157 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2016-2020 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 { stripIndent } from 'common-tags';
|
||||
import Command from '../../command';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk } from '../../utils/lazy';
|
||||
import { disambiguateReleaseParam } from '../../utils/normalization';
|
||||
import { tryAsInteger } from '../../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
application?: string;
|
||||
device?: string;
|
||||
release?: string;
|
||||
help: void;
|
||||
app?: string;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
tagKey: string;
|
||||
value?: string;
|
||||
}
|
||||
|
||||
export default class TagSetCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Set a tag on an application, device or release.
|
||||
|
||||
Set a tag on an application, device or release.
|
||||
|
||||
You can optionally provide a value to be associated with the created
|
||||
tag, as an extra argument after the tag key. If a value isn't
|
||||
provided, a tag with an empty value is created.
|
||||
`;
|
||||
|
||||
public static examples = [
|
||||
'$ balena tag set mySimpleTag --application MyApp',
|
||||
'$ balena tag set myCompositeTag myTagValue --application MyApp',
|
||||
'$ balena tag set myCompositeTag myTagValue --device 7cf02a6',
|
||||
'$ balena tag set myCompositeTag "my tag value with whitespaces" --device 7cf02a6',
|
||||
'$ balena tag set myCompositeTag myTagValue --release 1234',
|
||||
'$ balena tag set myCompositeTag --release 1234',
|
||||
'$ balena tag set myCompositeTag --release b376b0e544e9429483b656490e5b9443b4349bd6',
|
||||
];
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'tagKey',
|
||||
description: 'the key string of the tag',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
description: 'the optional value associated with the tag',
|
||||
required: false,
|
||||
},
|
||||
];
|
||||
|
||||
public static usage = 'tag set <tagKey> [value]';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
application: {
|
||||
...cf.application,
|
||||
exclusive: ['app', 'device', 'release'],
|
||||
},
|
||||
device: {
|
||||
...cf.device,
|
||||
exclusive: ['app', 'application', 'release'],
|
||||
},
|
||||
release: {
|
||||
...cf.release,
|
||||
exclusive: ['app', 'application', 'device'],
|
||||
},
|
||||
help: cf.help,
|
||||
app: flags.string({
|
||||
description: "same as '--application'",
|
||||
exclusive: ['application', 'device', 'release'],
|
||||
}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
TagSetCmd,
|
||||
);
|
||||
|
||||
// Prefer options.application over options.app
|
||||
options.application = options.application || options.app;
|
||||
delete options.app;
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
// Check user has specified one of application/device/release
|
||||
if (!options.application && !options.device && !options.release) {
|
||||
throw new ExpectedError(TagSetCmd.missingResourceMessage);
|
||||
}
|
||||
|
||||
if (params.value == null) {
|
||||
params.value = '';
|
||||
}
|
||||
|
||||
if (options.application) {
|
||||
return balena.models.application.tags.set(
|
||||
tryAsInteger(options.application),
|
||||
params.tagKey,
|
||||
params.value,
|
||||
);
|
||||
}
|
||||
if (options.device) {
|
||||
return balena.models.device.tags.set(
|
||||
tryAsInteger(options.device),
|
||||
params.tagKey,
|
||||
params.value,
|
||||
);
|
||||
}
|
||||
if (options.release) {
|
||||
const releaseParam = await disambiguateReleaseParam(
|
||||
balena,
|
||||
options.release,
|
||||
);
|
||||
|
||||
return balena.models.release.tags.set(
|
||||
releaseParam,
|
||||
params.tagKey,
|
||||
params.value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected static missingResourceMessage = stripIndent`
|
||||
To set a resource tag, you must provide exactly one of:
|
||||
|
||||
* An application, with --application <appname>
|
||||
* A device, with --device <uuid>
|
||||
* A release, with --release <id or commit>
|
||||
|
||||
See the help page for examples:
|
||||
|
||||
$ balena help tag set
|
||||
`;
|
||||
}
|
129
lib/actions-oclif/tags.ts
Normal file
129
lib/actions-oclif/tags.ts
Normal file
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2016-2020 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 { stripIndent } from 'common-tags';
|
||||
import Command from '../command';
|
||||
import { ExpectedError } from '../errors';
|
||||
import * as cf from '../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals } from '../utils/lazy';
|
||||
import { disambiguateReleaseParam } from '../utils/normalization';
|
||||
import { tryAsInteger } from '../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
application?: string;
|
||||
device?: string;
|
||||
release?: string;
|
||||
help: void;
|
||||
app?: string;
|
||||
}
|
||||
|
||||
export default class TagsCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
List all tags for an application, device or release.
|
||||
|
||||
List all tags and their values for a particular application,
|
||||
device or release.
|
||||
`;
|
||||
|
||||
public static examples = [
|
||||
'$ balena tags --application MyApp',
|
||||
'$ balena tags --device 7cf02a6',
|
||||
'$ balena tags --release 1234',
|
||||
'$ balena tags --release b376b0e544e9429483b656490e5b9443b4349bd6',
|
||||
];
|
||||
|
||||
public static usage = 'tags';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
application: {
|
||||
...cf.application,
|
||||
exclusive: ['app', 'device', 'release'],
|
||||
},
|
||||
device: {
|
||||
...cf.device,
|
||||
exclusive: ['app', 'application', 'release'],
|
||||
},
|
||||
release: {
|
||||
...cf.release,
|
||||
exclusive: ['app', 'application', 'device'],
|
||||
},
|
||||
help: cf.help,
|
||||
app: flags.string({
|
||||
description: "same as '--application'",
|
||||
exclusive: ['application', 'device', 'release'],
|
||||
}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = this.parse<FlagsDef, {}>(TagsCmd);
|
||||
|
||||
// Prefer options.application over options.app
|
||||
options.application = options.application || options.app;
|
||||
delete options.app;
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
// Check user has specified one of application/device/release
|
||||
if (!options.application && !options.device && !options.release) {
|
||||
throw new ExpectedError(this.missingResourceMessage);
|
||||
}
|
||||
|
||||
let tags;
|
||||
|
||||
if (options.application) {
|
||||
tags = await balena.models.application.tags.getAllByApplication(
|
||||
tryAsInteger(options.application),
|
||||
);
|
||||
}
|
||||
if (options.device) {
|
||||
tags = await balena.models.device.tags.getAllByDevice(
|
||||
tryAsInteger(options.device),
|
||||
);
|
||||
}
|
||||
if (options.release) {
|
||||
const releaseParam = await disambiguateReleaseParam(
|
||||
balena,
|
||||
options.release,
|
||||
);
|
||||
|
||||
tags = await balena.models.release.tags.getAllByRelease(releaseParam);
|
||||
}
|
||||
|
||||
if (!tags || tags.length === 0) {
|
||||
throw new ExpectedError('No tags found');
|
||||
}
|
||||
|
||||
console.log(
|
||||
getVisuals().table.horizontal(tags, ['id', 'tag_key', 'value']),
|
||||
);
|
||||
}
|
||||
|
||||
protected missingResourceMessage = stripIndent`
|
||||
To list tags for a resource, you must provide exactly one of:
|
||||
|
||||
* An application, with --application <appname>
|
||||
* A device, with --device <uuid>
|
||||
* A release, with --release <id or commit>
|
||||
|
||||
See the help page for examples:
|
||||
|
||||
$ balena help tags
|
||||
`;
|
||||
}
|
@ -23,24 +23,10 @@ import * as logs from './logs';
|
||||
import * as os from './os';
|
||||
import * as push from './push';
|
||||
import * as ssh from './ssh';
|
||||
import * as tags from './tags';
|
||||
import * as tunnel from './tunnel';
|
||||
import * as util from './util';
|
||||
|
||||
export {
|
||||
auth,
|
||||
device,
|
||||
tags,
|
||||
logs,
|
||||
local,
|
||||
help,
|
||||
os,
|
||||
config,
|
||||
ssh,
|
||||
util,
|
||||
push,
|
||||
tunnel,
|
||||
};
|
||||
export { auth, device, logs, local, help, os, config, ssh, util, push, tunnel };
|
||||
|
||||
export { build } from './build';
|
||||
|
||||
|
@ -1,295 +0,0 @@
|
||||
/*
|
||||
Copyright 2016-2018 Balena
|
||||
|
||||
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 { ApplicationTag, DeviceTag, ReleaseTag } from 'balena-sdk';
|
||||
import { CommandDefinition } from 'capitano';
|
||||
import { stripIndent } from 'common-tags';
|
||||
import { getBalenaSdk, getVisuals } from '../utils/lazy';
|
||||
import {
|
||||
disambiguateReleaseParam,
|
||||
normalizeUuidProp,
|
||||
} from '../utils/normalization';
|
||||
import * as commandOptions from './command-options';
|
||||
|
||||
export const list: CommandDefinition<
|
||||
{},
|
||||
{
|
||||
application?: string;
|
||||
device?: string;
|
||||
release?: number | string;
|
||||
release_raw?: string;
|
||||
}
|
||||
> = {
|
||||
signature: 'tags',
|
||||
description: 'list all resource tags',
|
||||
help: stripIndent`
|
||||
Use this command to list all tags for
|
||||
a particular application, device or release.
|
||||
|
||||
This command lists all application/device/release tags.
|
||||
|
||||
Example:
|
||||
|
||||
$ balena tags --application MyApp
|
||||
$ balena tags --device 7cf02a6
|
||||
$ balena tags --release 1234
|
||||
$ balena tags --release b376b0e544e9429483b656490e5b9443b4349bd6
|
||||
`,
|
||||
options: [
|
||||
commandOptions.optionalApplication,
|
||||
commandOptions.optionalDevice,
|
||||
commandOptions.optionalRelease,
|
||||
],
|
||||
permission: 'user',
|
||||
async action(_params, options) {
|
||||
normalizeUuidProp(options, 'device');
|
||||
const Bluebird = await import('bluebird');
|
||||
const _ = await import('lodash');
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
const { exitWithExpectedError } = await import('../errors');
|
||||
|
||||
return Bluebird.try<ApplicationTag[] | DeviceTag[] | ReleaseTag[]>(
|
||||
async () => {
|
||||
const wrongParametersError = stripIndent`
|
||||
To list resource tags, you must provide exactly one of:
|
||||
|
||||
* An application, with --application <appname>
|
||||
* A device, with --device <uuid>
|
||||
* A release, with --release <id or commit>
|
||||
|
||||
See the help page for examples:
|
||||
|
||||
$ balena help tags
|
||||
`;
|
||||
|
||||
if (
|
||||
_.filter([options.application, options.device, options.release])
|
||||
.length !== 1
|
||||
) {
|
||||
return exitWithExpectedError(wrongParametersError);
|
||||
}
|
||||
|
||||
if (options.application) {
|
||||
return balena.models.application.tags.getAllByApplication(
|
||||
options.application,
|
||||
);
|
||||
}
|
||||
if (options.device) {
|
||||
return balena.models.device.tags.getAllByDevice(options.device);
|
||||
}
|
||||
if (options.release) {
|
||||
const releaseParam = await disambiguateReleaseParam(
|
||||
balena,
|
||||
options.release,
|
||||
options.release_raw,
|
||||
);
|
||||
return balena.models.release.tags.getAllByRelease(releaseParam);
|
||||
}
|
||||
|
||||
// return never, so that TS typings are happy
|
||||
return exitWithExpectedError(wrongParametersError);
|
||||
},
|
||||
).tap(function(environmentVariables) {
|
||||
if (_.isEmpty(environmentVariables)) {
|
||||
exitWithExpectedError('No tags found');
|
||||
}
|
||||
|
||||
console.log(
|
||||
getVisuals().table.horizontal(environmentVariables, [
|
||||
'id',
|
||||
'tag_key',
|
||||
'value',
|
||||
]),
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const set: CommandDefinition<
|
||||
{
|
||||
tagKey: string;
|
||||
value?: string;
|
||||
},
|
||||
{
|
||||
application?: string;
|
||||
device?: string;
|
||||
release?: number | string;
|
||||
release_raw: string;
|
||||
}
|
||||
> = {
|
||||
signature: 'tag set <tagKey> [value]',
|
||||
description: 'set a resource tag',
|
||||
help: stripIndent`
|
||||
Use this command to set a tag to an application, device or release.
|
||||
|
||||
You can optionally provide a value to be associated with the created
|
||||
tag, as an extra argument after the tag key. When the value isn't
|
||||
provided, a tag with an empty value is created.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena tag set mySimpleTag --application MyApp
|
||||
$ balena tag set myCompositeTag myTagValue --application MyApp
|
||||
$ balena tag set myCompositeTag myTagValue --device 7cf02a6
|
||||
$ balena tag set myCompositeTag "my tag value with whitespaces" --device 7cf02a6
|
||||
$ balena tag set myCompositeTag myTagValue --release 1234
|
||||
$ balena tag set myCompositeTag --release 1234
|
||||
$ balena tag set myCompositeTag --release b376b0e544e9429483b656490e5b9443b4349bd6
|
||||
`,
|
||||
options: [
|
||||
commandOptions.optionalApplication,
|
||||
commandOptions.optionalDevice,
|
||||
commandOptions.optionalRelease,
|
||||
],
|
||||
permission: 'user',
|
||||
async action(params, options) {
|
||||
normalizeUuidProp(options, 'device');
|
||||
const _ = await import('lodash');
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
const { exitWithExpectedError } = await import('../errors');
|
||||
|
||||
if (_.isEmpty(params.tagKey)) {
|
||||
return exitWithExpectedError('No tag key was provided');
|
||||
}
|
||||
|
||||
if (
|
||||
_.filter([options.application, options.device, options.release])
|
||||
.length !== 1
|
||||
) {
|
||||
return exitWithExpectedError(stripIndent`
|
||||
To set a resource tag, you must provide exactly one of:
|
||||
|
||||
* An application, with --application <appname>
|
||||
* A device, with --device <uuid>
|
||||
* A release, with --release <id or commit>
|
||||
|
||||
See the help page for examples:
|
||||
|
||||
$ balena help tag set
|
||||
`);
|
||||
}
|
||||
|
||||
if (params.value == null) {
|
||||
params.value = '';
|
||||
}
|
||||
|
||||
if (options.application) {
|
||||
return balena.models.application.tags.set(
|
||||
options.application,
|
||||
params.tagKey,
|
||||
params.value,
|
||||
);
|
||||
}
|
||||
if (options.device) {
|
||||
return balena.models.device.tags.set(
|
||||
options.device,
|
||||
params.tagKey,
|
||||
params.value,
|
||||
);
|
||||
}
|
||||
if (options.release) {
|
||||
const releaseParam = await disambiguateReleaseParam(
|
||||
balena,
|
||||
options.release,
|
||||
options.release_raw,
|
||||
);
|
||||
|
||||
return balena.models.release.tags.set(
|
||||
releaseParam,
|
||||
params.tagKey,
|
||||
params.value,
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const remove: CommandDefinition<
|
||||
{
|
||||
tagKey: string;
|
||||
},
|
||||
{
|
||||
application?: string;
|
||||
device?: string;
|
||||
release?: number | string;
|
||||
release_raw?: string;
|
||||
}
|
||||
> = {
|
||||
signature: 'tag rm <tagKey>',
|
||||
description: 'remove a resource tag',
|
||||
help: stripIndent`
|
||||
Use this command to remove a tag from an application, device or release.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena tag rm myTagKey --application MyApp
|
||||
$ balena tag rm myTagKey --device 7cf02a6
|
||||
$ balena tag rm myTagKey --release 1234
|
||||
$ balena tag rm myTagKey --release b376b0e544e9429483b656490e5b9443b4349bd6
|
||||
`,
|
||||
options: [
|
||||
commandOptions.optionalApplication,
|
||||
commandOptions.optionalDevice,
|
||||
commandOptions.optionalRelease,
|
||||
],
|
||||
permission: 'user',
|
||||
async action(params, options) {
|
||||
const _ = await import('lodash');
|
||||
const balena = getBalenaSdk();
|
||||
const { exitWithExpectedError } = await import('../errors');
|
||||
|
||||
if (_.isEmpty(params.tagKey)) {
|
||||
return exitWithExpectedError('No tag key was provided');
|
||||
}
|
||||
|
||||
if (
|
||||
_.filter([options.application, options.device, options.release])
|
||||
.length !== 1
|
||||
) {
|
||||
return exitWithExpectedError(stripIndent`
|
||||
To remove a resource tag, you must provide exactly one of:
|
||||
|
||||
* An application, with --application <appname>
|
||||
* A device, with --device <uuid>
|
||||
* A release, with --release <id or commit>
|
||||
|
||||
See the help page for examples:
|
||||
|
||||
$ balena help tag rm
|
||||
`);
|
||||
}
|
||||
|
||||
if (options.application) {
|
||||
return balena.models.application.tags.remove(
|
||||
options.application,
|
||||
params.tagKey,
|
||||
);
|
||||
}
|
||||
if (options.device) {
|
||||
return balena.models.device.tags.remove(options.device, params.tagKey);
|
||||
}
|
||||
if (options.release) {
|
||||
const releaseParam = await disambiguateReleaseParam(
|
||||
balena,
|
||||
options.release,
|
||||
options.release_raw,
|
||||
);
|
||||
|
||||
return balena.models.release.tags.remove(releaseParam, params.tagKey);
|
||||
}
|
||||
},
|
||||
};
|
@ -71,11 +71,6 @@ capitano.command(actions.device.move);
|
||||
capitano.command(actions.device.osUpdate);
|
||||
capitano.command(actions.device.info);
|
||||
|
||||
// ---------- Tags Module ----------
|
||||
capitano.command(actions.tags.list);
|
||||
capitano.command(actions.tags.set);
|
||||
capitano.command(actions.tags.remove);
|
||||
|
||||
// ---------- OS Module ----------
|
||||
capitano.command(actions.os.versions);
|
||||
capitano.command(actions.os.download);
|
||||
|
@ -159,6 +159,9 @@ export const convertedCommands = [
|
||||
'note',
|
||||
'os:configure',
|
||||
'settings',
|
||||
'tags',
|
||||
'tag:rm',
|
||||
'tag:set',
|
||||
'version',
|
||||
'scan',
|
||||
];
|
||||
|
@ -37,6 +37,11 @@ export const quiet: IBooleanFlag<boolean> = flags.boolean({
|
||||
default: false,
|
||||
});
|
||||
|
||||
export const release = flags.string({
|
||||
char: 'r',
|
||||
description: 'release id',
|
||||
});
|
||||
|
||||
export const service = flags.string({
|
||||
char: 's',
|
||||
description: 'service name',
|
||||
|
@ -16,6 +16,7 @@ limitations under the License.
|
||||
|
||||
import { BalenaSDK } from 'balena-sdk';
|
||||
import _ = require('lodash');
|
||||
import { ExpectedError } from '../errors';
|
||||
|
||||
export function normalizeUuidProp(
|
||||
params: { [key: string]: any },
|
||||
@ -27,25 +28,59 @@ export function normalizeUuidProp(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a string which may represent one of:
|
||||
* - Integer release id
|
||||
* - String uuid, 7, 32, or 62 char
|
||||
* - String commit hash, 40 char, with short hashes being 7+ chars (more as needed to avoid collisions)
|
||||
* and returns the correctly typed value (integer|string).
|
||||
* @param balena balena sdk
|
||||
* @param release string representation of release reference (id/hash)
|
||||
*/
|
||||
export async function disambiguateReleaseParam(
|
||||
balena: BalenaSDK,
|
||||
param: string | number,
|
||||
paramRaw: string | undefined,
|
||||
release: string,
|
||||
) {
|
||||
// the user has passed an argument that was parsed as a string
|
||||
if (typeof param !== 'number') {
|
||||
return param;
|
||||
// Reject empty values or invalid characters
|
||||
const mixedCaseHex = /^[a-fA-F0-9]+$/;
|
||||
if (!release || !mixedCaseHex.test(release)) {
|
||||
throw new ExpectedError('Invalid release parameter');
|
||||
}
|
||||
|
||||
// check whether the argument was indeed an ID
|
||||
return balena.models.release
|
||||
.get(param, { $select: 'id' })
|
||||
.catch(error => {
|
||||
// we couldn't find a release by id,
|
||||
// try whether it was a commit with all numeric digits
|
||||
return balena.models.release
|
||||
.get(paramRaw || _.toString(param), { $select: 'id' })
|
||||
.catchThrow(error);
|
||||
})
|
||||
.then(({ id }) => id);
|
||||
// Accepting short hashes of 7,8,9 chars.
|
||||
const possibleUuidHashLength = [7, 8, 9, 32, 40, 62].includes(release.length);
|
||||
const hasLeadingZero = release[0] === '0';
|
||||
const isOnlyNumerical = /^[0-9]+$/.test(release);
|
||||
|
||||
// Reject non-numerical values with invalid uuid/hash lengths
|
||||
if (!isOnlyNumerical && !possibleUuidHashLength) {
|
||||
throw new ExpectedError('Invalid release parameter');
|
||||
}
|
||||
|
||||
// Reject leading-zero values with invalid uuid/hash lengths
|
||||
if (hasLeadingZero && !possibleUuidHashLength) {
|
||||
throw new ExpectedError('Invalid release parameter');
|
||||
}
|
||||
|
||||
// If alphanumeric, or has leading zero must now be uuid/hash.
|
||||
if (!isOnlyNumerical || hasLeadingZero) {
|
||||
return release;
|
||||
}
|
||||
|
||||
// Now very likely an integer id (but still could be number only uuid/hash)
|
||||
// Check integer id with API
|
||||
try {
|
||||
return (
|
||||
await balena.models.release.get(parseInt(release, 10), {
|
||||
$select: 'id',
|
||||
})
|
||||
).id;
|
||||
} catch (e) {
|
||||
if (e.name !== 'BalenaReleaseNotFound') {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Must be a number only uuid/hash (or nonexistent release)
|
||||
return (await balena.models.release.get(release, { $select: 'id' })).id;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ export function validateDotLocalUrl(input: string): boolean {
|
||||
}
|
||||
|
||||
export function validateLongUuid(input: string): boolean {
|
||||
if (input.length !== 32 && input.length !== 64) {
|
||||
if (input.length !== 32 && input.length !== 62) {
|
||||
return false;
|
||||
}
|
||||
return UUID_REGEX.test(input);
|
||||
@ -89,12 +89,9 @@ export function parseAsInteger(input: string, paramName?: string) {
|
||||
return Number(input);
|
||||
}
|
||||
|
||||
export function tryAsInteger(
|
||||
input: string,
|
||||
paramName?: string,
|
||||
): number | string {
|
||||
export function tryAsInteger(input: string): number | string {
|
||||
try {
|
||||
return parseAsInteger(input, paramName);
|
||||
return parseAsInteger(input);
|
||||
} catch {
|
||||
return input;
|
||||
}
|
||||
|
@ -69,9 +69,9 @@ Additional commands:
|
||||
os initialize <image> initialize an os image
|
||||
os versions <type> show the available balenaOS versions for the given device type
|
||||
settings print current settings
|
||||
tag rm <tagKey> remove a resource tag
|
||||
tag set <tagKey> [value] set a resource tag
|
||||
tags list all resource tags
|
||||
tag rm <tagkey> remove a tag from an application, device or release
|
||||
tag set <tagkey> [value] set a tag on an application, device or release
|
||||
tags list all tags for an application, device or release
|
||||
util available-drives list available drives
|
||||
version display version information for the balena CLI and/or Node.js
|
||||
whoami get current username and email address
|
||||
|
209
tests/utils/normalization.spec.ts
Normal file
209
tests/utils/normalization.spec.ts
Normal file
@ -0,0 +1,209 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 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 { BalenaReleaseNotFound } from 'balena-errors';
|
||||
import { expect } from 'chai';
|
||||
import * as sinon from 'sinon';
|
||||
import { ExpectedError } from '../../build/errors';
|
||||
import { disambiguateReleaseParam } from '../../build/utils/normalization';
|
||||
|
||||
describe('disambiguateReleaseParam() function', () => {
|
||||
it('should reject empty values', async () => {
|
||||
try {
|
||||
await disambiguateReleaseParam(null as any, '');
|
||||
throw new Error('should not be reached');
|
||||
} catch (e) {
|
||||
expect(e).to.be.an.instanceOf(ExpectedError);
|
||||
expect(e.message).to.equal('Invalid release parameter');
|
||||
}
|
||||
});
|
||||
|
||||
it('should reject values containing invalid chars', async () => {
|
||||
const invalidCharExamples = ' .,-_=!@#$%^&*() ';
|
||||
|
||||
for (const char of invalidCharExamples) {
|
||||
try {
|
||||
await disambiguateReleaseParam(null as any, char);
|
||||
throw new Error('should not be reached');
|
||||
} catch (e) {
|
||||
expect(e).to.be.an.instanceOf(ExpectedError);
|
||||
expect(e.message).to.equal('Invalid release parameter');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should reject non-numerical values with invalid uuid/hash lengths', async () => {
|
||||
const invalidLengthValue = 'abcd';
|
||||
|
||||
try {
|
||||
await disambiguateReleaseParam(null as any, invalidLengthValue);
|
||||
throw new Error('should not be reached');
|
||||
} catch (e) {
|
||||
expect(e).to.be.an.instanceOf(ExpectedError);
|
||||
expect(e.message).to.equal('Invalid release parameter');
|
||||
}
|
||||
});
|
||||
|
||||
it('should reject leading-zero numerical values with invalid uuid/hash lengths', async () => {
|
||||
const invalidLengthValue = '01234';
|
||||
|
||||
try {
|
||||
await disambiguateReleaseParam(null as any, invalidLengthValue);
|
||||
throw new Error('should not be reached');
|
||||
} catch (e) {
|
||||
expect(e).to.be.an.instanceOf(ExpectedError);
|
||||
expect(e.message).to.equal('Invalid release parameter');
|
||||
}
|
||||
});
|
||||
|
||||
it('should return non-numerical values with valid hash lengths as string, without SDK calls', async () => {
|
||||
const uuid7 = 'a'.repeat(7);
|
||||
const uuid32 = 'a'.repeat(32);
|
||||
const uuid62 = 'a'.repeat(62);
|
||||
const hash8 = 'a'.repeat(8);
|
||||
const hash9 = 'a'.repeat(9);
|
||||
const hash40 = 'a'.repeat(40);
|
||||
|
||||
expect(await disambiguateReleaseParam(null as any, uuid7)).to.equal(uuid7);
|
||||
expect(await disambiguateReleaseParam(null as any, uuid32)).to.equal(
|
||||
uuid32,
|
||||
);
|
||||
expect(await disambiguateReleaseParam(null as any, uuid62)).to.equal(
|
||||
uuid62,
|
||||
);
|
||||
expect(await disambiguateReleaseParam(null as any, hash8)).to.equal(hash8);
|
||||
expect(await disambiguateReleaseParam(null as any, hash9)).to.equal(hash9);
|
||||
expect(await disambiguateReleaseParam(null as any, hash40)).to.equal(
|
||||
hash40,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return numerical, leading zero values with valid uuid/hash lengths as string, without SDK calls', async () => {
|
||||
const uuid7 = '0' + '1'.repeat(6);
|
||||
const uuid32 = '0' + '1'.repeat(31);
|
||||
const uuid62 = '0' + '1'.repeat(61);
|
||||
const hash8 = '0' + '1'.repeat(7);
|
||||
const hash9 = '0' + '1'.repeat(8);
|
||||
const hash40 = '0' + '1'.repeat(39);
|
||||
|
||||
expect(await disambiguateReleaseParam(null as any, uuid7)).to.equal(uuid7);
|
||||
expect(await disambiguateReleaseParam(null as any, uuid32)).to.equal(
|
||||
uuid32,
|
||||
);
|
||||
expect(await disambiguateReleaseParam(null as any, uuid62)).to.equal(
|
||||
uuid62,
|
||||
);
|
||||
expect(await disambiguateReleaseParam(null as any, hash8)).to.equal(hash8);
|
||||
expect(await disambiguateReleaseParam(null as any, hash9)).to.equal(hash9);
|
||||
expect(await disambiguateReleaseParam(null as any, hash40)).to.equal(
|
||||
hash40,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return id from SDK on first call, if match is found', async () => {
|
||||
const input = '1234';
|
||||
const output = 1234;
|
||||
const getRelease = sinon.stub().returns(Promise.resolve({ id: output }));
|
||||
const sdk: any = {
|
||||
models: {
|
||||
release: {
|
||||
get: getRelease,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = await disambiguateReleaseParam(sdk, input);
|
||||
|
||||
expect(result).to.equal(output);
|
||||
expect(getRelease.calledOnce).to.be.true;
|
||||
expect(getRelease.getCall(0).args[0]).to.equal(parseInt(input, 10));
|
||||
});
|
||||
|
||||
it('should return id from SDK on second call, if match is found', async () => {
|
||||
const input = '1234';
|
||||
const output = 1234;
|
||||
const getRelease = sinon
|
||||
.stub()
|
||||
.onCall(0)
|
||||
.returns(Promise.reject(new BalenaReleaseNotFound(input)))
|
||||
.onCall(1)
|
||||
.returns(Promise.resolve({ id: output }));
|
||||
|
||||
const sdk: any = {
|
||||
models: {
|
||||
release: {
|
||||
get: getRelease,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = await disambiguateReleaseParam(sdk, input);
|
||||
|
||||
expect(result).to.equal(output);
|
||||
expect(getRelease.calledTwice).to.be.true;
|
||||
expect(getRelease.getCall(0).args[0]).to.equal(parseInt(input, 10));
|
||||
expect(getRelease.getCall(1).args[0]).to.equal(input);
|
||||
});
|
||||
|
||||
it('should throw error if no match found', async () => {
|
||||
const input = '1234';
|
||||
const getRelease = sinon
|
||||
.stub()
|
||||
.returns(Promise.reject(new BalenaReleaseNotFound(input)));
|
||||
|
||||
const sdk: any = {
|
||||
models: {
|
||||
release: {
|
||||
get: getRelease,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
await disambiguateReleaseParam(sdk, input);
|
||||
throw new Error('should not be reached');
|
||||
} catch (e) {
|
||||
expect(e).to.be.an.instanceOf(BalenaReleaseNotFound);
|
||||
expect(getRelease.calledTwice).to.be.true;
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw error if unknown error returned from SDK', async () => {
|
||||
const input = '1234';
|
||||
|
||||
const getRelease = sinon
|
||||
.stub()
|
||||
.returns(Promise.reject(new Error('some error')));
|
||||
|
||||
const sdk: any = {
|
||||
models: {
|
||||
release: {
|
||||
get: getRelease,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
await disambiguateReleaseParam(sdk, input);
|
||||
throw new Error('should not be reached');
|
||||
} catch (e) {
|
||||
expect(e).to.be.an.instanceOf(Error);
|
||||
expect(e.message).to.equal('some error');
|
||||
expect(getRelease.calledOnce).to.be.true;
|
||||
}
|
||||
});
|
||||
});
|
@ -114,17 +114,17 @@ describe('validateDotLocalUrl() function', () => {
|
||||
});
|
||||
|
||||
describe('validateLongUuid() function', () => {
|
||||
it('should return false for strings with length other than 32 or 64', () => {
|
||||
it('should return false for strings with length other than 32 or 62', () => {
|
||||
expect(v.validateLongUuid('')).to.equal(false);
|
||||
expect(v.validateLongUuid('abc')).to.equal(false);
|
||||
expect(v.validateLongUuid('a'.repeat(31))).to.equal(false);
|
||||
expect(v.validateLongUuid('a'.repeat(33))).to.equal(false);
|
||||
expect(v.validateLongUuid('a'.repeat(63))).to.equal(false);
|
||||
expect(v.validateLongUuid('a'.repeat(65))).to.equal(false);
|
||||
expect(v.validateLongUuid('a'.repeat(64))).to.equal(false);
|
||||
});
|
||||
|
||||
it('should return false for strings with characters other than a-z,0-9', () => {
|
||||
it('should return false for strings with characters other than a-f,0-9', () => {
|
||||
expect(v.validateLongUuid('a'.repeat(31) + 'A')).to.equal(false);
|
||||
expect(v.validateLongUuid('a'.repeat(31) + 'g')).to.equal(false);
|
||||
expect(v.validateLongUuid('a'.repeat(31) + '.')).to.equal(false);
|
||||
expect(v.validateLongUuid('a'.repeat(31) + '-')).to.equal(false);
|
||||
expect(v.validateLongUuid('a'.repeat(31) + '_')).to.equal(false);
|
||||
@ -134,9 +134,7 @@ describe('validateLongUuid() function', () => {
|
||||
expect(v.validateLongUuid('8ab84942d20b4753e08243a9e3a177e2')).to.equal(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
v.validateLongUuid('8ab84942d20b4753e08243a9e3a177e2'.repeat(2)),
|
||||
).to.equal(true);
|
||||
expect(v.validateLongUuid('a'.repeat(62))).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -161,19 +159,19 @@ describe('validateShortUuid() function', () => {
|
||||
});
|
||||
|
||||
describe('validateUuid() function', () => {
|
||||
it('should return false for strings with length other than 7, 32 or 64', () => {
|
||||
it('should return false for strings with length other than 7, 32 or 62', () => {
|
||||
expect(v.validateUuid('')).to.equal(false);
|
||||
expect(v.validateUuid('abc')).to.equal(false);
|
||||
expect(v.validateUuid('a'.repeat(6))).to.equal(false);
|
||||
expect(v.validateUuid('a'.repeat(8))).to.equal(false);
|
||||
expect(v.validateUuid('a'.repeat(31))).to.equal(false);
|
||||
expect(v.validateUuid('a'.repeat(33))).to.equal(false);
|
||||
expect(v.validateUuid('a'.repeat(63))).to.equal(false);
|
||||
expect(v.validateUuid('a'.repeat(65))).to.equal(false);
|
||||
expect(v.validateUuid('a'.repeat(64))).to.equal(false);
|
||||
});
|
||||
|
||||
it('should return false for strings with characters other than a-z,0-9', () => {
|
||||
it('should return false for strings with characters other than a-f,0-9', () => {
|
||||
expect(v.validateUuid('a'.repeat(31) + 'A')).to.equal(false);
|
||||
expect(v.validateUuid('a'.repeat(31) + 'g')).to.equal(false);
|
||||
expect(v.validateUuid('a'.repeat(31) + '.')).to.equal(false);
|
||||
expect(v.validateUuid('a'.repeat(31) + '-')).to.equal(false);
|
||||
expect(v.validateUuid('a'.repeat(31) + '_')).to.equal(false);
|
||||
@ -182,9 +180,7 @@ describe('validateUuid() function', () => {
|
||||
it('should return true for valid UUIDs', () => {
|
||||
expect(v.validateUuid('8ab8494')).to.equal(true);
|
||||
expect(v.validateUuid('8ab84942d20b4753e08243a9e3a177e2')).to.equal(true);
|
||||
expect(
|
||||
v.validateUuid('8ab84942d20b4753e08243a9e3a177e2'.repeat(2)),
|
||||
).to.equal(true);
|
||||
expect(v.validateLongUuid('a'.repeat(62))).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -221,3 +217,24 @@ describe('parseAsInteger() function', () => {
|
||||
expect(v.parseAsInteger('0')).to.be.a('number');
|
||||
});
|
||||
});
|
||||
|
||||
describe('tryAsInteger() function', () => {
|
||||
it('should return string with non-numeric characters as string', () => {
|
||||
expect(v.tryAsInteger('abc')).to.be.a('string');
|
||||
expect(v.tryAsInteger('1a')).to.be.a('string');
|
||||
expect(v.tryAsInteger('a1')).to.be.a('string');
|
||||
expect(v.tryAsInteger('a')).to.be.a('string');
|
||||
expect(v.tryAsInteger('1.0')).to.be.a('string');
|
||||
});
|
||||
|
||||
it('should return numerical strings with leading zeros as string', () => {
|
||||
expect(v.tryAsInteger('01')).to.be.a('string');
|
||||
expect(v.tryAsInteger('001')).to.be.a('string');
|
||||
});
|
||||
|
||||
it('should return numerical strings without leading zeros as number', () => {
|
||||
expect(v.tryAsInteger('100')).to.be.a('number');
|
||||
expect(v.tryAsInteger('256')).to.be.a('number');
|
||||
expect(v.tryAsInteger('0')).to.be.a('number');
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user