clever-tools 3.13.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -37
- package/bin/clever.js +1427 -718
- package/package.json +62 -77
- package/src/clever-client/auth-bridge.js +9 -12
- package/src/clever-client/ng.js +1 -1
- package/src/clever-client/operators.js +7 -7
- package/src/command-options.js +6 -6
- package/src/command-promise-handler.js +6 -6
- package/src/commands/accesslogs.js +38 -29
- package/src/commands/activity.js +62 -40
- package/src/commands/addon.js +65 -69
- package/src/commands/applications.js +33 -31
- package/src/commands/cancel-deploy.js +7 -7
- package/src/commands/config.js +9 -7
- package/src/commands/console.js +3 -3
- package/src/commands/create.js +33 -32
- package/src/commands/curl.js +14 -36
- package/src/commands/database.js +10 -30
- package/src/commands/delete.js +8 -8
- package/src/commands/deploy.js +60 -46
- package/src/commands/diag.js +27 -25
- package/src/commands/domain.js +89 -91
- package/src/commands/drain.js +26 -14
- package/src/commands/emails.js +24 -28
- package/src/commands/env.js +18 -18
- package/src/commands/features.js +12 -18
- package/src/commands/keycloak.js +11 -11
- package/src/commands/kv.js +13 -13
- package/src/commands/link.js +9 -8
- package/src/commands/login.js +19 -27
- package/src/commands/logout.js +1 -1
- package/src/commands/logs.js +20 -12
- package/src/commands/makeDefault.js +5 -5
- package/src/commands/matomo.js +7 -7
- package/src/commands/metabase.js +9 -9
- package/src/commands/ng.js +32 -32
- package/src/commands/notify-email.js +11 -15
- package/src/commands/open.js +1 -1
- package/src/commands/otoroshi.js +11 -11
- package/src/commands/profile.js +8 -8
- package/src/commands/published-config.js +11 -11
- package/src/commands/restart.js +15 -8
- package/src/commands/scale.js +25 -16
- package/src/commands/service.js +28 -11
- package/src/commands/ssh-keys.js +25 -29
- package/src/commands/ssh.js +1 -2
- package/src/commands/status.js +31 -22
- package/src/commands/stop.js +3 -3
- package/src/commands/tcp-redirs.js +27 -26
- package/src/commands/tokens.js +44 -43
- package/src/commands/unlink.js +7 -5
- package/src/commands/version.js +2 -4
- package/src/commands/webhooks.js +8 -10
- package/src/experimental-features.js +7 -5
- package/src/format-table.js +46 -15
- package/src/initial-setup.js +2 -32
- package/src/initial-update-notifier.js +18 -0
- package/src/lib/has-param.js +16 -0
- package/src/lib/ng-print.js +21 -24
- package/src/lib/operator-commands.js +58 -53
- package/src/lib/prompts.js +5 -5
- package/src/lib/slugify.js +1 -1
- package/src/logger.js +26 -21
- package/src/models/activity.js +3 -3
- package/src/models/addon.js +54 -56
- package/src/models/app_configuration.js +34 -32
- package/src/models/application.js +90 -77
- package/src/models/application_configuration.js +19 -27
- package/src/models/configuration.js +30 -32
- package/src/models/deployments.js +9 -19
- package/src/models/domain.js +10 -9
- package/src/models/drain.js +16 -15
- package/src/models/exit-strategy-option.js +15 -5
- package/src/models/fs-utils.js +4 -3
- package/src/models/git.js +26 -32
- package/src/models/ids-resolver.js +37 -41
- package/src/models/isomorphic-http-with-agent.js +3 -3
- package/src/models/json-array.js +5 -6
- package/src/models/log-v4.js +44 -52
- package/src/models/log.js +40 -45
- package/src/models/namespaces.js +4 -4
- package/src/models/ng-resources.js +49 -39
- package/src/models/ng.js +41 -40
- package/src/models/node-dns-resolver.js +3 -3
- package/src/models/notification.js +7 -10
- package/src/models/operator.js +8 -10
- package/src/models/organisation.js +5 -8
- package/src/models/send-to-api.js +18 -11
- package/src/models/user.js +6 -5
- package/src/models/utils.js +5 -8
- package/src/models/variables.js +18 -20
- package/src/parsers.js +34 -34
- package/src/load-package-json.cjs +0 -5
package/src/commands/tokens.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import dedent from 'dedent';
|
|
2
|
+
import { styleText } from 'node:util';
|
|
3
3
|
import { createApiToken, deleteApiToken, listApiTokens } from '../clever-client/auth-bridge.js';
|
|
4
|
+
import { promptSecret } from '../lib/prompts.js';
|
|
5
|
+
import { Logger } from '../logger.js';
|
|
6
|
+
import { conf } from '../models/configuration.js';
|
|
4
7
|
import { sendToAuthBridge } from '../models/send-to-api.js';
|
|
5
8
|
import { getCurrent as getCurrentUser } from '../models/user.js';
|
|
6
|
-
import { conf } from '../models/configuration.js';
|
|
7
|
-
import dedent from 'dedent';
|
|
8
|
-
import { promptSecret } from '../lib/prompts.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Create a new API token
|
|
@@ -15,7 +15,7 @@ import { promptSecret } from '../lib/prompts.js';
|
|
|
15
15
|
* @param {'json'|'human'} params.options.format - Output format
|
|
16
16
|
* @param {number} params.options.expiration - Expiration date as timestamp
|
|
17
17
|
*/
|
|
18
|
-
export async function create
|
|
18
|
+
export async function create(params) {
|
|
19
19
|
const [apiTokenName] = params.args;
|
|
20
20
|
const { expiration, format } = params.options;
|
|
21
21
|
const user = await getCurrentUser();
|
|
@@ -23,8 +23,8 @@ export async function create (params) {
|
|
|
23
23
|
if (!user.hasPassword) {
|
|
24
24
|
const apiTokenListHref = new URL('/users/me/api-tokens', conf.CONSOLE_URL).href;
|
|
25
25
|
throw new Error(dedent`
|
|
26
|
-
${
|
|
27
|
-
${
|
|
26
|
+
${styleText('yellow', '!')} Your Clever Cloud account is linked via GitHub and has no password. Setting one is required to create API tokens.
|
|
27
|
+
${styleText('blue', '→')} To do so, go to the following URL: ${styleText('blue', apiTokenListHref)}
|
|
28
28
|
`);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -39,8 +39,7 @@ export async function create (params) {
|
|
|
39
39
|
throw new Error('You cannot set an expiration date greater than 1 year');
|
|
40
40
|
}
|
|
41
41
|
expirationDate = new Date(expiration);
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
42
|
+
} else {
|
|
44
43
|
expirationDate = maxExpirationDate;
|
|
45
44
|
}
|
|
46
45
|
|
|
@@ -58,16 +57,18 @@ export async function create (params) {
|
|
|
58
57
|
name: apiTokenName,
|
|
59
58
|
expirationDate: expirationDate.toISOString(),
|
|
60
59
|
};
|
|
61
|
-
const createdToken = await createApiToken(tokenData)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
60
|
+
const createdToken = await createApiToken(tokenData)
|
|
61
|
+
.then(sendToAuthBridge)
|
|
62
|
+
.catch((error) => {
|
|
63
|
+
const errorCode = error?.cause?.responseBody?.code;
|
|
64
|
+
if (errorCode === 'invalid-credential') {
|
|
65
|
+
throw new Error('Invalid credentials, check your password');
|
|
66
|
+
}
|
|
67
|
+
if (errorCode === 'invalid-mfa-code') {
|
|
68
|
+
throw new Error('Invalid credentials, check your 2FA code');
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
});
|
|
71
72
|
|
|
72
73
|
switch (format) {
|
|
73
74
|
case 'json':
|
|
@@ -76,11 +77,11 @@ export async function create (params) {
|
|
|
76
77
|
case 'human':
|
|
77
78
|
default:
|
|
78
79
|
Logger.println(dedent`
|
|
79
|
-
${
|
|
80
|
+
${styleText('green', '✔')} API token successfully created! Store it securely, you won't able to print it again.
|
|
80
81
|
|
|
81
|
-
- API token ID : ${
|
|
82
|
-
- API token : ${
|
|
83
|
-
- Expiration : ${
|
|
82
|
+
- API token ID : ${styleText('grey', createdToken.apiTokenId)}
|
|
83
|
+
- API token : ${styleText('grey', createdToken.apiToken)}
|
|
84
|
+
- Expiration : ${styleText('grey', formatDate(createdToken.expirationDate))}
|
|
84
85
|
|
|
85
86
|
Export this token and use it to make authenticated requests to the Clever Cloud API through the Auth Bridge:
|
|
86
87
|
|
|
@@ -100,29 +101,29 @@ export async function create (params) {
|
|
|
100
101
|
* @param {Object} params.options.format - Output format
|
|
101
102
|
* @returns {Promise<void>}
|
|
102
103
|
*/
|
|
103
|
-
export async function list
|
|
104
|
+
export async function list(params) {
|
|
104
105
|
const { format } = params.options;
|
|
105
106
|
|
|
106
107
|
const tokens = await listApiTokens().then(sendToAuthBridge);
|
|
107
108
|
|
|
108
109
|
if (format === 'json') {
|
|
109
110
|
Logger.printJson(tokens);
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
111
|
+
} else {
|
|
112
112
|
if (tokens.length === 0) {
|
|
113
|
-
Logger.println(`ℹ️ No API token found, create one with ${
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
113
|
+
Logger.println(`ℹ️ No API token found, create one with ${styleText('blue', 'clever tokens create')} command`);
|
|
114
|
+
} else {
|
|
115
|
+
console.table(
|
|
116
|
+
tokens.map((token) => {
|
|
117
|
+
return {
|
|
118
|
+
'API token ID': token.apiTokenId,
|
|
119
|
+
Name: token.name,
|
|
120
|
+
'Creation IP address': token.ip,
|
|
121
|
+
Creation: formatDate(token.creationDate),
|
|
122
|
+
Expiration: formatDate(token.expirationDate),
|
|
123
|
+
State: token.state,
|
|
124
|
+
};
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
129
|
}
|
|
@@ -133,14 +134,14 @@ export async function list (params) {
|
|
|
133
134
|
* @param {string[]} params.args - Command line arguments, token ID to revoke is expected as first argument
|
|
134
135
|
* @returns {Promise<void>}
|
|
135
136
|
*/
|
|
136
|
-
export async function revoke
|
|
137
|
+
export async function revoke(params) {
|
|
137
138
|
const [apiTokenId] = params.args;
|
|
138
139
|
|
|
139
140
|
await deleteApiToken(apiTokenId).then(sendToAuthBridge);
|
|
140
141
|
|
|
141
|
-
Logger.println(
|
|
142
|
+
Logger.println(styleText('green', '✔'), 'API token successfully revoked!');
|
|
142
143
|
}
|
|
143
144
|
|
|
144
|
-
function formatDate
|
|
145
|
+
function formatDate(dateInput) {
|
|
145
146
|
return new Date(dateInput).toISOString().substring(0, 16).replace('T', ' ');
|
|
146
147
|
}
|
package/src/commands/unlink.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
|
+
import { Logger } from '../logger.js';
|
|
1
3
|
import * as AppConfig from '../models/app_configuration.js';
|
|
2
4
|
import * as Application from '../models/application.js';
|
|
3
|
-
import { Logger } from '../logger.js';
|
|
4
|
-
import colors from 'colors/safe.js';
|
|
5
5
|
|
|
6
|
-
export async function unlink
|
|
6
|
+
export async function unlink(params) {
|
|
7
7
|
const [alias] = params.args;
|
|
8
8
|
const app = await AppConfig.getAppDetails({ alias });
|
|
9
9
|
|
|
10
10
|
await Application.unlinkRepo(app.alias);
|
|
11
|
-
Logger.printSuccess(
|
|
12
|
-
}
|
|
11
|
+
Logger.printSuccess(
|
|
12
|
+
`Application ${styleText('green', app.appId)} has been successfully unlinked from local alias ${styleText('green', app.alias)}!`,
|
|
13
|
+
);
|
|
14
|
+
}
|
package/src/commands/version.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
+
import pkg from '../../package.json' with { type: 'json' };
|
|
1
2
|
import { Logger } from '../logger.js';
|
|
2
|
-
import { getPackageJson } from '../load-package-json.cjs';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export async function version () {
|
|
4
|
+
export async function version() {
|
|
7
5
|
Logger.println(pkg.version);
|
|
8
6
|
}
|
package/src/commands/webhooks.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { createWebhook, deleteWebhook, getWebhooks } from '@clevercloud/client/esm/api/v2/notification.js';
|
|
2
|
+
import { styleText } from 'node:util';
|
|
3
3
|
import { Logger } from '../logger.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
import { getWebhooks, createWebhook, deleteWebhook } from '@clevercloud/client/esm/api/v2/notification.js';
|
|
4
|
+
import { getOrgaIdOrUserId, getOwnerAndApp } from '../models/notification.js';
|
|
7
5
|
import { sendToApi } from '../models/send-to-api.js';
|
|
8
6
|
|
|
9
|
-
export async function list
|
|
7
|
+
export async function list(params) {
|
|
10
8
|
const { org, 'list-all': listAll, format } = params.options;
|
|
11
9
|
|
|
12
10
|
// TODO: fix alias option
|
|
@@ -35,7 +33,7 @@ export async function list (params) {
|
|
|
35
33
|
case 'human':
|
|
36
34
|
default: {
|
|
37
35
|
formattedHooks.forEach((hook) => {
|
|
38
|
-
Logger.println(hook.name ?
|
|
36
|
+
Logger.println(hook.name ? styleText('bold', hook.name) : hook.id);
|
|
39
37
|
Logger.println(` id: ${hook.id}`);
|
|
40
38
|
Logger.println(` services: ${hook.services.join(', ')}`);
|
|
41
39
|
Logger.println(` events: ${hook.events.join(', ')}`);
|
|
@@ -46,7 +44,7 @@ export async function list (params) {
|
|
|
46
44
|
}
|
|
47
45
|
}
|
|
48
46
|
|
|
49
|
-
export async function add
|
|
47
|
+
export async function add(params) {
|
|
50
48
|
const { org, format, event: events, service } = params.options;
|
|
51
49
|
const [name, hookUrl] = params.args;
|
|
52
50
|
|
|
@@ -56,7 +54,7 @@ export async function add (params) {
|
|
|
56
54
|
const body = {
|
|
57
55
|
name,
|
|
58
56
|
urls: [{ format, url: hookUrl }],
|
|
59
|
-
scope:
|
|
57
|
+
scope: appId != null && service == null ? [appId] : service,
|
|
60
58
|
events,
|
|
61
59
|
};
|
|
62
60
|
|
|
@@ -65,7 +63,7 @@ export async function add (params) {
|
|
|
65
63
|
Logger.println('The webhook has been added');
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
export async function remove
|
|
66
|
+
export async function remove(params) {
|
|
69
67
|
const { org } = params.options;
|
|
70
68
|
const [notificationId] = params.args;
|
|
71
69
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import dedent from 'dedent';
|
|
2
|
+
import { conf } from './models/configuration.js';
|
|
2
3
|
|
|
3
4
|
export const EXPERIMENTAL_FEATURES = {
|
|
4
5
|
kv: {
|
|
5
6
|
status: 'alpha',
|
|
6
|
-
description:
|
|
7
|
+
description:
|
|
8
|
+
'Send commands to databases such as Materia KV or Redis® directly from Clever Tools, without other dependencies',
|
|
7
9
|
instructions: dedent`
|
|
8
10
|
Target any compatible add-on by its name or ID (with an org ID if needed) and send commands to it:
|
|
9
11
|
|
|
@@ -13,7 +15,7 @@ export const EXPERIMENTAL_FEATURES = {
|
|
|
13
15
|
clever kv myMateriaKV -o myOrg TTL myTempKey
|
|
14
16
|
clever kv redis_xxxxx --org org_xxxxx PING
|
|
15
17
|
|
|
16
|
-
Learn more about Materia KV:
|
|
18
|
+
Learn more about Materia KV: ${conf.DOC_URL}/addons/materia-kv/
|
|
17
19
|
`,
|
|
18
20
|
},
|
|
19
21
|
ng: {
|
|
@@ -41,7 +43,7 @@ export const EXPERIMENTAL_FEATURES = {
|
|
|
41
43
|
- Search Network Groups, members or peers:
|
|
42
44
|
clever ng search myQuery
|
|
43
45
|
|
|
44
|
-
Learn more about Network Groups:
|
|
46
|
+
Learn more about Network Groups: ${conf.DOC_URL}/develop/network-groups/
|
|
45
47
|
`,
|
|
46
48
|
},
|
|
47
49
|
operators: {
|
|
@@ -51,10 +53,10 @@ export const EXPERIMENTAL_FEATURES = {
|
|
|
51
53
|
clever keycloak
|
|
52
54
|
clever keycloak get keycloak_xxx
|
|
53
55
|
clever keycloak ng enable myKeycloak
|
|
54
|
-
|
|
56
|
+
|
|
55
57
|
clever metabase version check myMetabase
|
|
56
58
|
clever metabase version update myMetabase 0.53
|
|
57
|
-
|
|
59
|
+
|
|
58
60
|
clever matomo open myMatomo
|
|
59
61
|
clever otoroshi open logs myOtoroshi
|
|
60
62
|
`,
|
package/src/format-table.js
CHANGED
|
@@ -1,20 +1,51 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import stringLength from 'string-length';
|
|
1
|
+
import charRegex from 'char-regex';
|
|
2
|
+
import { stripVTControlCharacters } from 'node:util';
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
const SEPARATOR = ' ';
|
|
6
5
|
|
|
6
|
+
function stringLength(string) {
|
|
7
|
+
if (!string) {
|
|
8
|
+
return 0;
|
|
9
|
+
}
|
|
10
|
+
const stringWithoutAnsi = stripVTControlCharacters(string);
|
|
11
|
+
if (!stringWithoutAnsi) {
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
const stringWithSplitEmojis = stringWithoutAnsi.match(charRegex());
|
|
15
|
+
if (!stringWithSplitEmojis) {
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
return stringWithSplitEmojis.length;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const formatTable = (data, columnWidth = []) => {
|
|
7
22
|
const fixedWidthPlaceholder = columnWidth.map((item) => {
|
|
8
|
-
|
|
9
|
-
return _.repeat(' ', item);
|
|
10
|
-
}
|
|
11
|
-
return item;
|
|
23
|
+
return typeof item === 'number' ? ' '.repeat(item) : item;
|
|
12
24
|
});
|
|
13
25
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
26
|
+
const columnSizes = [fixedWidthPlaceholder, ...data]
|
|
27
|
+
.map((row) => row.map((cell) => String(cell)))
|
|
28
|
+
.reduce((acc, row) => {
|
|
29
|
+
row.forEach((cell, index) => {
|
|
30
|
+
const cellLength = stringLength(cell);
|
|
31
|
+
acc[index] = Math.max(acc[index] ?? 0, cellLength);
|
|
32
|
+
});
|
|
33
|
+
return acc;
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
return data
|
|
37
|
+
.map((row) => row.map((cell) => String(cell)))
|
|
38
|
+
.map((row) => {
|
|
39
|
+
return row
|
|
40
|
+
.map((cell, index) => {
|
|
41
|
+
const isLastColumn = index === row.length - 1;
|
|
42
|
+
if (isLastColumn) {
|
|
43
|
+
return cell;
|
|
44
|
+
}
|
|
45
|
+
const rightPaddingLength = columnSizes[index] - stringLength(cell) ?? 0;
|
|
46
|
+
return cell + ' '.repeat(rightPaddingLength);
|
|
47
|
+
})
|
|
48
|
+
.join(SEPARATOR);
|
|
49
|
+
})
|
|
50
|
+
.join('\n');
|
|
51
|
+
};
|
package/src/initial-setup.js
CHANGED
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { getPackageJson } from './load-package-json.cjs';
|
|
3
|
-
import updateNotifierModule from 'update-notifier';
|
|
4
|
-
|
|
5
|
-
function hasParam (param, paramValue) {
|
|
6
|
-
const index = process.argv.indexOf(param);
|
|
7
|
-
if (index === -1) {
|
|
8
|
-
return false;
|
|
9
|
-
}
|
|
10
|
-
if (paramValue != null) {
|
|
11
|
-
return process.argv[index + 1] === paramValue;
|
|
12
|
-
}
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
1
|
+
import { hasParam } from './lib/has-param.js';
|
|
15
2
|
|
|
16
3
|
// These need to be set before Logger and other stuffs
|
|
17
4
|
if (hasParam('-v') || hasParam('--verbose')) {
|
|
@@ -28,22 +15,5 @@ if (hasParam('--autocomplete-index')) {
|
|
|
28
15
|
const colorExplicitFalse = hasParam('--no-color') || hasParam('--color', 'false');
|
|
29
16
|
const colorExplicitTrue = hasParam('--color', 'true');
|
|
30
17
|
if (colorExplicitFalse || (!process.stdout.isTTY && !colorExplicitTrue)) {
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// These need to be set before Logger and other stuffs
|
|
35
|
-
const pkg = getPackageJson();
|
|
36
|
-
const isRunThroughPackagedBinary = process.pkg != null;
|
|
37
|
-
const updateNotifierExplicitFalse = hasParam('--no-update-notifier') || hasParam('--update-notifier', 'false');
|
|
38
|
-
if (!updateNotifierExplicitFalse && !isRunThroughPackagedBinary) {
|
|
39
|
-
updateNotifierModule({
|
|
40
|
-
pkg,
|
|
41
|
-
tagsUrl: 'https://api.github.com/repos/CleverCloud/clever-tools/tags',
|
|
42
|
-
}).notify({
|
|
43
|
-
isGlobal: true,
|
|
44
|
-
getDetails () {
|
|
45
|
-
const docsUrl = 'https://github.com/CleverCloud/clever-tools/tree/master/docs#how-to-use-clever-tools';
|
|
46
|
-
return `\nPlease follow this link to update your clever-tools:\n${docsUrl}`;
|
|
47
|
-
},
|
|
48
|
-
});
|
|
18
|
+
process.env.NO_COLOR = '1';
|
|
49
19
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import updateNotifierModule from 'update-notifier';
|
|
2
|
+
import pkg from '../package.json' with { type: 'json' };
|
|
3
|
+
import { hasParam } from './lib/has-param.js';
|
|
4
|
+
|
|
5
|
+
// These need to be set before Logger and other stuffs
|
|
6
|
+
const updateNotifierExplicitFalse = hasParam('--no-update-notifier') || hasParam('--update-notifier', 'false');
|
|
7
|
+
if (!updateNotifierExplicitFalse) {
|
|
8
|
+
updateNotifierModule({
|
|
9
|
+
pkg,
|
|
10
|
+
tagsUrl: 'https://api.github.com/repos/CleverCloud/clever-tools/tags',
|
|
11
|
+
}).notify({
|
|
12
|
+
isGlobal: true,
|
|
13
|
+
getDetails() {
|
|
14
|
+
const docsUrl = 'https://github.com/CleverCloud/clever-tools/tree/master/docs#how-to-use-clever-tools';
|
|
15
|
+
return `\nPlease follow this link to update your clever-tools:\n${docsUrl}`;
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a specific parameter exists in the command line arguments.
|
|
3
|
+
* @param {string} param
|
|
4
|
+
* @param {string} [paramValue]
|
|
5
|
+
* @return {boolean}
|
|
6
|
+
*/
|
|
7
|
+
export function hasParam(param, paramValue) {
|
|
8
|
+
const index = process.argv.indexOf(param);
|
|
9
|
+
if (index === -1) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (paramValue != null) {
|
|
13
|
+
return process.argv[index + 1] === paramValue;
|
|
14
|
+
}
|
|
15
|
+
return true;
|
|
16
|
+
}
|
package/src/lib/ng-print.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as networkGroup from '../models/ng.js';
|
|
3
|
-
|
|
1
|
+
import { styleText } from 'node:util';
|
|
4
2
|
import { Logger } from '../logger.js';
|
|
3
|
+
import * as networkGroup from '../models/ng.js';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Print a Network Group
|
|
@@ -9,8 +8,7 @@ import { Logger } from '../logger.js';
|
|
|
9
8
|
* @param {string} format Output format
|
|
10
9
|
* @param {boolean} full If true, get more details about the Network Group (default: false)
|
|
11
10
|
*/
|
|
12
|
-
function printNg
|
|
13
|
-
|
|
11
|
+
function printNg(ng, format, full = false) {
|
|
14
12
|
switch (format) {
|
|
15
13
|
case 'json': {
|
|
16
14
|
Logger.printJson(ng);
|
|
@@ -31,19 +29,19 @@ function printNg (ng, format, full = false) {
|
|
|
31
29
|
if (full) {
|
|
32
30
|
const members = Object.entries(ng.members)
|
|
33
31
|
.sort((a, b) => a[1].domainName.localeCompare(b[1].domainName))
|
|
34
|
-
.map(([
|
|
32
|
+
.map(([_id, member]) => ({
|
|
35
33
|
Domain: member.domainName,
|
|
36
34
|
}));
|
|
37
35
|
if (members.length > 0) {
|
|
38
|
-
Logger.println(
|
|
36
|
+
Logger.println(styleText('bold', ' • Members:'));
|
|
39
37
|
console.table(members);
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
const peers = Object.entries(ng.peers)
|
|
43
41
|
.sort((a, b) => a[1].parentMember.localeCompare(b[1].parentMember))
|
|
44
|
-
.map(([
|
|
42
|
+
.map(([_id, peer]) => formatPeer(peer));
|
|
45
43
|
if (peers.length > 0) {
|
|
46
|
-
Logger.println(
|
|
44
|
+
Logger.println(styleText('bold', ' • Peers:'));
|
|
47
45
|
console.table(peers);
|
|
48
46
|
}
|
|
49
47
|
}
|
|
@@ -56,8 +54,7 @@ function printNg (ng, format, full = false) {
|
|
|
56
54
|
* @param {Object} member The Network Group member to print
|
|
57
55
|
* @param {string} format Output format
|
|
58
56
|
*/
|
|
59
|
-
function printMember
|
|
60
|
-
|
|
57
|
+
function printMember(member, format) {
|
|
61
58
|
switch (format) {
|
|
62
59
|
case 'json': {
|
|
63
60
|
Logger.printJson(member);
|
|
@@ -79,7 +76,7 @@ function printMember (member, format) {
|
|
|
79
76
|
* @param {string} format Output format
|
|
80
77
|
* @param {boolean} full If true, get more details about the peer (default: false)
|
|
81
78
|
*/
|
|
82
|
-
function printPeer
|
|
79
|
+
function printPeer(peer, format, full = false) {
|
|
83
80
|
switch (format) {
|
|
84
81
|
case 'json': {
|
|
85
82
|
Logger.printJson(peer);
|
|
@@ -97,7 +94,7 @@ function printPeer (peer, format, full = false) {
|
|
|
97
94
|
* @param {Object} peer
|
|
98
95
|
* @param {boolean} full If true, get more details about the peer (default: false)
|
|
99
96
|
*/
|
|
100
|
-
function formatPeer
|
|
97
|
+
function formatPeer(peer, full = false) {
|
|
101
98
|
const peerToPrint = {
|
|
102
99
|
'Parent Member': peer.parentMember,
|
|
103
100
|
ID: peer.id,
|
|
@@ -108,8 +105,7 @@ function formatPeer (peer, full = false) {
|
|
|
108
105
|
if (full) {
|
|
109
106
|
if (peer.endpoint.ngTerm != null) {
|
|
110
107
|
peerToPrint['Host:IP'] = `${peer.endpoint.ngTerm.host}:${peer.endpoint.ngTerm.port}`;
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
108
|
+
} else {
|
|
113
109
|
peerToPrint.Host = peer.endpoint.ngIp;
|
|
114
110
|
}
|
|
115
111
|
if (peer.endpoint.publicTerm != null) {
|
|
@@ -128,18 +124,17 @@ function formatPeer (peer, full = false) {
|
|
|
128
124
|
* @param {string} action Action to perform (search or get)
|
|
129
125
|
* @param {string} type Type of item to search (NetworkGroup, Member, Peer)
|
|
130
126
|
*/
|
|
131
|
-
export async function printResults
|
|
132
|
-
|
|
127
|
+
export async function printResults(idOrLabel, org, format, action, type) {
|
|
133
128
|
const exactMatch = action === 'get';
|
|
134
129
|
const toLookFor = type ?? (action === 'search' ? 'all' : 'single');
|
|
135
130
|
|
|
136
131
|
const found = await networkGroup.searchNgOrResource(idOrLabel, org, toLookFor, exactMatch);
|
|
137
132
|
|
|
138
133
|
if (!found.length) {
|
|
139
|
-
const searchString = idOrLabel.ngId
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
134
|
+
const searchString = idOrLabel.ngId ?? idOrLabel.memberId ?? idOrLabel.ngResourceLabel;
|
|
135
|
+
Logger.println(
|
|
136
|
+
`${styleText('blue', '!')} No Network Group or resource found for ${styleText('blue', searchString)}`,
|
|
137
|
+
);
|
|
143
138
|
return;
|
|
144
139
|
}
|
|
145
140
|
|
|
@@ -175,17 +170,19 @@ export async function printResults (idOrLabel, org, format, action, type) {
|
|
|
175
170
|
case 'human':
|
|
176
171
|
default: {
|
|
177
172
|
if (grouped.NetworkGroup) {
|
|
178
|
-
Logger.println(`${
|
|
173
|
+
Logger.println(`${styleText('bold', ` • Found ${grouped.NetworkGroup.length} Network Group(s):`)}`);
|
|
179
174
|
grouped.NetworkGroup?.forEach((item) => printNg(item, format));
|
|
180
175
|
}
|
|
181
176
|
|
|
182
177
|
if (grouped.Member) {
|
|
183
|
-
Logger.println(`${
|
|
178
|
+
Logger.println(`${styleText('bold', ` • Found ${grouped.Member.length} Member(s):`)}`);
|
|
184
179
|
grouped.Member?.forEach((item) => printMember(item, format));
|
|
185
180
|
}
|
|
186
181
|
|
|
187
182
|
if (grouped.ExternalPeer || grouped.CleverPeer) {
|
|
188
|
-
Logger.println(
|
|
183
|
+
Logger.println(
|
|
184
|
+
`${styleText('bold', ` • Found ${grouped.ExternalPeer.length + grouped.CleverPeer.length} Peer(s):`)}`,
|
|
185
|
+
);
|
|
189
186
|
grouped.CleverPeer?.forEach((item) => printPeer(item, format));
|
|
190
187
|
grouped.ExternalPeer?.forEach((item) => printPeer(item, format));
|
|
191
188
|
}
|