clever-tools 3.11.0 → 3.13.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/bin/clever.js +416 -3
- package/package.json +4 -3
- package/src/clever-client/auth-bridge.js +61 -0
- package/src/clever-client/ng.js +18 -0
- package/src/clever-client/operators.js +121 -0
- package/src/commands/addon.js +34 -28
- package/src/commands/cancel-deploy.js +3 -4
- package/src/commands/config.js +16 -20
- package/src/commands/console.js +4 -10
- package/src/commands/create.js +76 -9
- package/src/commands/curl.js +17 -17
- package/src/commands/database.js +9 -9
- package/src/commands/delete.js +11 -10
- package/src/commands/deploy.js +35 -21
- package/src/commands/domain.js +13 -16
- package/src/commands/emails.js +174 -0
- package/src/commands/env.js +15 -8
- package/src/commands/keycloak.js +138 -0
- package/src/commands/kv.js +1 -1
- package/src/commands/link.js +7 -3
- package/src/commands/makeDefault.js +2 -1
- package/src/commands/matomo.js +85 -0
- package/src/commands/metabase.js +112 -0
- package/src/commands/ng.js +202 -0
- package/src/commands/open.js +2 -5
- package/src/commands/otoroshi.js +138 -0
- package/src/commands/profile.js +11 -10
- package/src/commands/published-config.js +7 -7
- package/src/commands/restart.js +1 -1
- package/src/commands/ssh-keys.js +159 -0
- package/src/commands/stop.js +3 -3
- package/src/commands/tcp-redirs.js +8 -8
- package/src/commands/tokens.js +146 -0
- package/src/commands/unlink.js +2 -1
- package/src/experimental-features.js +47 -2
- package/src/lib/ng-print.js +195 -0
- package/src/lib/operator-commands.js +281 -0
- package/src/lib/prompts.js +30 -0
- package/src/lib/slugify.js +10 -0
- package/src/logger.js +3 -0
- package/src/models/activity.js +2 -3
- package/src/models/addon.js +9 -6
- package/src/models/app_configuration.js +12 -9
- package/src/models/application.js +44 -22
- package/src/models/application_configuration.js +72 -72
- package/src/models/configuration.js +1 -0
- package/src/models/git.js +29 -1
- package/src/models/ids-resolver.js +37 -1
- package/src/models/interact.js +0 -24
- package/src/models/log-v4.js +13 -4
- package/src/models/namespaces.js +3 -2
- package/src/models/ng-resources.js +270 -0
- package/src/models/ng.js +276 -0
- package/src/models/operator.js +48 -0
- package/src/models/send-to-api.js +18 -0
- package/src/models/utils.js +21 -0
- package/src/parsers.js +71 -3
package/src/commands/deploy.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import colors from 'colors/safe.js';
|
|
2
|
+
import dedent from 'dedent';
|
|
2
3
|
|
|
3
4
|
import * as AppConfig from '../models/app_configuration.js';
|
|
4
5
|
import * as Application from '../models/application.js';
|
|
@@ -27,14 +28,10 @@ export async function deploy (params) {
|
|
|
27
28
|
|
|
28
29
|
await git.addRemote(appData.alias, appData.deployUrl);
|
|
29
30
|
|
|
30
|
-
Logger.println(colors.bold.blue(`Remote application is app_id=${appId}, alias=${appData.alias}, name=${appData.name}`));
|
|
31
|
-
|
|
32
|
-
Logger.println(colors.bold.blue(`Remote application belongs to ${ownerId}`));
|
|
33
|
-
|
|
34
31
|
if (commitIdToPush === remoteHeadCommitId) {
|
|
35
32
|
switch (sameCommitPolicy) {
|
|
36
33
|
case 'ignore':
|
|
37
|
-
Logger.
|
|
34
|
+
Logger.printSuccess(`The application is up-to-date (${colors.grey(remoteHeadCommitId)})`);
|
|
38
35
|
return;
|
|
39
36
|
case 'restart':
|
|
40
37
|
return restartOnSameCommit(ownerId, appId, commitIdToPush, quiet, false, exitStrategy);
|
|
@@ -42,31 +39,44 @@ export async function deploy (params) {
|
|
|
42
39
|
return restartOnSameCommit(ownerId, appId, commitIdToPush, quiet, true, exitStrategy);
|
|
43
40
|
case 'error':
|
|
44
41
|
default: {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
throw new Error(`${upToDateMessage}\n${colors.yellow('clever restart')}`);
|
|
42
|
+
const restartCommand = commitIdToPush !== deployedCommitId ? `clever restart --commit ${commitIdToPush}` : 'clever restart';
|
|
43
|
+
throw new Error(dedent`
|
|
44
|
+
Remote HEAD has the same commit as the one to push ${colors.grey(`(${remoteHeadCommitId})`)}, your application is up-to-date.
|
|
45
|
+
Create a new commit, use ${colors.blue(restartCommand)} or the ${colors.blue('--same-commit-policy')} option.
|
|
46
|
+
`);
|
|
51
47
|
}
|
|
52
48
|
}
|
|
53
49
|
}
|
|
54
50
|
|
|
51
|
+
// It's sometimes tricky to figure out the deployment ID for the current git push.
|
|
52
|
+
// We on have the commit ID but there in a situation where the last deployment was cancelled, it may have the same commit ID.
|
|
53
|
+
// So before pushing, we get the last deployments so we can after the push figure out which deployment is new…
|
|
54
|
+
const knownDeployments = await getAllDeployments({ id: ownerId, appId, limit: 5 }).then(sendToApi);
|
|
55
|
+
|
|
56
|
+
Logger.println(dedent`
|
|
57
|
+
${colors.bold(`🚀 Deploying ${colors.green(appData.name)}`)}
|
|
58
|
+
Application ID ${colors.grey(`${appId}`)}
|
|
59
|
+
Org ID ${colors.grey(`${ownerId}`)}
|
|
60
|
+
`);
|
|
61
|
+
|
|
62
|
+
Logger.println();
|
|
63
|
+
|
|
64
|
+
Logger.println(colors.bold('🔀 Git information'));
|
|
55
65
|
if (remoteHeadCommitId == null || deployedCommitId == null) {
|
|
56
|
-
Logger.println('App is brand new, no commits on remote yet
|
|
66
|
+
Logger.println(` ${colors.yellow('!')} App is brand new, no commits on remote yet`);
|
|
57
67
|
}
|
|
58
68
|
else {
|
|
59
|
-
Logger.println(`Remote
|
|
60
|
-
Logger.println(`
|
|
69
|
+
Logger.println(` Remote head ${colors.yellow(remoteHeadCommitId)} (${branchRefspec})`);
|
|
70
|
+
Logger.println(` Deployed commit ${colors.yellow(deployedCommitId)}`);
|
|
61
71
|
}
|
|
62
|
-
Logger.println(`
|
|
72
|
+
Logger.println(` Local commit ${colors.yellow(commitIdToPush)} ${colors.blue('[will be deployed]')}`);
|
|
63
73
|
|
|
64
|
-
|
|
65
|
-
// We on have the commit ID but there in a situation where the last deployment was cancelled, it may have the same commit ID.
|
|
66
|
-
// So before pushing, we get the last deployments so we can after the push figure out which deployment is new…
|
|
67
|
-
const knownDeployments = await getAllDeployments({ id: ownerId, appId, limit: 5 }).then(sendToApi);
|
|
74
|
+
Logger.println();
|
|
68
75
|
|
|
69
|
-
Logger.println(
|
|
76
|
+
Logger.println(dedent`
|
|
77
|
+
${colors.bold('🔄 Deployment progress')}
|
|
78
|
+
${colors.blue('→ Pushing source code to Clever Cloud…')}
|
|
79
|
+
`);
|
|
70
80
|
|
|
71
81
|
await git.push(appData.deployUrl, commitIdToPush, force)
|
|
72
82
|
.catch(async (e) => {
|
|
@@ -78,12 +88,16 @@ export async function deploy (params) {
|
|
|
78
88
|
throw e;
|
|
79
89
|
}
|
|
80
90
|
});
|
|
81
|
-
|
|
91
|
+
|
|
92
|
+
await Logger.println(` ${colors.green('✓ Code pushed to Clever Cloud')}`);
|
|
82
93
|
|
|
83
94
|
return Log.watchDeploymentAndDisplayLogs({ ownerId, appId, commitId: commitIdToPush, knownDeployments, quiet, exitStrategy });
|
|
84
95
|
}
|
|
85
96
|
|
|
86
97
|
async function restartOnSameCommit (ownerId, appId, commitIdToPush, quiet, withoutCache, exitStrategy) {
|
|
98
|
+
const cacheSuffix = withoutCache ? ' without using cache' : '';
|
|
99
|
+
Logger.println(`🔄 Restarting ${colors.bold(appId)}${cacheSuffix} ${colors.grey(`(${commitIdToPush})`)}`);
|
|
100
|
+
|
|
87
101
|
const restart = await Application.redeploy(ownerId, appId, commitIdToPush, withoutCache);
|
|
88
102
|
return Log.watchDeploymentAndDisplayLogs({ ownerId, appId, deploymentId: restart.deploymentId, quiet, exitStrategy });
|
|
89
103
|
}
|
package/src/commands/domain.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
removeDomain,
|
|
10
10
|
unmarkFavouriteDomain,
|
|
11
11
|
} from '@clevercloud/client/esm/api/v2/application.js';
|
|
12
|
-
import { getSummary } from '@clevercloud/client/
|
|
12
|
+
import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
|
|
13
13
|
import { sendToApi } from '../models/send-to-api.js';
|
|
14
14
|
import colors from 'colors/safe.js';
|
|
15
15
|
import { parse as parseDomain } from 'tldts';
|
|
@@ -17,6 +17,7 @@ import { diagDomainConfig } from '@clevercloud/client/esm/utils/diag-domain-conf
|
|
|
17
17
|
import { sortDomains } from '@clevercloud/client/esm/utils/domains.js';
|
|
18
18
|
import { DnsResolver } from '../models/node-dns-resolver.js';
|
|
19
19
|
import _ from 'lodash';
|
|
20
|
+
import { getDefaultLoadBalancersDnsInfo } from '@clevercloud/client/esm/api/v4/load-balancers.js';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* @typedef {import('@clevercloud/client/esm/utils/diag-domain-config.types.js').DomainInfo} DomainInfo
|
|
@@ -110,7 +111,7 @@ export async function diagApplication (params) {
|
|
|
110
111
|
let hasError = false;
|
|
111
112
|
|
|
112
113
|
const app = await getApp({ id: ownerId, appId }).then(sendToApi);
|
|
113
|
-
const expectedDnsForPublicLoadBalancer = await getDefaultLoadBalancersDnsInfo({
|
|
114
|
+
const expectedDnsForPublicLoadBalancer = await getDefaultLoadBalancersDnsInfo({ ownerId, appId }).then(sendToApi);
|
|
114
115
|
|
|
115
116
|
const loadBalancerDnsConfig = {
|
|
116
117
|
aRecords: expectedDnsForPublicLoadBalancer[0].dns.a,
|
|
@@ -181,7 +182,16 @@ export async function overview (params) {
|
|
|
181
182
|
|
|
182
183
|
const applicationsWithDomains = await Promise.all(
|
|
183
184
|
applications.map(async (app) => {
|
|
184
|
-
const domains = await getAllDomains({ id: app.ownerId, appId: app.id })
|
|
185
|
+
const domains = await getAllDomains({ id: app.ownerId, appId: app.id })
|
|
186
|
+
.then(sendToApi)
|
|
187
|
+
.catch((error) => {
|
|
188
|
+
// if the user cannot access application domains, we simply act as if there were no domains
|
|
189
|
+
if (error?.response?.status === 403) {
|
|
190
|
+
Logger.printErrorLine(`You cannot list domains for application ${app.name} (${app.id})`);
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
throw error;
|
|
194
|
+
});
|
|
185
195
|
return { app, domains };
|
|
186
196
|
}),
|
|
187
197
|
);
|
|
@@ -351,19 +361,6 @@ function reportDomainDiagnostics ({ hostname, pathPrefix, resolvedDnsConfig, dia
|
|
|
351
361
|
}
|
|
352
362
|
}
|
|
353
363
|
|
|
354
|
-
// TODO: put in clever client
|
|
355
|
-
function getDefaultLoadBalancersDnsInfo (params) {
|
|
356
|
-
return Promise.resolve({
|
|
357
|
-
method: 'get',
|
|
358
|
-
url: `/v4/load-balancers/organisations/${params.id}/applications/${params.appId}/load-balancers/default`,
|
|
359
|
-
headers: {
|
|
360
|
-
Accept: 'application/json',
|
|
361
|
-
},
|
|
362
|
-
// no query params
|
|
363
|
-
// no body
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
|
|
367
364
|
/**
|
|
368
365
|
* Parses domain information from vhosts array
|
|
369
366
|
*
|
|
@@ -0,0 +1,174 @@
|
|
|
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
|
+
import {
|
|
8
|
+
todo_addEmailAddress as addEmailAddress,
|
|
9
|
+
todo_getEmailAddresses as getEmailAddresses,
|
|
10
|
+
todo_removeEmailAddress as removeEmailAddress,
|
|
11
|
+
} from '@clevercloud/client/esm/api/v2/user.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Show primary and secondary email addresses of the current user
|
|
15
|
+
* @param {object} params The command parameters
|
|
16
|
+
* @param {string} params.options.format The output format
|
|
17
|
+
*/
|
|
18
|
+
export async function list (params) {
|
|
19
|
+
const { format } = params.options;
|
|
20
|
+
const addresses = await getUserEmailAddresses();
|
|
21
|
+
|
|
22
|
+
switch (format) {
|
|
23
|
+
case 'json': {
|
|
24
|
+
Logger.printJson(addresses);
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
case 'human':
|
|
28
|
+
default: {
|
|
29
|
+
Logger.println('✉️ Primary email address:');
|
|
30
|
+
Logger.println(` • ${colors.green(addresses.primary)}`);
|
|
31
|
+
if (addresses.secondary.length > 0) {
|
|
32
|
+
Logger.println();
|
|
33
|
+
Logger.println(`✉️ ${addresses.secondary.length} secondary email address(es):`);
|
|
34
|
+
addresses.secondary.forEach((address) =>
|
|
35
|
+
Logger.println(` • ${colors.blue(address)}`),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Add a secondary email address to the current user
|
|
44
|
+
* @param {object} params The command parameters
|
|
45
|
+
* @param {Array<string>} params.args
|
|
46
|
+
*/
|
|
47
|
+
export async function addSecondary (params) {
|
|
48
|
+
const [secondaryAddress] = params.args;
|
|
49
|
+
|
|
50
|
+
const secondaryAddressEncoded = encodeURIComponent(secondaryAddress);
|
|
51
|
+
try {
|
|
52
|
+
await addEmailAddress({ email: secondaryAddressEncoded }).then(sendToApi);
|
|
53
|
+
Logger.printSuccess(`The server sent a confirmation email to ${secondaryAddress} to validate your secondary address`);
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
switch (e?.responseBody?.id) {
|
|
57
|
+
case 101:
|
|
58
|
+
throw new Error('This address already belongs to your account');
|
|
59
|
+
case 550:
|
|
60
|
+
throw new Error('The format of this address is invalid');
|
|
61
|
+
case 1004:
|
|
62
|
+
throw new Error('This address belongs to another account');
|
|
63
|
+
default:
|
|
64
|
+
throw e;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Set the primary email address of the current user
|
|
71
|
+
* @param {object} params The command parameters
|
|
72
|
+
* @param {Array<string>} params.args
|
|
73
|
+
*/
|
|
74
|
+
export async function setPrimary (params) {
|
|
75
|
+
const [newPrimaryAddress] = params.args;
|
|
76
|
+
|
|
77
|
+
const addresses = await getUserEmailAddresses();
|
|
78
|
+
|
|
79
|
+
if (addresses.primary === newPrimaryAddress) {
|
|
80
|
+
throw new Error('This address is already the primary one');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!addresses.secondary.includes(newPrimaryAddress)) {
|
|
84
|
+
throw new Error('This address must be added as a secondary address before marking it as primary');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const newPrimaryEmailEncoded = encodeURIComponent(newPrimaryAddress);
|
|
88
|
+
await addEmailAddress({ email: newPrimaryEmailEncoded }, { make_primary: true }).then(sendToApi);
|
|
89
|
+
|
|
90
|
+
Logger.printSuccess(`Primary address updated to ${newPrimaryAddress} successfully`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Remove a secondary email address from the current user
|
|
95
|
+
* @param {object} params The command parameters
|
|
96
|
+
* @param {Array<string>} params.args
|
|
97
|
+
*/
|
|
98
|
+
export async function removeSecondary (params) {
|
|
99
|
+
const [addressToRemove] = params.args;
|
|
100
|
+
|
|
101
|
+
const addresses = await getUserEmailAddresses();
|
|
102
|
+
|
|
103
|
+
if (!addresses.secondary.includes(addressToRemove)) {
|
|
104
|
+
throw new Error('This address is not part of the secondary addresses of the current user, it can\'t be removed');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const addressToRemoveEncoded = encodeURIComponent(addressToRemove);
|
|
108
|
+
await removeEmailAddress({ email: addressToRemoveEncoded }).then(sendToApi);
|
|
109
|
+
|
|
110
|
+
Logger.printSuccess(`Secondary address ${addressToRemove} removed successfully`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Remove all secondary email addresses from the current user
|
|
115
|
+
* @param {object} params The command parameters
|
|
116
|
+
* @param {object} params.options The command options
|
|
117
|
+
* @param {boolean} params.options.yes The user confirmation
|
|
118
|
+
*/
|
|
119
|
+
export async function removeAllSecondary (params) {
|
|
120
|
+
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
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const addresses = await getUserEmailAddresses();
|
|
128
|
+
|
|
129
|
+
if (addresses.secondary.length === 0) {
|
|
130
|
+
Logger.println('No secondary address to remove');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const results = await Promise.all(
|
|
135
|
+
addresses.secondary.map((addressToRemove) => {
|
|
136
|
+
const addressToRemoveEncoded = encodeURIComponent(addressToRemove);
|
|
137
|
+
return removeEmailAddress({ email: addressToRemoveEncoded }).then(sendToApi)
|
|
138
|
+
.then(() => [true, addressToRemove])
|
|
139
|
+
.catch(() => [false, addressToRemove]);
|
|
140
|
+
}),
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
if (results.every(([isRemoved]) => isRemoved)) {
|
|
144
|
+
Logger.printSuccess('All secondary addresses were removed successfully');
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
const addressesWithErrors = results
|
|
148
|
+
.filter(([isRemoved]) => !isRemoved)
|
|
149
|
+
.map(([_, address]) => address)
|
|
150
|
+
.join(', ');
|
|
151
|
+
throw new Error(`Some errors occured while removing these addresses: ${addressesWithErrors}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Open the email addresses management page of the Console in your browser
|
|
157
|
+
* @returns {Promise<void>} A promise that resolves when the page is opened
|
|
158
|
+
*/
|
|
159
|
+
export function openConsole () {
|
|
160
|
+
return openBrowser('/users/me/emails', 'Opening the email addresses management page of the Console in your browser');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get the primary and secondary email addresses of the current user
|
|
165
|
+
* @returns {Promise<{ primary: string, secondary: string[] }>} The primary and secondary email addresses of the current user
|
|
166
|
+
*/
|
|
167
|
+
async function getUserEmailAddresses () {
|
|
168
|
+
const currentUser = await User.getCurrent();
|
|
169
|
+
const secondaryAddresses = await getEmailAddresses().then(sendToApi);
|
|
170
|
+
return {
|
|
171
|
+
primary: currentUser.email,
|
|
172
|
+
secondary: secondaryAddresses.sort(),
|
|
173
|
+
};
|
|
174
|
+
}
|
package/src/commands/env.js
CHANGED
|
@@ -4,16 +4,23 @@ import colors from 'colors/safe.js';
|
|
|
4
4
|
import * as variables from '../models/variables.js';
|
|
5
5
|
import { sendToApi } from '../models/send-to-api.js';
|
|
6
6
|
import { toNameEqualsValueString, validateName } from '@clevercloud/client/esm/utils/env-vars.js';
|
|
7
|
-
import
|
|
7
|
+
import {
|
|
8
|
+
getAllEnvVars,
|
|
9
|
+
getAllEnvVarsForAddons,
|
|
10
|
+
getAllEnvVarsForDependencies,
|
|
11
|
+
updateEnvVar,
|
|
12
|
+
updateAllEnvVars,
|
|
13
|
+
removeEnvVar,
|
|
14
|
+
} from '@clevercloud/client/esm/api/v2/application.js';
|
|
8
15
|
|
|
9
16
|
export async function list (params) {
|
|
10
17
|
const { alias, app: appIdOrName, 'add-export': addExportsOption, format } = params.options;
|
|
11
18
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
12
19
|
|
|
13
20
|
const [envFromApp, envFromAddons, envFromDeps] = await Promise.all([
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
getAllEnvVars({ id: ownerId, appId }).then(sendToApi),
|
|
22
|
+
getAllEnvVarsForAddons({ id: ownerId, appId }).then(sendToApi),
|
|
23
|
+
getAllEnvVarsForDependencies({ id: ownerId, appId }).then(sendToApi),
|
|
17
24
|
]);
|
|
18
25
|
|
|
19
26
|
switch (format) {
|
|
@@ -69,7 +76,7 @@ export async function set (params) {
|
|
|
69
76
|
|
|
70
77
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
71
78
|
|
|
72
|
-
await
|
|
79
|
+
await updateEnvVar({ id: ownerId, appId, envName }, { value }).then(sendToApi);
|
|
73
80
|
|
|
74
81
|
Logger.println('Your environment variable has been successfully saved');
|
|
75
82
|
};
|
|
@@ -79,7 +86,7 @@ export async function rm (params) {
|
|
|
79
86
|
const { alias, app: appIdOrName } = params.options;
|
|
80
87
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
81
88
|
|
|
82
|
-
await
|
|
89
|
+
await removeEnvVar({ id: ownerId, appId, envName }).then(sendToApi);
|
|
83
90
|
|
|
84
91
|
Logger.println('Your environment variable has been successfully removed');
|
|
85
92
|
};
|
|
@@ -90,7 +97,7 @@ export async function importEnv (params) {
|
|
|
90
97
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
91
98
|
|
|
92
99
|
const envVars = await variables.readVariablesFromStdin(format);
|
|
93
|
-
await
|
|
100
|
+
await updateAllEnvVars({ id: ownerId, appId }, envVars).then(sendToApi);
|
|
94
101
|
|
|
95
102
|
Logger.println('Environment variables have been set');
|
|
96
103
|
};
|
|
@@ -110,7 +117,7 @@ export async function importVarsFromLocalEnv (params) {
|
|
|
110
117
|
|
|
111
118
|
for (const envName of envNames) {
|
|
112
119
|
const value = process.env[envName] || '';
|
|
113
|
-
await
|
|
120
|
+
await updateEnvVar({ id: ownerId, appId, envName }, { value }).then(sendToApi);
|
|
114
121
|
}
|
|
115
122
|
|
|
116
123
|
Logger.println('Your environment variables have been successfully saved');
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import {
|
|
2
|
+
operatorCheckVersion,
|
|
3
|
+
operatorList,
|
|
4
|
+
operatorNgDisable,
|
|
5
|
+
operatorNgEnable,
|
|
6
|
+
operatorOpen,
|
|
7
|
+
operatorOpenLogs,
|
|
8
|
+
operatorOpenWebUi,
|
|
9
|
+
operatorPrint,
|
|
10
|
+
operatorReboot,
|
|
11
|
+
operatorRebuild,
|
|
12
|
+
operatorUpdateVersion,
|
|
13
|
+
} from '../lib/operator-commands.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check the version of a Keycloak operator
|
|
17
|
+
* @param {object} params The command's parameters
|
|
18
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
19
|
+
* @param {string} params.options.format The output format
|
|
20
|
+
* @returns {Promise<void>}
|
|
21
|
+
*/
|
|
22
|
+
export async function checkVersion (params) {
|
|
23
|
+
const [addonIdOrName] = params.args;
|
|
24
|
+
const { format } = params.options;
|
|
25
|
+
await operatorCheckVersion('keycloak', addonIdOrName, format);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Update the version of a Keycloak operator
|
|
30
|
+
* @param {object} params The command's parameters
|
|
31
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
32
|
+
* @returns {Promise<void>}
|
|
33
|
+
*/
|
|
34
|
+
export async function updateVersion (params) {
|
|
35
|
+
const [addonIdOrName] = params.args;
|
|
36
|
+
const { target } = params.options;
|
|
37
|
+
await operatorUpdateVersion('keycloak', target, addonIdOrName);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the details of a Keycloak operator
|
|
42
|
+
* @param {object} params The command's parameters
|
|
43
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
44
|
+
* @param {string} params.options.format The output format
|
|
45
|
+
* @returns {Promise<void>}
|
|
46
|
+
*/
|
|
47
|
+
export async function get (params) {
|
|
48
|
+
const [addonIdOrName] = params.args;
|
|
49
|
+
const { format } = params.options;
|
|
50
|
+
await operatorPrint('keycloak', addonIdOrName, format);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* List all Keycloak operators
|
|
55
|
+
* @returns {Promise<void>}
|
|
56
|
+
*/
|
|
57
|
+
export async function list (params) {
|
|
58
|
+
await operatorList('keycloak', params.options.format);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Unlink a Keycloak operator from a Network Group
|
|
63
|
+
* @param {object} params The command's parameters
|
|
64
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
65
|
+
* @returns {Promise<void>}
|
|
66
|
+
* @throws {Error} If the Network Group feature is already disabled
|
|
67
|
+
*/
|
|
68
|
+
export async function ngDisable (params) {
|
|
69
|
+
const [addonIdOrName] = params.args;
|
|
70
|
+
await operatorNgDisable('keycloak', addonIdOrName);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Link a Keycloak operator to a Network Group
|
|
75
|
+
* @param {object} params The command's parameters
|
|
76
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
77
|
+
* @returns {Promise<void>}
|
|
78
|
+
* @throws {Error} If the Network Group feature is already enabled
|
|
79
|
+
*/
|
|
80
|
+
export async function ngEnable (params) {
|
|
81
|
+
const [addonIdOrName] = params.args;
|
|
82
|
+
await operatorNgEnable('keycloak', addonIdOrName);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Open a Keycloak operator dashboard in the Clever Cloud Console
|
|
87
|
+
* @param {object} params The command's parameters
|
|
88
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
89
|
+
* @returns {Promise<void>}
|
|
90
|
+
*/
|
|
91
|
+
export async function open (params) {
|
|
92
|
+
const [addonIdOrName] = params.args;
|
|
93
|
+
await operatorOpen('keycloak', addonIdOrName);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Open the Logs section of a Keycloak Operator application in the Clever Cloud Console
|
|
98
|
+
* @param {object} params The command's parameters
|
|
99
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
100
|
+
* @returns {Promise<void>}
|
|
101
|
+
*/
|
|
102
|
+
export async function openLogs (params) {
|
|
103
|
+
const [addonIdOrName] = params.args;
|
|
104
|
+
await operatorOpenLogs('keycloak', addonIdOrName);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Open the Web UI of a Keycloak Operator application in the Clever Cloud Console
|
|
109
|
+
* @param {object} params The command's parameters
|
|
110
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
111
|
+
* @returns {Promise<void>}
|
|
112
|
+
*/
|
|
113
|
+
export async function openWebUi (params) {
|
|
114
|
+
const [addonIdOrName] = params.args;
|
|
115
|
+
await operatorOpenWebUi('keycloak', addonIdOrName);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Restart a Keycloak operator
|
|
120
|
+
* @param {object} params The command's parameters
|
|
121
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
122
|
+
* @returns {Promise<void>}
|
|
123
|
+
*/
|
|
124
|
+
export async function reboot (params) {
|
|
125
|
+
const [addonIdOrName] = params.args;
|
|
126
|
+
await operatorReboot('keycloak', addonIdOrName);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Rebuild a Keycloak operator
|
|
131
|
+
* @param {object} params The command's parameters
|
|
132
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
133
|
+
* @returns {Promise<void>}
|
|
134
|
+
*/
|
|
135
|
+
export async function rebuild (params) {
|
|
136
|
+
const [addonIdOrName] = params.args;
|
|
137
|
+
await operatorRebuild('keycloak', addonIdOrName);
|
|
138
|
+
}
|
package/src/commands/kv.js
CHANGED
|
@@ -2,7 +2,7 @@ import Redis from 'ioredis';
|
|
|
2
2
|
import colors from 'colors/safe.js';
|
|
3
3
|
import { Logger } from '../logger.js';
|
|
4
4
|
import { sendToApi } from '../models/send-to-api.js';
|
|
5
|
-
import { getAllEnvVars } from '@clevercloud/client/
|
|
5
|
+
import { getAllEnvVars } from '@clevercloud/client/esm/api/v2/addon.js';
|
|
6
6
|
import { findAddonsByNameOrId } from '../models/ids-resolver.js';
|
|
7
7
|
|
|
8
8
|
const URL_ENV_KEY = 'REDIS_URL';
|
package/src/commands/link.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Application from '../models/application.js';
|
|
2
2
|
import { Logger } from '../logger.js';
|
|
3
|
+
import colors from 'colors/safe.js';
|
|
3
4
|
|
|
4
5
|
export async function link (params) {
|
|
5
6
|
const [app] = params.args;
|
|
@@ -7,9 +8,12 @@ export async function link (params) {
|
|
|
7
8
|
|
|
8
9
|
if (app.app_id != null && orgaIdOrName != null) {
|
|
9
10
|
Logger.warn('You\'ve specified a unique application ID, organisation option will be ignored');
|
|
11
|
+
await Application.linkRepo(app, null, alias);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
await Application.linkRepo(app, orgaIdOrName, alias);
|
|
10
15
|
}
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Logger.println('Your application has been successfully linked!');
|
|
17
|
+
const linkedMessage = alias ? ` to local alias ${colors.green(alias)}` : '';
|
|
18
|
+
Logger.printSuccess(`Application ${colors.green(app.app_name || app.app_id)} has been successfully linked${linkedMessage}!`);
|
|
15
19
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as AppConfig from '../models/app_configuration.js';
|
|
2
2
|
import { Logger } from '../logger.js';
|
|
3
|
+
import colors from 'colors/safe.js';
|
|
3
4
|
|
|
4
5
|
export async function makeDefault (params) {
|
|
5
6
|
const [alias] = params.args;
|
|
6
7
|
|
|
7
8
|
await AppConfig.setDefault(alias);
|
|
8
9
|
|
|
9
|
-
Logger.
|
|
10
|
+
Logger.printSuccess(`The application ${colors.green(alias)} has been set as default`);
|
|
10
11
|
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {
|
|
2
|
+
operatorList,
|
|
3
|
+
operatorOpen,
|
|
4
|
+
operatorOpenLogs,
|
|
5
|
+
operatorOpenWebUi,
|
|
6
|
+
operatorPrint,
|
|
7
|
+
operatorReboot,
|
|
8
|
+
operatorRebuild,
|
|
9
|
+
} from '../lib/operator-commands.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get the details of a Matomo operator
|
|
13
|
+
* @param {object} params The command's parameters
|
|
14
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
15
|
+
* @param {string} params.options.format The output format
|
|
16
|
+
* @returns {Promise<void>}
|
|
17
|
+
*/
|
|
18
|
+
export async function get (params) {
|
|
19
|
+
const [addonIdOrName] = params.args;
|
|
20
|
+
const { format } = params.options;
|
|
21
|
+
await operatorPrint('matomo', addonIdOrName, format);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* List all Matomo operators
|
|
26
|
+
* @returns {Promise<void>}
|
|
27
|
+
*/
|
|
28
|
+
export async function list (params) {
|
|
29
|
+
await operatorList('addon-matomo', params.options.format);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Open a Matomo operator dashboard in the Clever Cloud Console
|
|
34
|
+
* @param {object} params The command's parameters
|
|
35
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
36
|
+
* @returns {Promise<void>}
|
|
37
|
+
*/
|
|
38
|
+
export async function open (params) {
|
|
39
|
+
const [addonIdOrName] = params.args;
|
|
40
|
+
await operatorOpen('matomo', addonIdOrName);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Open the Logs section of a Matomo Operator application in the Clever Cloud Console
|
|
45
|
+
* @param {object} params The command's parameters
|
|
46
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
47
|
+
* @returns {Promise<void>}
|
|
48
|
+
*/
|
|
49
|
+
export async function openLogs (params) {
|
|
50
|
+
const [addonIdOrName] = params.args;
|
|
51
|
+
await operatorOpenLogs('matomo', addonIdOrName);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Open the Web UI of a Matomo Operator application in the Clever Cloud Console
|
|
56
|
+
* @param {object} params The command's parameters
|
|
57
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
58
|
+
* @returns {Promise<void>}
|
|
59
|
+
*/
|
|
60
|
+
export async function openWebUi (params) {
|
|
61
|
+
const [addonIdOrName] = params.args;
|
|
62
|
+
await operatorOpenWebUi('matomo', addonIdOrName);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Reboot a Matomo operator
|
|
67
|
+
* @param {object} params The command's parameters
|
|
68
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
69
|
+
* @returns {Promise<void>}
|
|
70
|
+
*/
|
|
71
|
+
export async function reboot (params) {
|
|
72
|
+
const [addonIdOrName] = params.args;
|
|
73
|
+
await operatorReboot('matomo', addonIdOrName);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Rebuild a Matomo operator
|
|
78
|
+
* @param {object} params The command's parameters
|
|
79
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
80
|
+
* @returns {Promise<void>}
|
|
81
|
+
*/
|
|
82
|
+
export async function rebuild (params) {
|
|
83
|
+
const [addonIdOrName] = params.args;
|
|
84
|
+
await operatorRebuild('matomo', addonIdOrName);
|
|
85
|
+
}
|