clever-tools 3.14.0 → 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.
Files changed (93) hide show
  1. package/README.md +130 -37
  2. package/bin/clever.js +1427 -718
  3. package/package.json +61 -77
  4. package/src/clever-client/auth-bridge.js +9 -12
  5. package/src/clever-client/ng.js +1 -1
  6. package/src/clever-client/operators.js +7 -7
  7. package/src/command-options.js +6 -6
  8. package/src/command-promise-handler.js +6 -6
  9. package/src/commands/accesslogs.js +38 -29
  10. package/src/commands/activity.js +62 -40
  11. package/src/commands/addon.js +65 -69
  12. package/src/commands/applications.js +33 -31
  13. package/src/commands/cancel-deploy.js +7 -7
  14. package/src/commands/config.js +9 -7
  15. package/src/commands/console.js +3 -3
  16. package/src/commands/create.js +32 -31
  17. package/src/commands/curl.js +14 -36
  18. package/src/commands/database.js +10 -30
  19. package/src/commands/delete.js +8 -8
  20. package/src/commands/deploy.js +60 -46
  21. package/src/commands/diag.js +27 -25
  22. package/src/commands/domain.js +89 -91
  23. package/src/commands/drain.js +26 -14
  24. package/src/commands/emails.js +24 -28
  25. package/src/commands/env.js +18 -18
  26. package/src/commands/features.js +12 -18
  27. package/src/commands/keycloak.js +11 -11
  28. package/src/commands/kv.js +13 -13
  29. package/src/commands/link.js +9 -8
  30. package/src/commands/login.js +19 -27
  31. package/src/commands/logout.js +1 -1
  32. package/src/commands/logs.js +20 -12
  33. package/src/commands/makeDefault.js +5 -5
  34. package/src/commands/matomo.js +7 -7
  35. package/src/commands/metabase.js +9 -9
  36. package/src/commands/ng.js +32 -32
  37. package/src/commands/notify-email.js +11 -15
  38. package/src/commands/open.js +1 -1
  39. package/src/commands/otoroshi.js +11 -11
  40. package/src/commands/profile.js +8 -8
  41. package/src/commands/published-config.js +11 -11
  42. package/src/commands/restart.js +15 -8
  43. package/src/commands/scale.js +25 -16
  44. package/src/commands/service.js +18 -9
  45. package/src/commands/ssh-keys.js +25 -29
  46. package/src/commands/ssh.js +1 -2
  47. package/src/commands/status.js +31 -22
  48. package/src/commands/stop.js +3 -3
  49. package/src/commands/tcp-redirs.js +27 -26
  50. package/src/commands/tokens.js +44 -43
  51. package/src/commands/unlink.js +7 -5
  52. package/src/commands/version.js +2 -4
  53. package/src/commands/webhooks.js +8 -10
  54. package/src/experimental-features.js +7 -5
  55. package/src/format-table.js +46 -15
  56. package/src/initial-setup.js +2 -32
  57. package/src/initial-update-notifier.js +18 -0
  58. package/src/lib/has-param.js +16 -0
  59. package/src/lib/ng-print.js +21 -24
  60. package/src/lib/operator-commands.js +58 -53
  61. package/src/lib/prompts.js +5 -5
  62. package/src/lib/slugify.js +1 -1
  63. package/src/logger.js +24 -22
  64. package/src/models/activity.js +3 -3
  65. package/src/models/addon.js +52 -53
  66. package/src/models/app_configuration.js +34 -32
  67. package/src/models/application.js +90 -77
  68. package/src/models/application_configuration.js +19 -27
  69. package/src/models/configuration.js +30 -32
  70. package/src/models/deployments.js +9 -19
  71. package/src/models/domain.js +10 -9
  72. package/src/models/drain.js +16 -15
  73. package/src/models/exit-strategy-option.js +15 -5
  74. package/src/models/fs-utils.js +4 -3
  75. package/src/models/git.js +26 -32
  76. package/src/models/ids-resolver.js +37 -41
  77. package/src/models/isomorphic-http-with-agent.js +3 -3
  78. package/src/models/json-array.js +5 -6
  79. package/src/models/log-v4.js +44 -52
  80. package/src/models/log.js +40 -45
  81. package/src/models/namespaces.js +4 -4
  82. package/src/models/ng-resources.js +49 -39
  83. package/src/models/ng.js +41 -40
  84. package/src/models/node-dns-resolver.js +3 -3
  85. package/src/models/notification.js +7 -10
  86. package/src/models/operator.js +8 -10
  87. package/src/models/organisation.js +5 -8
  88. package/src/models/send-to-api.js +18 -11
  89. package/src/models/user.js +6 -5
  90. package/src/models/utils.js +5 -8
  91. package/src/models/variables.js +18 -20
  92. package/src/parsers.js +34 -34
  93. package/src/load-package-json.cjs +0 -5
@@ -1,13 +1,13 @@
1
- import { getHostAndTokens, processError } from './send-to-api.js';
2
- import colors from 'colors/safe.js';
3
- import { Deferred } from './utils.js';
1
+ import { ApplicationLogStream } from '@clevercloud/client/esm/streams/application-logs.js';
2
+ import { styleText } from 'node:util';
4
3
  import { Logger } from '../logger.js';
4
+ import { conf } from './configuration.js';
5
5
  import { waitForDeploymentEnd, waitForDeploymentStart } from './deployments.js';
6
- import { ApplicationLogStream } from '@clevercloud/client/esm/streams/application-logs.js';
7
- import { JsonArray } from './json-array.js';
8
- import * as ExitStrategy from '../models/exit-strategy-option.js';
9
6
  import { getBest } from './domain.js';
10
- import { conf } from './configuration.js';
7
+ import * as ExitStrategy from './exit-strategy-option.js';
8
+ import { JsonArray } from './json-array.js';
9
+ import { getHostAndTokens, processError } from './send-to-api.js';
10
+ import { Deferred } from './utils.js';
11
11
 
12
12
  const RESET_COLOR = '\x1B[0m';
13
13
 
@@ -20,8 +20,7 @@ const retryConfiguration = {
20
20
  maxRetryCount: 6,
21
21
  };
22
22
 
23
- export async function displayLogs (params) {
24
-
23
+ export async function displayLogs(params) {
25
24
  const deferred = params.deferred || new Deferred();
26
25
  const { apiHost, tokens } = await getHostAndTokens();
27
26
  const { ownerId, appId, filter, since, until, deploymentId, format } = params;
@@ -50,14 +49,14 @@ export async function displayLogs (params) {
50
49
  const jsonArray = new JsonArray();
51
50
 
52
51
  logStream
53
- .on('open', (event) => {
54
- Logger.debug(colors.blue(`Logs stream (open) ${JSON.stringify({ appId, filter, deploymentId })}`));
52
+ .on('open', () => {
53
+ Logger.debug(styleText('blue', `Logs stream (open) ${JSON.stringify({ appId, filter, deploymentId })}`));
55
54
  if (format === 'json') {
56
55
  jsonArray.open();
57
56
  }
58
57
  })
59
58
  .on('error', (event) => {
60
- Logger.debug(colors.red(`Logs stream (error) ${event.error.message}`));
59
+ Logger.debug(styleText('red', `Logs stream (error) ${event.error.message}`));
61
60
  })
62
61
  .onLog((log) => {
63
62
  switch (format) {
@@ -69,14 +68,17 @@ export async function displayLogs (params) {
69
68
  return;
70
69
  case 'human':
71
70
  default:
72
- if (log.message === RESET_COLOR) return;
71
+ if (log.message === RESET_COLOR) {
72
+ return;
73
+ }
73
74
  Logger.println(formatLogLine(log));
74
75
  }
75
76
  });
76
77
 
77
78
  // start() is blocking until end of stream
78
- logStream.start()
79
- .then((reason) => {
79
+ logStream
80
+ .start()
81
+ .then(() => {
80
82
  if (format === 'json') {
81
83
  jsonArray.close();
82
84
  }
@@ -88,26 +90,16 @@ export async function displayLogs (params) {
88
90
  return logStream;
89
91
  }
90
92
 
91
- export async function watchDeploymentAndDisplayLogs (options) {
92
-
93
- const {
94
- ownerId,
95
- appId,
96
- deploymentId,
97
- commitId,
98
- knownDeployments,
99
- quiet,
100
- redeployDate,
101
- exitStrategy,
102
- } = options;
93
+ export async function watchDeploymentAndDisplayLogs(options) {
94
+ const { ownerId, appId, deploymentId, commitId, knownDeployments, quiet, redeployDate, exitStrategy } = options;
103
95
 
104
96
  ExitStrategy.plotQuietWarning(exitStrategy, quiet);
105
97
  // If in quiet mode, we only log start/finished deployment messages
106
98
  if (!quiet) {
107
- Logger.println(` ${colors.blue('→ Waiting for deployment to start…')}`);
99
+ Logger.println(` ${styleText('blue', '→ Waiting for deployment to start…')}`);
108
100
  }
109
101
  const deployment = await waitForDeploymentStart({ ownerId, appId, deploymentId, commitId, knownDeployments });
110
- Logger.println(` ${colors.green(`✓ Deployment started ${colors.grey(`(${deployment.uuid})`)}`)}`);
102
+ Logger.println(` ${styleText('green', `✓ Deployment started ${styleText('grey', `(${deployment.uuid})`)}`)}`);
111
103
 
112
104
  if (exitStrategy === 'deploy-start') {
113
105
  return;
@@ -127,7 +119,7 @@ export async function watchDeploymentAndDisplayLogs (options) {
127
119
  }
128
120
 
129
121
  if (!quiet) {
130
- Logger.println(` ${colors.blue('→ Waiting for application logs…')}`);
122
+ Logger.println(` ${styleText('blue', '→ Waiting for application logs…')}`);
131
123
  }
132
124
 
133
125
  // Wait for deployment end (or an error thrown by logs with the deferred)
@@ -143,43 +135,43 @@ export async function watchDeploymentAndDisplayLogs (options) {
143
135
  if (deploymentEnded.state === 'OK') {
144
136
  const favouriteDomain = await getBest(appId, ownerId);
145
137
  Logger.println('');
146
- Logger.println(`${colors.bold.green('✓ Access your application:')} ${colors.underline.bold(`https://${favouriteDomain.fqdn}`)}`);
147
- Logger.println(`${colors.bold.blue('→ Manage your application:')} ${colors.underline.bold(`${conf.GOTO_URL}/${appId}`)}`);
148
- }
149
- else if (deploymentEnded.state === 'CANCELLED') {
138
+ Logger.println(
139
+ `${styleText(['bold', 'green'], '✓ Access your application:')} ${styleText(['underline', 'bold'], `https://${favouriteDomain.fqdn}`)}`,
140
+ );
141
+ Logger.println(
142
+ `${styleText(['bold', 'blue'], '→ Manage your application:')} ${styleText(['underline', 'bold'], `${conf.GOTO_URL}/${appId}`)}`,
143
+ );
144
+ } else if (deploymentEnded.state === 'CANCELLED') {
150
145
  throw new Error('Deployment was cancelled. Please check the activity');
151
- }
152
- else {
146
+ } else {
153
147
  throw new Error('Deployment failed. Please check the logs');
154
148
  }
155
149
  }
156
150
 
157
- function formatLogLine (log) {
151
+ function formatLogLine(log) {
158
152
  const { date, message } = log;
159
153
  if (isDeploymentSuccessMessage(log)) {
160
- return `${date.toISOString()}: ${colors.bold.green(message)}`;
161
- }
162
- else if (isDeploymentFailedMessage(log)) {
163
- return `${date.toISOString()}: ${colors.bold.red(message)}`;
164
- }
165
- else if (isBuildSucessMessage(log)) {
166
- return `${date.toISOString()}: ${colors.bold.blue(message)}`;
154
+ return `${date.toISOString()}: ${styleText(['bold', 'green'], message)}`;
155
+ } else if (isDeploymentFailedMessage(log)) {
156
+ return `${date.toISOString()}: ${styleText(['bold', 'red'], message)}`;
157
+ } else if (isBuildSucessMessage(log)) {
158
+ return `${date.toISOString()}: ${styleText(['bold', 'blue'], message)}`;
167
159
  }
168
160
  return `${date.toISOString()}: ${message}${RESET_COLOR}`;
169
161
  }
170
162
 
171
- function isCleverMessage (log) {
163
+ function isCleverMessage(log) {
172
164
  return log.service !== 'bas-deploy.service';
173
- };
165
+ }
174
166
 
175
- function isDeploymentSuccessMessage (log) {
167
+ function isDeploymentSuccessMessage(log) {
176
168
  return isCleverMessage(log) && log.message.toLowerCase().startsWith('successfully deployed in');
177
- };
169
+ }
178
170
 
179
- function isDeploymentFailedMessage (log) {
171
+ function isDeploymentFailedMessage(log) {
180
172
  return isCleverMessage(log) && log.message.toLowerCase().startsWith('deploy failed in');
181
- };
173
+ }
182
174
 
183
- function isBuildSucessMessage (log) {
175
+ function isBuildSucessMessage(log) {
184
176
  return isCleverMessage(log) && log.message.toLowerCase().startsWith('build succeeded in');
185
- };
177
+ }
package/src/models/log.js CHANGED
@@ -1,49 +1,42 @@
1
- import _ from 'lodash';
2
- import colors from 'colors/safe.js';
3
-
4
- import { Logger } from '../logger.js';
5
- import { Deferred } from './utils.js';
6
1
  import { getOldLogs } from '@clevercloud/client/esm/api/v2/log.js';
7
2
  import { LogsStream } from '@clevercloud/client/esm/streams/logs.node.js';
8
- import { sendToApi, getHostAndTokens } from './send-to-api.js';
3
+ import _ from 'lodash';
4
+ import { styleText } from 'node:util';
5
+ import { Logger } from '../logger.js';
9
6
  import { waitForDeploymentEnd, waitForDeploymentStart } from './deployments.js';
10
- import * as ExitStrategy from '../models/exit-strategy-option.js';
7
+ import * as ExitStrategy from './exit-strategy-option.js';
8
+ import { getHostAndTokens, sendToApi } from './send-to-api.js';
9
+ import { Deferred } from './utils.js';
11
10
 
12
- function isCleverMessage (line) {
11
+ function isCleverMessage(line) {
13
12
  return line._source.syslog_program === '/home/bas/rubydeployer/deployer.rb';
14
- };
13
+ }
15
14
 
16
- function isDeploymentSuccessMessage (line) {
17
- return isCleverMessage(line)
18
- && _.startsWith(line._source['@message'].toLowerCase(), 'successfully deployed in');
19
- };
15
+ function isDeploymentSuccessMessage(line) {
16
+ return isCleverMessage(line) && _.startsWith(line._source['@message'].toLowerCase(), 'successfully deployed in');
17
+ }
20
18
 
21
- function isDeploymentFailedMessage (line) {
22
- return isCleverMessage(line)
23
- && _.startsWith(line._source['@message'].toLowerCase(), 'deploy failed in');
24
- };
19
+ function isDeploymentFailedMessage(line) {
20
+ return isCleverMessage(line) && _.startsWith(line._source['@message'].toLowerCase(), 'deploy failed in');
21
+ }
25
22
 
26
- function isBuildSucessMessage (line) {
27
- return isCleverMessage(line)
28
- && _.startsWith(line._source['@message'].toLowerCase(), 'build succeeded in');
29
- };
23
+ function isBuildSucessMessage(line) {
24
+ return isCleverMessage(line) && _.startsWith(line._source['@message'].toLowerCase(), 'build succeeded in');
25
+ }
30
26
 
31
- function formatLogLine (line) {
27
+ function formatLogLine(line) {
32
28
  const { '@timestamp': timestamp, '@message': message } = line._source;
33
29
  if (isDeploymentSuccessMessage(line)) {
34
- return `${timestamp}: ${colors.bold.green(message)}`;
35
- }
36
- else if (isDeploymentFailedMessage(line)) {
37
- return `${timestamp}: ${colors.bold.red(message)}`;
38
- }
39
- else if (isBuildSucessMessage(line)) {
40
- return `${timestamp}: ${colors.bold.blue(message)}`;
30
+ return `${timestamp}: ${styleText(['bold', 'green'], message)}`;
31
+ } else if (isDeploymentFailedMessage(line)) {
32
+ return `${timestamp}: ${styleText(['bold', 'red'], message)}`;
33
+ } else if (isBuildSucessMessage(line)) {
34
+ return `${timestamp}: ${styleText(['bold', 'blue'], message)}`;
41
35
  }
42
36
  return `${timestamp}: ${message}`;
43
37
  }
44
38
 
45
- async function displayLiveLogs ({ appId, filter, until, deploymentId }, deferred) {
46
-
39
+ async function displayLiveLogs({ appId, filter, until, deploymentId }, deferred) {
47
40
  const { apiHost, tokens } = await getHostAndTokens();
48
41
  const logsStream = new LogsStream({ apiHost, tokens, appId, filter, deploymentId });
49
42
 
@@ -53,8 +46,7 @@ async function displayLiveLogs ({ appId, filter, until, deploymentId }, deferred
53
46
  const { '@timestamp': timestamp } = line._source;
54
47
  if (until != null && new Date(timestamp) > until) {
55
48
  logsStream.close();
56
- }
57
- else {
49
+ } else {
58
50
  Logger.println(formatLogLine(line));
59
51
  }
60
52
  })
@@ -67,13 +59,11 @@ async function displayLiveLogs ({ appId, filter, until, deploymentId }, deferred
67
59
  return logsStream;
68
60
  }
69
61
 
70
- export async function displayLogs ({ appAddonId, until, since, filter, deploymentId }) {
71
-
62
+ export async function displayLogs({ appAddonId, until, since, filter, deploymentId }) {
72
63
  const now = new Date();
73
64
 
74
- const fetchOldLogs = (since == null || since < now);
65
+ const fetchOldLogs = since == null || since < now;
75
66
  if (fetchOldLogs) {
76
-
77
67
  const oldLogs = await getOldLogs({
78
68
  appId: appAddonId,
79
69
  before: until != null ? until.toISOString() : null,
@@ -99,13 +89,20 @@ export async function displayLogs ({ appAddonId, until, since, filter, deploymen
99
89
  return deferred.promise;
100
90
  }
101
91
 
102
- export async function watchDeploymentAndDisplayLogs ({ ownerId, appId, deploymentId, commitId, knownDeployments, quiet, exitStrategy }) {
103
-
92
+ export async function watchDeploymentAndDisplayLogs({
93
+ ownerId,
94
+ appId,
95
+ deploymentId,
96
+ commitId,
97
+ knownDeployments,
98
+ quiet,
99
+ exitStrategy,
100
+ }) {
104
101
  ExitStrategy.plotQuietWarning(exitStrategy, quiet);
105
102
  // If in quiet mode, we only log start/finished deployment messages
106
103
  Logger.println('Waiting for deployment to start…');
107
104
  const deployment = await waitForDeploymentStart({ ownerId, appId, deploymentId, commitId, knownDeployments });
108
- Logger.println(colors.bold.blue(`Deployment started (${deployment.uuid})`));
105
+ Logger.println(styleText(['bold', 'blue'], `Deployment started (${deployment.uuid})`));
109
106
 
110
107
  if (exitStrategy === 'deploy-start') {
111
108
  return;
@@ -137,12 +134,10 @@ export async function watchDeploymentAndDisplayLogs ({ ownerId, appId, deploymen
137
134
  }
138
135
 
139
136
  if (deploymentEnded.state === 'OK') {
140
- Logger.println(colors.bold.green('Deployment successful'));
141
- }
142
- else if (deploymentEnded.state === 'CANCELLED') {
137
+ Logger.println(styleText(['bold', 'green'], 'Deployment successful'));
138
+ } else if (deploymentEnded.state === 'CANCELLED') {
143
139
  throw new Error('Deployment was cancelled. Please check the activity');
144
- }
145
- else {
140
+ } else {
146
141
  throw new Error('Deployment failed. Please check the logs');
147
142
  }
148
143
  }
@@ -1,13 +1,13 @@
1
- import * as Application from './application.js';
2
1
  import { getNamespaces as getTcpRedirNamespaces } from '@clevercloud/client/esm/api/v2/organisation.js';
3
- import { sendToApi } from './send-to-api.js';
4
2
  import cliparse from 'cliparse';
3
+ import * as Application from './application.js';
4
+ import { sendToApi } from './send-to-api.js';
5
5
 
6
- export async function getNamespaces (ownerId) {
6
+ export async function getNamespaces(ownerId) {
7
7
  return getTcpRedirNamespaces({ id: ownerId }).then(sendToApi);
8
8
  }
9
9
 
10
- export async function completeNamespaces () {
10
+ export async function completeNamespaces() {
11
11
  // Sadly we do not have access to current params in complete as of now
12
12
  const { ownerId } = await Application.resolveId(null, null);
13
13
 
@@ -1,12 +1,11 @@
1
- import colors from 'colors/safe.js';
2
- import * as networkGroup from './ng.js';
1
+ import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
3
2
  import * as networkGroupApi from '@clevercloud/client/esm/api/v4/network-group.js';
4
-
5
3
  import crypto from 'node:crypto';
6
4
  import { setTimeout } from 'node:timers/promises';
5
+ import { styleText } from 'node:util';
7
6
  import { Logger } from '../logger.js';
7
+ import * as networkGroup from './ng.js';
8
8
  import { sendToApi } from './send-to-api.js';
9
- import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
10
9
 
11
10
  /**
12
11
  * Create an external peer and link its parent member to the Network Group
@@ -19,8 +18,7 @@ import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
19
18
  * @throws {Error} If the parent member is not linked to the Network Group
20
19
  * @throws {Error} If the external peer is not linked to the Network Group
21
20
  */
22
- export async function createExternalPeerWithParent (ngIdOrLabel, peerLabel, publicKey, org) {
23
-
21
+ export async function createExternalPeerWithParent(ngIdOrLabel, peerLabel, publicKey, org) {
24
22
  if (!peerLabel) {
25
23
  throw new Error('A valid peer label is required');
26
24
  }
@@ -28,7 +26,7 @@ export async function createExternalPeerWithParent (ngIdOrLabel, peerLabel, publ
28
26
  const [ng] = await networkGroup.searchNgOrResource(ngIdOrLabel, org, 'NetworkGroup');
29
27
 
30
28
  if (!ng) {
31
- throw new Error(`Network Group ${colors.red(ngIdOrLabel.ngId || ngIdOrLabel.ngResourceLabel)} not found`);
29
+ throw new Error(`Network Group ${styleText('red', ngIdOrLabel.ngId || ngIdOrLabel.ngResourceLabel)} not found`);
32
30
  }
33
31
 
34
32
  // We define a parent member for the external peer
@@ -45,7 +43,9 @@ export async function createExternalPeerWithParent (ngIdOrLabel, peerLabel, publ
45
43
 
46
44
  const checkParentMember = await checkResource(ng.id, org, parentMember.id, true);
47
45
  if (!checkParentMember) {
48
- throw new Error(`Parent member ${colors.red(parentMember.id)} not linked to Network Group ${colors.red(ng.id)}`);
46
+ throw new Error(
47
+ `Parent member ${styleText('red', parentMember.id)} not linked to Network Group ${styleText('red', ng.id)}`,
48
+ );
49
49
  }
50
50
 
51
51
  Logger.info(`Parent member ${parentMember.id} created and linked to Network Group ${ng.id}`);
@@ -60,11 +60,15 @@ export async function createExternalPeerWithParent (ngIdOrLabel, peerLabel, publ
60
60
 
61
61
  Logger.info(`Adding external peer to Member ${parentMember.id} of Network Group ${ng.id}`);
62
62
  Logger.debug('Sending body: ' + JSON.stringify(body, null, 2));
63
- await networkGroupApi.createNetworkGroupExternalPeer({ ownerId: ng.ownerId, networkGroupId: ng.id }, body).then(sendToApi);
63
+ await networkGroupApi
64
+ .createNetworkGroupExternalPeer({ ownerId: ng.ownerId, networkGroupId: ng.id }, body)
65
+ .then(sendToApi);
64
66
 
65
67
  const checkExternalPeer = await checkResource(ng.id, org, peerLabel, true, 'peer', 'label');
66
68
  if (!checkExternalPeer) {
67
- throw new Error(`External peer ${colors.red(peerLabel)} not linked to Network Group ${colors.red(ng.id)}`);
69
+ throw new Error(
70
+ `External peer ${styleText('red', peerLabel)} not linked to Network Group ${styleText('red', ng.id)}`,
71
+ );
68
72
  }
69
73
 
70
74
  Logger.info(`External peer ${peerLabel} added to Member ${parentMember.id} of Network Group ${ng.id}`);
@@ -80,12 +84,11 @@ export async function createExternalPeerWithParent (ngIdOrLabel, peerLabel, publ
80
84
  * @throws {Error} If the External Peer is still linked to the Network Group
81
85
  * @throws {Error} If the Parent Member is still linked to the Network Group
82
86
  */
83
- export async function deleteExternalPeerWithParent (ngIdOrLabel, peerIdOrLabel, org) {
84
-
87
+ export async function deleteExternalPeerWithParent(ngIdOrLabel, peerIdOrLabel, org) {
85
88
  const [ng] = await networkGroup.searchNgOrResource(ngIdOrLabel, org, 'NetworkGroup');
86
89
 
87
90
  if (!ng) {
88
- throw new Error(`Network Group ${colors.red(ngIdOrLabel.ngId || ngIdOrLabel.ngResourceLabel)} not found`);
91
+ throw new Error(`Network Group ${styleText('red', ngIdOrLabel.ngId || ngIdOrLabel.ngResourceLabel)} not found`);
89
92
  }
90
93
 
91
94
  const externalPeer = ng.peers.find((p) => {
@@ -93,15 +96,19 @@ export async function deleteExternalPeerWithParent (ngIdOrLabel, peerIdOrLabel,
93
96
  });
94
97
 
95
98
  if (!externalPeer) {
96
- throw new Error(`External peer ${colors.red(peerIdOrLabel)} not found`);
99
+ throw new Error(`External peer ${styleText('red', peerIdOrLabel)} not found`);
97
100
  }
98
101
 
99
102
  Logger.info(`Deleting external peer ${externalPeer.id} from Network Group ${ng.id}`);
100
- await networkGroupApi.deleteNetworkGroupExternalPeer({ ownerId: ng.ownerId, networkGroupId: ng.id, peerId: externalPeer.id }).then(sendToApi);
103
+ await networkGroupApi
104
+ .deleteNetworkGroupExternalPeer({ ownerId: ng.ownerId, networkGroupId: ng.id, peerId: externalPeer.id })
105
+ .then(sendToApi);
101
106
 
102
107
  const checkPeer = await checkResource(ng.id, org, externalPeer.id, false, 'peer');
103
108
  if (!checkPeer) {
104
- throw new Error(`External peer ${colors.red(externalPeer.id)} still linked to Network Group ${colors.red(ng.id)}`);
109
+ throw new Error(
110
+ `External peer ${styleText('red', externalPeer.id)} still linked to Network Group ${styleText('red', ng.id)}`,
111
+ );
105
112
  }
106
113
 
107
114
  Logger.info(`External peer ${externalPeer.id} deleted from Network Group ${ng.id}`);
@@ -111,7 +118,9 @@ export async function deleteExternalPeerWithParent (ngIdOrLabel, peerIdOrLabel,
111
118
 
112
119
  const checkParentMember = await checkResource(ng.id, org, externalPeer.parentMember, false);
113
120
  if (!checkParentMember) {
114
- throw new Error(`Parent member ${colors.red(externalPeer.parentMember)} still linked to Network Group ${colors.red(ng.id)}`);
121
+ throw new Error(
122
+ `Parent member ${styleText('red', externalPeer.parentMember)} still linked to Network Group ${styleText('red', ng.id)}`,
123
+ );
115
124
  }
116
125
 
117
126
  Logger.info(`Parent member ${externalPeer.parentMember} unlinked from Network Group ${ng.id}`);
@@ -124,7 +133,7 @@ export async function deleteExternalPeerWithParent (ngIdOrLabel, peerIdOrLabel,
124
133
  * @param {object} org Organisation ID or name
125
134
  * @param {string} label Label of the Member
126
135
  */
127
- export async function linkMember (ngIdOrLabel, memberId, org, label) {
136
+ export async function linkMember(ngIdOrLabel, memberId, org, label) {
128
137
  if (!memberId) {
129
138
  throw new Error('A valid member ID is required (addon_xxx, app_xxx, external_xxx)');
130
139
  }
@@ -132,14 +141,16 @@ export async function linkMember (ngIdOrLabel, memberId, org, label) {
132
141
  const [ng] = await networkGroup.searchNgOrResource(ngIdOrLabel, org, 'NetworkGroup');
133
142
 
134
143
  if (!ng) {
135
- throw new Error(`Network Group ${colors.red(ngIdOrLabel.ngId || ngIdOrLabel.ngResourceLabel)} not found`);
144
+ throw new Error(`Network Group ${styleText('red', ngIdOrLabel.ngId || ngIdOrLabel.ngResourceLabel)} not found`);
136
145
  }
137
146
 
138
147
  await checkMembersToLink([memberId], ng.ownerId);
139
148
 
140
149
  const alreadyMember = ng.members.find((m) => m.id === memberId);
141
150
  if (alreadyMember) {
142
- throw new Error(`Member ${colors.red(memberId)} is already linked to Network Group ${colors.red(ng.id)}`);
151
+ throw new Error(
152
+ `Member ${styleText('red', memberId)} is already linked to Network Group ${styleText('red', ng.id)}`,
153
+ );
143
154
  }
144
155
 
145
156
  const [member] = networkGroup.constructMembers(ng.id, [memberId]);
@@ -157,7 +168,7 @@ export async function linkMember (ngIdOrLabel, memberId, org, label) {
157
168
 
158
169
  const check = await checkResource(ng.id, org, member.id, true);
159
170
  if (!check) {
160
- throw new Error(`Member ${colors.red(member.id)} not linked to Network Group ${colors.red(ng.id)}`);
171
+ throw new Error(`Member ${styleText('red', member.id)} not linked to Network Group ${styleText('red', ng.id)}`);
161
172
  }
162
173
 
163
174
  Logger.info(`Member ${member.id} linked to Network Group ${ng.id}`);
@@ -173,7 +184,7 @@ export async function linkMember (ngIdOrLabel, memberId, org, label) {
173
184
  * @throws {Error} If the Member is not found in the Network Group
174
185
  * @throws {Error} If the Member is still linked to the Network Group
175
186
  */
176
- export async function unlinkMember (ngIdOrLabel, memberId, org) {
187
+ export async function unlinkMember(ngIdOrLabel, memberId, org) {
177
188
  if (!memberId) {
178
189
  throw new Error('A valid member ID is required (addon_xxx, app_xxx, external_xxx)');
179
190
  }
@@ -181,20 +192,22 @@ export async function unlinkMember (ngIdOrLabel, memberId, org) {
181
192
  const [ng] = await networkGroup.searchNgOrResource(ngIdOrLabel, org, 'NetworkGroup');
182
193
 
183
194
  if (!ng) {
184
- throw new Error(`Network Group ${colors.red(ngIdOrLabel.ngId || ngIdOrLabel.ngLabel)} not found`);
195
+ throw new Error(`Network Group ${styleText('red', ngIdOrLabel.ngId || ngIdOrLabel.ngLabel)} not found`);
185
196
  }
186
197
 
187
198
  const member = ng.members.find((m) => m.id === memberId);
188
199
  if (!member) {
189
- throw new Error(`Member ${colors.red(memberId)} not found in Network Group ${colors.red(ng.id)}`);
200
+ throw new Error(`Member ${styleText('red', memberId)} not found in Network Group ${styleText('red', ng.id)}`);
190
201
  }
191
202
 
192
203
  Logger.info(`Unlinking member ${memberId} from Network Group ${ng.id}`);
193
- await networkGroupApi.deleteNetworkGroupMember({ ownerId: ng.ownerId, networkGroupId: ng.id, memberId }).then(sendToApi);
204
+ await networkGroupApi
205
+ .deleteNetworkGroupMember({ ownerId: ng.ownerId, networkGroupId: ng.id, memberId })
206
+ .then(sendToApi);
194
207
 
195
208
  const check = await checkResource(ng.id, org, memberId, false);
196
209
  if (!check) {
197
- throw new Error(`Member ${colors.red(memberId)} still linked to Network Group ${colors.red(ng.id)}`);
210
+ throw new Error(`Member ${styleText('red', memberId)} still linked to Network Group ${styleText('red', ng.id)}`);
198
211
  }
199
212
 
200
213
  Logger.info(`Member ${memberId} unlinked from Network Group ${ng.id}`);
@@ -205,14 +218,8 @@ export async function unlinkMember (ngIdOrLabel, memberId, org) {
205
218
  * @param {Array<string>} members Members to check
206
219
  * @throws {Error} If members can't be linked to a Network Group
207
220
  */
208
- export async function checkMembersToLink (members, ownerId) {
209
- const VALID_ADDON_PROVIDERS = [
210
- 'es-addon',
211
- 'mongodb-addon',
212
- 'mysql-addon',
213
- 'postgresql-addon',
214
- 'redis-addon',
215
- ];
221
+ export async function checkMembersToLink(members, ownerId) {
222
+ const VALID_ADDON_PROVIDERS = ['es-addon', 'mongodb-addon', 'mysql-addon', 'postgresql-addon', 'redis-addon'];
216
223
 
217
224
  const summary = await getSummary().then(sendToApi);
218
225
 
@@ -225,20 +232,23 @@ export async function checkMembersToLink (members, ownerId) {
225
232
  let source = data.applications;
226
233
 
227
234
  for (const memberId of members) {
228
- if (memberId.startsWith('addon_')) source = data.addons;
235
+ if (memberId.startsWith('addon_')) {
236
+ source = data.addons;
237
+ }
229
238
 
230
239
  const foundRessource = source.find((r) => r.id === memberId);
231
240
 
232
241
  if (foundRessource && memberId.startsWith('addon_') && !VALID_ADDON_PROVIDERS.includes(foundRessource.providerId)) {
233
242
  membersNotOK.push(memberId);
234
- }
235
- else if (!foundRessource && !memberId.startsWith('external_')) {
243
+ } else if (!foundRessource && !memberId.startsWith('external_')) {
236
244
  membersNotOK.push(memberId);
237
245
  }
238
246
  }
239
247
 
240
248
  if (membersNotOK.length > 0) {
241
- throw new Error(`Member(s) ${colors.red(membersNotOK.join(', '))} can't be linked to the Network Group, check Organisation ID or name`);
249
+ throw new Error(
250
+ `Member(s) ${styleText('red', membersNotOK.join(', '))} can't be linked to the Network Group, check Organisation ID or name`,
251
+ );
242
252
  }
243
253
  }
244
254
 
@@ -252,7 +262,7 @@ export async function checkMembersToLink (members, ownerId) {
252
262
  * @param {string} [searchBy] Search by 'id' or 'label', default is 'id'
253
263
  * @returns {Promise<boolean>} True if the resource is present, false otherwise
254
264
  */
255
- async function checkResource (ngId, org, resource, shouldBePresent, resourceType = 'member', searchBy = 'id') {
265
+ async function checkResource(ngId, org, resource, shouldBePresent, resourceType = 'member', searchBy = 'id') {
256
266
  const endTime = Date.now() + networkGroup.POLLING_TIMEOUT_MS;
257
267
 
258
268
  while (Date.now() < endTime) {