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.
- package/README.md +130 -37
- package/bin/clever.js +1427 -718
- package/package.json +61 -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 +32 -31
- 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 +18 -9
- 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 +24 -22
- package/src/models/activity.js +3 -3
- package/src/models/addon.js +52 -53
- 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/emails.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import colors from 'colors/safe.js';
|
|
2
|
-
import * as User from '../models/user.js';
|
|
3
|
-
import { Logger } from '../logger.js';
|
|
4
|
-
import { openBrowser } from '../models/utils.js';
|
|
5
|
-
import { sendToApi } from '../models/send-to-api.js';
|
|
6
|
-
import { confirm } from '../lib/prompts.js';
|
|
7
1
|
import {
|
|
8
2
|
todo_addEmailAddress as addEmailAddress,
|
|
9
3
|
todo_getEmailAddresses as getEmailAddresses,
|
|
10
4
|
todo_removeEmailAddress as removeEmailAddress,
|
|
11
5
|
} from '@clevercloud/client/esm/api/v2/user.js';
|
|
6
|
+
import { styleText } from 'node:util';
|
|
7
|
+
import { confirm } from '../lib/prompts.js';
|
|
8
|
+
import { Logger } from '../logger.js';
|
|
9
|
+
import { sendToApi } from '../models/send-to-api.js';
|
|
10
|
+
import * as User from '../models/user.js';
|
|
11
|
+
import { openBrowser } from '../models/utils.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Show primary and secondary email addresses of the current user
|
|
15
15
|
* @param {object} params The command parameters
|
|
16
16
|
* @param {string} params.options.format The output format
|
|
17
17
|
*/
|
|
18
|
-
export async function list
|
|
18
|
+
export async function list(params) {
|
|
19
19
|
const { format } = params.options;
|
|
20
20
|
const addresses = await getUserEmailAddresses();
|
|
21
21
|
|
|
@@ -27,13 +27,11 @@ export async function list (params) {
|
|
|
27
27
|
case 'human':
|
|
28
28
|
default: {
|
|
29
29
|
Logger.println('✉️ Primary email address:');
|
|
30
|
-
Logger.println(` • ${
|
|
30
|
+
Logger.println(` • ${styleText('green', addresses.primary)}`);
|
|
31
31
|
if (addresses.secondary.length > 0) {
|
|
32
32
|
Logger.println();
|
|
33
33
|
Logger.println(`✉️ ${addresses.secondary.length} secondary email address(es):`);
|
|
34
|
-
addresses.secondary.forEach((address) =>
|
|
35
|
-
Logger.println(` • ${colors.blue(address)}`),
|
|
36
|
-
);
|
|
34
|
+
addresses.secondary.forEach((address) => Logger.println(` • ${styleText('blue', address)}`));
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
37
|
}
|
|
@@ -44,15 +42,16 @@ export async function list (params) {
|
|
|
44
42
|
* @param {object} params The command parameters
|
|
45
43
|
* @param {Array<string>} params.args
|
|
46
44
|
*/
|
|
47
|
-
export async function addSecondary
|
|
45
|
+
export async function addSecondary(params) {
|
|
48
46
|
const [secondaryAddress] = params.args;
|
|
49
47
|
|
|
50
48
|
const secondaryAddressEncoded = encodeURIComponent(secondaryAddress);
|
|
51
49
|
try {
|
|
52
50
|
await addEmailAddress({ email: secondaryAddressEncoded }).then(sendToApi);
|
|
53
|
-
Logger.printSuccess(
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
Logger.printSuccess(
|
|
52
|
+
`The server sent a confirmation email to ${secondaryAddress} to validate your secondary address`,
|
|
53
|
+
);
|
|
54
|
+
} catch (e) {
|
|
56
55
|
switch (e?.responseBody?.id) {
|
|
57
56
|
case 101:
|
|
58
57
|
throw new Error('This address already belongs to your account');
|
|
@@ -71,7 +70,7 @@ export async function addSecondary (params) {
|
|
|
71
70
|
* @param {object} params The command parameters
|
|
72
71
|
* @param {Array<string>} params.args
|
|
73
72
|
*/
|
|
74
|
-
export async function setPrimary
|
|
73
|
+
export async function setPrimary(params) {
|
|
75
74
|
const [newPrimaryAddress] = params.args;
|
|
76
75
|
|
|
77
76
|
const addresses = await getUserEmailAddresses();
|
|
@@ -95,13 +94,13 @@ export async function setPrimary (params) {
|
|
|
95
94
|
* @param {object} params The command parameters
|
|
96
95
|
* @param {Array<string>} params.args
|
|
97
96
|
*/
|
|
98
|
-
export async function removeSecondary
|
|
97
|
+
export async function removeSecondary(params) {
|
|
99
98
|
const [addressToRemove] = params.args;
|
|
100
99
|
|
|
101
100
|
const addresses = await getUserEmailAddresses();
|
|
102
101
|
|
|
103
102
|
if (!addresses.secondary.includes(addressToRemove)) {
|
|
104
|
-
throw new Error(
|
|
103
|
+
throw new Error("This address is not part of the secondary addresses of the current user, it can't be removed");
|
|
105
104
|
}
|
|
106
105
|
|
|
107
106
|
const addressToRemoveEncoded = encodeURIComponent(addressToRemove);
|
|
@@ -116,12 +115,9 @@ export async function removeSecondary (params) {
|
|
|
116
115
|
* @param {object} params.options The command options
|
|
117
116
|
* @param {boolean} params.options.yes The user confirmation
|
|
118
117
|
*/
|
|
119
|
-
export async function removeAllSecondary
|
|
118
|
+
export async function removeAllSecondary(params) {
|
|
120
119
|
if (!params.options.yes) {
|
|
121
|
-
await confirm(
|
|
122
|
-
'Are you sure you want to remove all your secondary addresses?',
|
|
123
|
-
'No secondary addresses removed',
|
|
124
|
-
);
|
|
120
|
+
await confirm('Are you sure you want to remove all your secondary addresses?', 'No secondary addresses removed');
|
|
125
121
|
}
|
|
126
122
|
|
|
127
123
|
const addresses = await getUserEmailAddresses();
|
|
@@ -134,7 +130,8 @@ export async function removeAllSecondary (params) {
|
|
|
134
130
|
const results = await Promise.all(
|
|
135
131
|
addresses.secondary.map((addressToRemove) => {
|
|
136
132
|
const addressToRemoveEncoded = encodeURIComponent(addressToRemove);
|
|
137
|
-
return removeEmailAddress({ email: addressToRemoveEncoded })
|
|
133
|
+
return removeEmailAddress({ email: addressToRemoveEncoded })
|
|
134
|
+
.then(sendToApi)
|
|
138
135
|
.then(() => [true, addressToRemove])
|
|
139
136
|
.catch(() => [false, addressToRemove]);
|
|
140
137
|
}),
|
|
@@ -142,8 +139,7 @@ export async function removeAllSecondary (params) {
|
|
|
142
139
|
|
|
143
140
|
if (results.every(([isRemoved]) => isRemoved)) {
|
|
144
141
|
Logger.printSuccess('All secondary addresses were removed successfully');
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
142
|
+
} else {
|
|
147
143
|
const addressesWithErrors = results
|
|
148
144
|
.filter(([isRemoved]) => !isRemoved)
|
|
149
145
|
.map(([_, address]) => address)
|
|
@@ -156,7 +152,7 @@ export async function removeAllSecondary (params) {
|
|
|
156
152
|
* Open the email addresses management page of the Console in your browser
|
|
157
153
|
* @returns {Promise<void>} A promise that resolves when the page is opened
|
|
158
154
|
*/
|
|
159
|
-
export function openConsole
|
|
155
|
+
export function openConsole() {
|
|
160
156
|
return openBrowser('/users/me/emails', 'Opening the email addresses management page of the Console in your browser');
|
|
161
157
|
}
|
|
162
158
|
|
|
@@ -164,7 +160,7 @@ export function openConsole () {
|
|
|
164
160
|
* Get the primary and secondary email addresses of the current user
|
|
165
161
|
* @returns {Promise<{ primary: string, secondary: string[] }>} The primary and secondary email addresses of the current user
|
|
166
162
|
*/
|
|
167
|
-
async function getUserEmailAddresses
|
|
163
|
+
async function getUserEmailAddresses() {
|
|
168
164
|
const currentUser = await User.getCurrent();
|
|
169
165
|
const secondaryAddresses = await getEmailAddresses().then(sendToApi);
|
|
170
166
|
return {
|
package/src/commands/env.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import * as Application from '../models/application.js';
|
|
2
|
-
import { Logger } from '../logger.js';
|
|
3
|
-
import colors from 'colors/safe.js';
|
|
4
|
-
import * as variables from '../models/variables.js';
|
|
5
|
-
import { sendToApi } from '../models/send-to-api.js';
|
|
6
|
-
import { toNameEqualsValueString, validateName } from '@clevercloud/client/esm/utils/env-vars.js';
|
|
7
1
|
import {
|
|
8
2
|
getAllEnvVars,
|
|
9
3
|
getAllEnvVarsForAddons,
|
|
10
4
|
getAllEnvVarsForDependencies,
|
|
11
|
-
updateEnvVar,
|
|
12
|
-
updateAllEnvVars,
|
|
13
5
|
removeEnvVar,
|
|
6
|
+
updateAllEnvVars,
|
|
7
|
+
updateEnvVar,
|
|
14
8
|
} from '@clevercloud/client/esm/api/v2/application.js';
|
|
9
|
+
import { toNameEqualsValueString, validateName } from '@clevercloud/client/esm/utils/env-vars.js';
|
|
10
|
+
import { styleText } from 'node:util';
|
|
11
|
+
import { Logger } from '../logger.js';
|
|
12
|
+
import * as Application from '../models/application.js';
|
|
13
|
+
import { sendToApi } from '../models/send-to-api.js';
|
|
14
|
+
import * as variables from '../models/variables.js';
|
|
15
15
|
|
|
16
|
-
export async function list
|
|
16
|
+
export async function list(params) {
|
|
17
17
|
const { alias, app: appIdOrName, 'add-export': addExportsOption, format } = params.options;
|
|
18
18
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
19
19
|
|
|
@@ -44,7 +44,7 @@ export async function list (params) {
|
|
|
44
44
|
case 'human':
|
|
45
45
|
default: {
|
|
46
46
|
if (addExportsOption) {
|
|
47
|
-
Logger.println(
|
|
47
|
+
Logger.println(styleText('yellow', '`--add-export` option is deprecated. Use `--format shell` instead.'));
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
const addExports = addExportsOption || format === 'shell';
|
|
@@ -65,7 +65,7 @@ export async function list (params) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
export async function set
|
|
68
|
+
export async function set(params) {
|
|
69
69
|
const [envName, value] = params.args;
|
|
70
70
|
const { alias, app: appIdOrName } = params.options;
|
|
71
71
|
|
|
@@ -79,9 +79,9 @@ export async function set (params) {
|
|
|
79
79
|
await updateEnvVar({ id: ownerId, appId, envName }, { value }).then(sendToApi);
|
|
80
80
|
|
|
81
81
|
Logger.println('Your environment variable has been successfully saved');
|
|
82
|
-
}
|
|
82
|
+
}
|
|
83
83
|
|
|
84
|
-
export async function rm
|
|
84
|
+
export async function rm(params) {
|
|
85
85
|
const [envName] = params.args;
|
|
86
86
|
const { alias, app: appIdOrName } = params.options;
|
|
87
87
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
@@ -89,9 +89,9 @@ export async function rm (params) {
|
|
|
89
89
|
await removeEnvVar({ id: ownerId, appId, envName }).then(sendToApi);
|
|
90
90
|
|
|
91
91
|
Logger.println('Your environment variable has been successfully removed');
|
|
92
|
-
}
|
|
92
|
+
}
|
|
93
93
|
|
|
94
|
-
export async function importEnv
|
|
94
|
+
export async function importEnv(params) {
|
|
95
95
|
const { alias, app: appIdOrName, json } = params.options;
|
|
96
96
|
const format = json ? 'json' : 'name-equals-value';
|
|
97
97
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
@@ -100,9 +100,9 @@ export async function importEnv (params) {
|
|
|
100
100
|
await updateAllEnvVars({ id: ownerId, appId }, envVars).then(sendToApi);
|
|
101
101
|
|
|
102
102
|
Logger.println('Environment variables have been set');
|
|
103
|
-
}
|
|
103
|
+
}
|
|
104
104
|
|
|
105
|
-
export async function importVarsFromLocalEnv
|
|
105
|
+
export async function importVarsFromLocalEnv(params) {
|
|
106
106
|
const [envNames] = params.args;
|
|
107
107
|
const { alias, app: appIdOrName } = params.options;
|
|
108
108
|
|
|
@@ -121,4 +121,4 @@ export async function importVarsFromLocalEnv (params) {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
Logger.println('Your environment variables have been successfully saved');
|
|
124
|
-
}
|
|
124
|
+
}
|
package/src/commands/features.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { getFeatures, setFeature } from '../models/configuration.js';
|
|
2
1
|
import { EXPERIMENTAL_FEATURES } from '../experimental-features.js';
|
|
3
|
-
import { formatTable
|
|
2
|
+
import { formatTable } from '../format-table.js';
|
|
4
3
|
import { Logger } from '../logger.js';
|
|
4
|
+
import { getFeatures, setFeature } from '../models/configuration.js';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export async function list (params) {
|
|
6
|
+
export async function list(params) {
|
|
9
7
|
const { format } = params.options;
|
|
10
8
|
|
|
11
9
|
const featuresConf = await getFeatures();
|
|
@@ -30,20 +28,17 @@ export async function list (params) {
|
|
|
30
28
|
default: {
|
|
31
29
|
const headers = ['ID', 'STATUS', 'DESCRIPTION', 'ENABLED'];
|
|
32
30
|
|
|
33
|
-
Logger.println(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
feature.id,
|
|
37
|
-
feature.status,
|
|
38
|
-
feature.description,
|
|
39
|
-
feature.enabled,
|
|
31
|
+
Logger.println(
|
|
32
|
+
formatTable([
|
|
33
|
+
headers,
|
|
34
|
+
...features.map((feature) => [feature.id, feature.status, feature.description, feature.enabled]),
|
|
40
35
|
]),
|
|
41
|
-
|
|
36
|
+
);
|
|
42
37
|
}
|
|
43
38
|
}
|
|
44
39
|
}
|
|
45
40
|
|
|
46
|
-
export async function info
|
|
41
|
+
export async function info(params) {
|
|
47
42
|
const { feature } = params.namedArgs;
|
|
48
43
|
const availableFeatures = Object.keys(EXPERIMENTAL_FEATURES);
|
|
49
44
|
|
|
@@ -54,7 +49,7 @@ export async function info (params) {
|
|
|
54
49
|
Logger.println(EXPERIMENTAL_FEATURES[feature].instructions);
|
|
55
50
|
}
|
|
56
51
|
|
|
57
|
-
export async function enable
|
|
52
|
+
export async function enable(params) {
|
|
58
53
|
const { features } = params.namedArgs;
|
|
59
54
|
const availableFeatures = Object.keys(EXPERIMENTAL_FEATURES);
|
|
60
55
|
|
|
@@ -70,14 +65,13 @@ export async function enable (params) {
|
|
|
70
65
|
|
|
71
66
|
if (features.length === 1) {
|
|
72
67
|
Logger.println(EXPERIMENTAL_FEATURES[features[0]].instructions);
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
68
|
+
} else {
|
|
75
69
|
Logger.println();
|
|
76
70
|
Logger.println("To learn more about these experimental features, use 'clever features info FEATURE_NAME'");
|
|
77
71
|
}
|
|
78
72
|
}
|
|
79
73
|
|
|
80
|
-
export async function disable
|
|
74
|
+
export async function disable(params) {
|
|
81
75
|
const { features } = params.namedArgs;
|
|
82
76
|
const availableFeatures = Object.keys(EXPERIMENTAL_FEATURES);
|
|
83
77
|
|
package/src/commands/keycloak.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
* @param {string} params.options.format The output format
|
|
20
20
|
* @returns {Promise<void>}
|
|
21
21
|
*/
|
|
22
|
-
export async function checkVersion
|
|
22
|
+
export async function checkVersion(params) {
|
|
23
23
|
const [addonIdOrName] = params.args;
|
|
24
24
|
const { format } = params.options;
|
|
25
25
|
await operatorCheckVersion('keycloak', addonIdOrName, format);
|
|
@@ -31,7 +31,7 @@ export async function checkVersion (params) {
|
|
|
31
31
|
* @param {string} params.args[0] The operator's name or ID
|
|
32
32
|
* @returns {Promise<void>}
|
|
33
33
|
*/
|
|
34
|
-
export async function updateVersion
|
|
34
|
+
export async function updateVersion(params) {
|
|
35
35
|
const [addonIdOrName] = params.args;
|
|
36
36
|
const { target } = params.options;
|
|
37
37
|
await operatorUpdateVersion('keycloak', target, addonIdOrName);
|
|
@@ -44,7 +44,7 @@ export async function updateVersion (params) {
|
|
|
44
44
|
* @param {string} params.options.format The output format
|
|
45
45
|
* @returns {Promise<void>}
|
|
46
46
|
*/
|
|
47
|
-
export async function get
|
|
47
|
+
export async function get(params) {
|
|
48
48
|
const [addonIdOrName] = params.args;
|
|
49
49
|
const { format } = params.options;
|
|
50
50
|
await operatorPrint('keycloak', addonIdOrName, format);
|
|
@@ -54,7 +54,7 @@ export async function get (params) {
|
|
|
54
54
|
* List all Keycloak operators
|
|
55
55
|
* @returns {Promise<void>}
|
|
56
56
|
*/
|
|
57
|
-
export async function list
|
|
57
|
+
export async function list(params) {
|
|
58
58
|
await operatorList('keycloak', params.options.format);
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -65,7 +65,7 @@ export async function list (params) {
|
|
|
65
65
|
* @returns {Promise<void>}
|
|
66
66
|
* @throws {Error} If the Network Group feature is already disabled
|
|
67
67
|
*/
|
|
68
|
-
export async function ngDisable
|
|
68
|
+
export async function ngDisable(params) {
|
|
69
69
|
const [addonIdOrName] = params.args;
|
|
70
70
|
await operatorNgDisable('keycloak', addonIdOrName);
|
|
71
71
|
}
|
|
@@ -77,7 +77,7 @@ export async function ngDisable (params) {
|
|
|
77
77
|
* @returns {Promise<void>}
|
|
78
78
|
* @throws {Error} If the Network Group feature is already enabled
|
|
79
79
|
*/
|
|
80
|
-
export async function ngEnable
|
|
80
|
+
export async function ngEnable(params) {
|
|
81
81
|
const [addonIdOrName] = params.args;
|
|
82
82
|
await operatorNgEnable('keycloak', addonIdOrName);
|
|
83
83
|
}
|
|
@@ -88,7 +88,7 @@ export async function ngEnable (params) {
|
|
|
88
88
|
* @param {string} params.args[0] The operator's name or ID
|
|
89
89
|
* @returns {Promise<void>}
|
|
90
90
|
*/
|
|
91
|
-
export async function open
|
|
91
|
+
export async function open(params) {
|
|
92
92
|
const [addonIdOrName] = params.args;
|
|
93
93
|
await operatorOpen('keycloak', addonIdOrName);
|
|
94
94
|
}
|
|
@@ -99,7 +99,7 @@ export async function open (params) {
|
|
|
99
99
|
* @param {string} params.args[0] The operator's name or ID
|
|
100
100
|
* @returns {Promise<void>}
|
|
101
101
|
*/
|
|
102
|
-
export async function openLogs
|
|
102
|
+
export async function openLogs(params) {
|
|
103
103
|
const [addonIdOrName] = params.args;
|
|
104
104
|
await operatorOpenLogs('keycloak', addonIdOrName);
|
|
105
105
|
}
|
|
@@ -110,7 +110,7 @@ export async function openLogs (params) {
|
|
|
110
110
|
* @param {string} params.args[0] The operator's name or ID
|
|
111
111
|
* @returns {Promise<void>}
|
|
112
112
|
*/
|
|
113
|
-
export async function openWebUi
|
|
113
|
+
export async function openWebUi(params) {
|
|
114
114
|
const [addonIdOrName] = params.args;
|
|
115
115
|
await operatorOpenWebUi('keycloak', addonIdOrName);
|
|
116
116
|
}
|
|
@@ -121,7 +121,7 @@ export async function openWebUi (params) {
|
|
|
121
121
|
* @param {string} params.args[0] The operator's name or ID
|
|
122
122
|
* @returns {Promise<void>}
|
|
123
123
|
*/
|
|
124
|
-
export async function reboot
|
|
124
|
+
export async function reboot(params) {
|
|
125
125
|
const [addonIdOrName] = params.args;
|
|
126
126
|
await operatorReboot('keycloak', addonIdOrName);
|
|
127
127
|
}
|
|
@@ -132,7 +132,7 @@ export async function reboot (params) {
|
|
|
132
132
|
* @param {string} params.args[0] The operator's name or ID
|
|
133
133
|
* @returns {Promise<void>}
|
|
134
134
|
*/
|
|
135
|
-
export async function rebuild
|
|
135
|
+
export async function rebuild(params) {
|
|
136
136
|
const [addonIdOrName] = params.args;
|
|
137
137
|
await operatorRebuild('keycloak', addonIdOrName);
|
|
138
138
|
}
|
package/src/commands/kv.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { getAllEnvVars } from '@clevercloud/client/esm/api/v2/addon.js';
|
|
1
2
|
import Redis from 'ioredis';
|
|
2
|
-
import
|
|
3
|
+
import { styleText } from 'node:util';
|
|
3
4
|
import { Logger } from '../logger.js';
|
|
4
|
-
import { sendToApi } from '../models/send-to-api.js';
|
|
5
|
-
import { getAllEnvVars } from '@clevercloud/client/esm/api/v2/addon.js';
|
|
6
5
|
import { findAddonsByNameOrId } from '../models/ids-resolver.js';
|
|
6
|
+
import { sendToApi } from '../models/send-to-api.js';
|
|
7
7
|
|
|
8
8
|
const URL_ENV_KEY = 'REDIS_URL';
|
|
9
9
|
const MAX_RETRIES_PER_REQUEST = 1;
|
|
@@ -16,7 +16,7 @@ const MAX_RETRIES_PER_REQUEST = 1;
|
|
|
16
16
|
* @param {string} params.options.format
|
|
17
17
|
* @returns {Promise<void>}
|
|
18
18
|
*/
|
|
19
|
-
export async function sendRawCommand
|
|
19
|
+
export async function sendRawCommand(params) {
|
|
20
20
|
const [addonIdOrRealIdOrName] = params.args;
|
|
21
21
|
const { org, format } = params.options;
|
|
22
22
|
|
|
@@ -28,7 +28,7 @@ export async function sendRawCommand (params) {
|
|
|
28
28
|
|
|
29
29
|
if (addons.length > 1) {
|
|
30
30
|
const formattedAddons = addons
|
|
31
|
-
.map(({ addonId, ownerId }) => `\n${
|
|
31
|
+
.map(({ addonId, ownerId }) => `\n${styleText('grey', `- ${addonId} (${ownerId})`)}`)
|
|
32
32
|
.join('');
|
|
33
33
|
throw new Error(`Several add-ons found for '${addonIdOrRealIdOrName}', use ID instead:${formattedAddons}`);
|
|
34
34
|
}
|
|
@@ -56,17 +56,18 @@ export async function sendRawCommand (params) {
|
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Get the URL of the compatible KV database
|
|
59
|
-
* @param {string} ownerId
|
|
60
|
-
* @param {string} addonId
|
|
59
|
+
* @param {string} ownerId
|
|
60
|
+
* @param {string} addonId
|
|
61
61
|
* @returns {Promise<string>} the URL of the compatible KV database
|
|
62
62
|
*/
|
|
63
|
-
async function getAddonUrl
|
|
64
|
-
|
|
63
|
+
async function getAddonUrl(ownerId, addonId) {
|
|
65
64
|
const envVars = await getAllEnvVars({ id: ownerId, addonId }).then(sendToApi);
|
|
66
65
|
const redisUrl = envVars.find((env) => env.name === URL_ENV_KEY)?.value;
|
|
67
66
|
|
|
68
67
|
if (!redisUrl) {
|
|
69
|
-
throw new Error(
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Environment variable ${styleText('red', URL_ENV_KEY)} not found, is it a Materia KV or Redis® add-on?`,
|
|
70
|
+
);
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
return redisUrl;
|
|
@@ -78,15 +79,14 @@ async function getAddonUrl (ownerId, addonId) {
|
|
|
78
79
|
* @param {Array<string>} command
|
|
79
80
|
* @returns {Promise<string>} the command result
|
|
80
81
|
*/
|
|
81
|
-
async function sendCommand
|
|
82
|
+
async function sendCommand(url, command) {
|
|
82
83
|
Logger.debug(`Sending command '${command.join(' ')}' to ${url}`);
|
|
83
84
|
const client = new Redis(url, { maxRetriesPerRequest: MAX_RETRIES_PER_REQUEST });
|
|
84
85
|
try {
|
|
85
86
|
const result = await client.call(...command);
|
|
86
87
|
Logger.debug(`Command result: ${result}`);
|
|
87
88
|
return result;
|
|
88
|
-
}
|
|
89
|
-
finally {
|
|
89
|
+
} finally {
|
|
90
90
|
await client.disconnect();
|
|
91
91
|
Logger.debug('Disconnected from server');
|
|
92
92
|
}
|
package/src/commands/link.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
2
|
import { Logger } from '../logger.js';
|
|
3
|
-
import
|
|
3
|
+
import * as Application from '../models/application.js';
|
|
4
4
|
|
|
5
|
-
export async function link
|
|
5
|
+
export async function link(params) {
|
|
6
6
|
const [app] = params.args;
|
|
7
7
|
const { org: orgaIdOrName, alias } = params.options;
|
|
8
8
|
|
|
9
9
|
if (app.app_id != null && orgaIdOrName != null) {
|
|
10
|
-
Logger.warn(
|
|
10
|
+
Logger.warn("You've specified a unique application ID, organisation option will be ignored");
|
|
11
11
|
await Application.linkRepo(app, null, alias);
|
|
12
|
-
}
|
|
13
|
-
else {
|
|
12
|
+
} else {
|
|
14
13
|
await Application.linkRepo(app, orgaIdOrName, alias);
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
const linkedMessage = alias ? ` to local alias ${
|
|
18
|
-
Logger.printSuccess(
|
|
16
|
+
const linkedMessage = alias ? ` to local alias ${styleText('green', alias)}` : '';
|
|
17
|
+
Logger.printSuccess(
|
|
18
|
+
`Application ${styleText('green', app.app_name || app.app_id)} has been successfully linked${linkedMessage}!`,
|
|
19
|
+
);
|
|
19
20
|
}
|
package/src/commands/login.js
CHANGED
|
@@ -1,29 +1,21 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import colors from 'colors/safe.js';
|
|
2
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
3
|
+
import { styleText } from 'node:util';
|
|
5
4
|
import open from 'open';
|
|
6
|
-
import
|
|
7
|
-
|
|
5
|
+
import pkg from '../../package.json' with { type: 'json' };
|
|
8
6
|
import { Logger } from '../logger.js';
|
|
9
|
-
import * as User from '../models/user.js';
|
|
10
7
|
import { conf, writeOAuthConf } from '../models/configuration.js';
|
|
11
|
-
|
|
12
|
-
import { getPackageJson } from '../load-package-json.cjs';
|
|
13
|
-
|
|
14
|
-
const delay = util.promisify(setTimeout);
|
|
15
|
-
const pkg = getPackageJson();
|
|
8
|
+
import * as User from '../models/user.js';
|
|
16
9
|
|
|
17
10
|
// 20 random bytes as Base64URL
|
|
18
|
-
function randomToken
|
|
11
|
+
function randomToken() {
|
|
19
12
|
return crypto.randomBytes(20).toString('base64').replace(/\//g, '-').replace(/\+/g, '_').replace(/=/g, '');
|
|
20
13
|
}
|
|
21
14
|
|
|
22
15
|
const POLLING_INTERVAL = 2000;
|
|
23
16
|
const POLLING_MAX_TRY_COUNT = 60;
|
|
24
17
|
|
|
25
|
-
function pollOauthData
|
|
26
|
-
|
|
18
|
+
function pollOauthData(url, tryCount = 0) {
|
|
27
19
|
if (tryCount >= POLLING_MAX_TRY_COUNT) {
|
|
28
20
|
throw new Error('Something went wrong while trying to log you in.');
|
|
29
21
|
}
|
|
@@ -31,21 +23,21 @@ function pollOauthData (url, tryCount = 0) {
|
|
|
31
23
|
Logger.println("We're still waiting for the login process (in your browser) to be completed…");
|
|
32
24
|
}
|
|
33
25
|
|
|
34
|
-
return
|
|
35
|
-
.
|
|
36
|
-
.
|
|
37
|
-
|
|
38
|
-
.catch(async (e) => {
|
|
39
|
-
if (e.status === 404) {
|
|
26
|
+
return globalThis
|
|
27
|
+
.fetch(url)
|
|
28
|
+
.then(async (r) => {
|
|
29
|
+
if (r.status === 404) {
|
|
40
30
|
await delay(POLLING_INTERVAL);
|
|
41
31
|
return pollOauthData(url, tryCount + 1);
|
|
42
32
|
}
|
|
33
|
+
return r.json();
|
|
34
|
+
})
|
|
35
|
+
.catch(async () => {
|
|
43
36
|
throw new Error('Something went wrong while trying to log you in.');
|
|
44
37
|
});
|
|
45
38
|
}
|
|
46
39
|
|
|
47
|
-
async function loginViaConsole
|
|
48
|
-
|
|
40
|
+
async function loginViaConsole() {
|
|
49
41
|
const cliToken = randomToken();
|
|
50
42
|
|
|
51
43
|
const consoleUrl = new URL(conf.CONSOLE_TOKEN_URL);
|
|
@@ -57,16 +49,16 @@ async function loginViaConsole () {
|
|
|
57
49
|
cliPollUrl.searchParams.set('cli_token', cliToken);
|
|
58
50
|
|
|
59
51
|
Logger.debug('Try to login to Clever Cloud…');
|
|
60
|
-
Logger.println(`Opening ${
|
|
52
|
+
Logger.println(`Opening ${styleText('green', consoleUrl.toString())} in your browser to log you in…`);
|
|
61
53
|
await open(consoleUrl.toString(), { wait: false });
|
|
62
54
|
|
|
63
55
|
return pollOauthData(cliPollUrl.toString());
|
|
64
56
|
}
|
|
65
57
|
|
|
66
|
-
export async function login
|
|
58
|
+
export async function login(params) {
|
|
67
59
|
const { token, secret } = params.options;
|
|
68
|
-
const isLoginWithArgs =
|
|
69
|
-
const isInteractiveLogin =
|
|
60
|
+
const isLoginWithArgs = token != null && secret != null;
|
|
61
|
+
const isInteractiveLogin = token == null && secret == null;
|
|
70
62
|
|
|
71
63
|
if (isLoginWithArgs) {
|
|
72
64
|
return writeOAuthConf({ token, secret });
|
|
@@ -76,7 +68,7 @@ export async function login (params) {
|
|
|
76
68
|
const oauthData = await loginViaConsole();
|
|
77
69
|
await writeOAuthConf(oauthData);
|
|
78
70
|
const { name, email } = await User.getCurrent();
|
|
79
|
-
const formattedName = name ||
|
|
71
|
+
const formattedName = name || styleText(['red', 'bold'], '[unspecified name]');
|
|
80
72
|
return Logger.println(`Login successful as ${formattedName} <${email}>`);
|
|
81
73
|
}
|
|
82
74
|
|
package/src/commands/logout.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Logger } from '../logger.js';
|
|
2
2
|
import { conf, writeOAuthConf } from '../models/configuration.js';
|
|
3
3
|
|
|
4
|
-
export async function logout
|
|
4
|
+
export async function logout() {
|
|
5
5
|
// write empty object
|
|
6
6
|
await writeOAuthConf({});
|
|
7
7
|
Logger.println(`${conf.CONFIGURATION_FILE} has been updated.`);
|
package/src/commands/logs.js
CHANGED
|
@@ -1,25 +1,33 @@
|
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
|
+
import { Logger } from '../logger.js';
|
|
1
3
|
import * as Application from '../models/application.js';
|
|
2
|
-
import
|
|
4
|
+
import { resolveAddonId } from '../models/ids-resolver.js';
|
|
3
5
|
import * as Log from '../models/log-v4.js';
|
|
4
|
-
import
|
|
6
|
+
import * as LogV2 from '../models/log.js';
|
|
5
7
|
import { Deferred } from '../models/utils.js';
|
|
6
|
-
import colors from 'colors/safe.js';
|
|
7
|
-
import { resolveAddonId } from '../models/ids-resolver.js';
|
|
8
8
|
|
|
9
|
-
export async function appLogs
|
|
10
|
-
const {
|
|
9
|
+
export async function appLogs(params) {
|
|
10
|
+
const {
|
|
11
|
+
alias,
|
|
12
|
+
app: appIdOrName,
|
|
13
|
+
addon: addonIdOrRealId,
|
|
14
|
+
after: since,
|
|
15
|
+
before: until,
|
|
16
|
+
search,
|
|
17
|
+
'deployment-id': deploymentId,
|
|
18
|
+
format,
|
|
19
|
+
} = params.options;
|
|
11
20
|
|
|
12
21
|
// ignore --search ""
|
|
13
|
-
const filter =
|
|
14
|
-
const isForHuman =
|
|
22
|
+
const filter = search !== '' ? search : null;
|
|
23
|
+
const isForHuman = format === 'human';
|
|
15
24
|
|
|
16
25
|
// TODO: drop when addons are migrated to the v4 API
|
|
17
26
|
if (addonIdOrRealId != null) {
|
|
18
27
|
const addonId = await resolveAddonId(addonIdOrRealId);
|
|
19
28
|
if (isForHuman) {
|
|
20
|
-
Logger.println(
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
29
|
+
Logger.println(styleText('blue', 'Waiting for addon logs…'));
|
|
30
|
+
} else {
|
|
23
31
|
throw new Error(`"${format}" format is not yet available for add-on logs`);
|
|
24
32
|
}
|
|
25
33
|
return LogV2.displayLogs({ appAddonId: addonId, since, until, filter, deploymentId });
|
|
@@ -28,7 +36,7 @@ export async function appLogs (params) {
|
|
|
28
36
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
29
37
|
|
|
30
38
|
if (isForHuman) {
|
|
31
|
-
Logger.println(
|
|
39
|
+
Logger.println(styleText('blue', 'Waiting for application logs…'));
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
const deferred = new Deferred();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
2
|
import { Logger } from '../logger.js';
|
|
3
|
-
import
|
|
3
|
+
import * as AppConfig from '../models/app_configuration.js';
|
|
4
4
|
|
|
5
|
-
export async function makeDefault
|
|
5
|
+
export async function makeDefault(params) {
|
|
6
6
|
const [alias] = params.args;
|
|
7
7
|
|
|
8
8
|
await AppConfig.setDefault(alias);
|
|
9
9
|
|
|
10
|
-
Logger.printSuccess(`The application ${
|
|
11
|
-
}
|
|
10
|
+
Logger.printSuccess(`The application ${styleText('green', alias)} has been set as default`);
|
|
11
|
+
}
|