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/diag.js
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
|
-
import os from 'node:os';
|
|
2
|
-
|
|
3
1
|
import { releaseInfo as getLinuxInfos } from 'linux-release-info';
|
|
4
|
-
import
|
|
5
|
-
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { styleText } from 'node:util';
|
|
4
|
+
import pkg from '../../package.json' with { type: 'json' };
|
|
6
5
|
import { Logger } from '../logger.js';
|
|
7
|
-
import { getPackageJson } from '../load-package-json.cjs';
|
|
8
|
-
import * as User from '../models/user.js';
|
|
9
6
|
import { conf, loadOAuthConf } from '../models/configuration.js';
|
|
7
|
+
import * as User from '../models/user.js';
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export async function diag (params) {
|
|
9
|
+
export async function diag(params) {
|
|
14
10
|
const { format } = params.options;
|
|
15
11
|
|
|
16
12
|
/** @type {string} */
|
|
17
13
|
const userId = await User.getCurrentId().catch(() => null);
|
|
18
14
|
const authDetails = await loadOAuthConf();
|
|
19
15
|
|
|
20
|
-
function getAuthState
|
|
16
|
+
function getAuthState() {
|
|
21
17
|
if (authDetails.token == null) {
|
|
22
18
|
return 'not connected';
|
|
23
19
|
}
|
|
@@ -31,6 +27,7 @@ export async function diag (params) {
|
|
|
31
27
|
|
|
32
28
|
const formattedDiag = {
|
|
33
29
|
version: pkg.version,
|
|
30
|
+
commitId: pkg.commitId,
|
|
34
31
|
nodeVersion: process.version,
|
|
35
32
|
platform: os.platform(),
|
|
36
33
|
release: os.release(),
|
|
@@ -59,35 +56,40 @@ export async function diag (params) {
|
|
|
59
56
|
}
|
|
60
57
|
case 'human':
|
|
61
58
|
default: {
|
|
62
|
-
Logger.println('clever-tools ' +
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
Logger.println('clever-tools ' + styleText('green', formattedDiag.version));
|
|
60
|
+
// Only available in built binaries
|
|
61
|
+
if (formattedDiag.commitId) {
|
|
62
|
+
Logger.println('Commit ' + styleText('green', formattedDiag.commitId));
|
|
63
|
+
}
|
|
64
|
+
Logger.println('Node.js ' + styleText('green', formattedDiag.nodeVersion));
|
|
65
|
+
Logger.println('Platform ' + styleText('green', formattedDiag.platform));
|
|
66
|
+
Logger.println('Release ' + styleText('green', formattedDiag.release));
|
|
67
|
+
Logger.println('Architecture ' + styleText('green', formattedDiag.arch));
|
|
67
68
|
if (formattedDiag.linuxInfos != null) {
|
|
68
|
-
Logger.println('Linux ' +
|
|
69
|
+
Logger.println('Linux ' + styleText('green', formattedDiag.linuxInfos));
|
|
69
70
|
}
|
|
70
|
-
Logger.println('Shell ' +
|
|
71
|
-
Logger.println('Packaged ' +
|
|
72
|
-
Logger.println('Exec path ' +
|
|
73
|
-
Logger.println('Config file ' +
|
|
71
|
+
Logger.println('Shell ' + styleText('green', formattedDiag.shell));
|
|
72
|
+
Logger.println('Packaged ' + styleText('green', String(formattedDiag.isPackaged)));
|
|
73
|
+
Logger.println('Exec path ' + styleText('green', formattedDiag.execPath));
|
|
74
|
+
Logger.println('Config file ' + styleText('green', formattedDiag.configFile));
|
|
74
75
|
|
|
75
|
-
Logger.println('Auth source ' +
|
|
76
|
+
Logger.println('Auth source ' + styleText('green', formattedDiag.authSource));
|
|
76
77
|
|
|
77
|
-
const token =
|
|
78
|
+
const token =
|
|
79
|
+
formattedDiag.oAuthToken == null ? styleText('red', '(none)') : styleText('green', formattedDiag.oAuthToken);
|
|
78
80
|
Logger.println('oAuth token ' + token);
|
|
79
81
|
|
|
80
82
|
switch (formattedDiag.authState) {
|
|
81
83
|
case 'authenticated': {
|
|
82
|
-
Logger.println('User ID ' +
|
|
84
|
+
Logger.println('User ID ' + styleText('green', formattedDiag.userId));
|
|
83
85
|
break;
|
|
84
86
|
}
|
|
85
87
|
case 'authentication failed': {
|
|
86
|
-
Logger.println('User ID ' +
|
|
88
|
+
Logger.println('User ID ' + styleText('red', 'Authentication failed'));
|
|
87
89
|
break;
|
|
88
90
|
}
|
|
89
91
|
case 'not connected': {
|
|
90
|
-
Logger.println('User ID ' +
|
|
92
|
+
Logger.println('User ID ' + styleText('red', 'Not connected'));
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
95
|
}
|
package/src/commands/domain.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import * as Application from '../models/application.js';
|
|
2
|
-
import { Logger } from '../logger.js';
|
|
3
1
|
import {
|
|
4
2
|
addDomain,
|
|
5
|
-
get as getApp,
|
|
6
3
|
getAllDomains,
|
|
4
|
+
get as getApp,
|
|
7
5
|
getFavouriteDomain as getFavouriteDomainWithError,
|
|
8
6
|
markFavouriteDomain,
|
|
9
7
|
removeDomain,
|
|
10
8
|
unmarkFavouriteDomain,
|
|
11
9
|
} from '@clevercloud/client/esm/api/v2/application.js';
|
|
12
10
|
import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
|
|
13
|
-
import {
|
|
14
|
-
import colors from 'colors/safe.js';
|
|
15
|
-
import { parse as parseDomain } from 'tldts';
|
|
11
|
+
import { getDefaultLoadBalancersDnsInfo } from '@clevercloud/client/esm/api/v4/load-balancers.js';
|
|
16
12
|
import { diagDomainConfig } from '@clevercloud/client/esm/utils/diag-domain-config.js';
|
|
17
13
|
import { sortDomains } from '@clevercloud/client/esm/utils/domains.js';
|
|
18
|
-
import { DnsResolver } from '../models/node-dns-resolver.js';
|
|
19
14
|
import _ from 'lodash';
|
|
20
|
-
import {
|
|
15
|
+
import { styleText } from 'node:util';
|
|
16
|
+
import { parse as parseDomain } from 'tldts';
|
|
17
|
+
import { Logger } from '../logger.js';
|
|
18
|
+
import * as Application from '../models/application.js';
|
|
19
|
+
import { DnsResolver } from '../models/node-dns-resolver.js';
|
|
20
|
+
import { sendToApi } from '../models/send-to-api.js';
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* @typedef {import('@clevercloud/client/esm/utils/diag-domain-config.types.js').DomainInfo} DomainInfo
|
|
@@ -25,7 +25,7 @@ import { getDefaultLoadBalancersDnsInfo } from '@clevercloud/client/esm/api/v4/l
|
|
|
25
25
|
* @typedef {import('@clevercloud/client/esm/utils/diag-domain-config.types.js').DomainDiag} DomainDiag
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
function getFavouriteDomain
|
|
28
|
+
function getFavouriteDomain({ ownerId, appId }) {
|
|
29
29
|
return getFavouriteDomainWithError({ id: ownerId, appId })
|
|
30
30
|
.then(sendToApi)
|
|
31
31
|
.then(({ fqdn }) => fqdn)
|
|
@@ -38,21 +38,19 @@ function getFavouriteDomain ({ ownerId, appId }) {
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export async function list
|
|
41
|
+
export async function list(params) {
|
|
42
42
|
const { alias, app: appIdOrName } = params.options;
|
|
43
43
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
44
44
|
|
|
45
45
|
const app = await getApp({ id: ownerId, appId }).then(sendToApi);
|
|
46
46
|
const favouriteDomain = await getFavouriteDomain({ ownerId, appId });
|
|
47
47
|
return app.vhosts.forEach(({ fqdn }) => {
|
|
48
|
-
const prefix =
|
|
49
|
-
? '* '
|
|
50
|
-
: ' ';
|
|
48
|
+
const prefix = fqdn === favouriteDomain ? '* ' : ' ';
|
|
51
49
|
Logger.println(prefix + fqdn);
|
|
52
50
|
});
|
|
53
51
|
}
|
|
54
52
|
|
|
55
|
-
export async function add
|
|
53
|
+
export async function add(params) {
|
|
56
54
|
const [fqdn] = params.args;
|
|
57
55
|
const { alias, app: appIdOrName } = params.options;
|
|
58
56
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
@@ -62,7 +60,7 @@ export async function add (params) {
|
|
|
62
60
|
Logger.println('Your domain has been successfully saved');
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
export async function getFavourite
|
|
63
|
+
export async function getFavourite(params) {
|
|
66
64
|
const { alias, app: appIdOrName } = params.options;
|
|
67
65
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
68
66
|
|
|
@@ -75,7 +73,7 @@ export async function getFavourite (params) {
|
|
|
75
73
|
return Logger.println(favouriteDomain);
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
export async function setFavourite
|
|
76
|
+
export async function setFavourite(params) {
|
|
79
77
|
const [fqdn] = params.args;
|
|
80
78
|
const { alias, app: appIdOrName } = params.options;
|
|
81
79
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
@@ -84,7 +82,7 @@ export async function setFavourite (params) {
|
|
|
84
82
|
Logger.println('Your favourite domain has been successfully set');
|
|
85
83
|
}
|
|
86
84
|
|
|
87
|
-
export async function unsetFavourite
|
|
85
|
+
export async function unsetFavourite(params) {
|
|
88
86
|
const { alias, app: appIdOrName } = params.options;
|
|
89
87
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
90
88
|
|
|
@@ -92,7 +90,7 @@ export async function unsetFavourite (params) {
|
|
|
92
90
|
Logger.println('Favourite domain has been successfully unset');
|
|
93
91
|
}
|
|
94
92
|
|
|
95
|
-
export async function rm
|
|
93
|
+
export async function rm(params) {
|
|
96
94
|
const [fqdn] = params.args;
|
|
97
95
|
const { alias, app: appIdOrName } = params.options;
|
|
98
96
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
@@ -102,7 +100,7 @@ export async function rm (params) {
|
|
|
102
100
|
Logger.println('Your domain has been successfully removed');
|
|
103
101
|
}
|
|
104
102
|
|
|
105
|
-
export async function diagApplication
|
|
103
|
+
export async function diagApplication(params) {
|
|
106
104
|
const dnsResolver = new DnsResolver();
|
|
107
105
|
const allDomainDiagnostics = [];
|
|
108
106
|
const { alias, app: appIdOrName, format, filter } = params.options;
|
|
@@ -125,14 +123,18 @@ export async function diagApplication (params) {
|
|
|
125
123
|
for (const { hostname, pathPrefix, isApex } of sortedDomains) {
|
|
126
124
|
const resolvedDnsConfig = {
|
|
127
125
|
aRecords: await dnsResolver.resolveA(hostname),
|
|
128
|
-
cnameRecords: await dnsResolver.resolveCname(hostname) ?? [],
|
|
126
|
+
cnameRecords: (await dnsResolver.resolveCname(hostname)) ?? [],
|
|
129
127
|
};
|
|
130
128
|
|
|
131
|
-
const diagnosticResults = diagDomainConfig(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
const diagnosticResults = diagDomainConfig(
|
|
130
|
+
{
|
|
131
|
+
hostname,
|
|
132
|
+
pathPrefix,
|
|
133
|
+
isApex,
|
|
134
|
+
},
|
|
135
|
+
resolvedDnsConfig,
|
|
136
|
+
loadBalancerDnsConfig,
|
|
137
|
+
);
|
|
136
138
|
allDomainDiagnostics.push({ ...diagnosticResults, resolvedDnsConfig });
|
|
137
139
|
|
|
138
140
|
if (diagnosticResults.diagSummary === 'invalid' || diagnosticResults.diagSummary === 'no-config') {
|
|
@@ -162,8 +164,7 @@ export async function diagApplication (params) {
|
|
|
162
164
|
}
|
|
163
165
|
}
|
|
164
166
|
|
|
165
|
-
export async function overview
|
|
166
|
-
|
|
167
|
+
export async function overview(params) {
|
|
167
168
|
const { format, filter } = params.options;
|
|
168
169
|
|
|
169
170
|
const summary = await getSummary().then(sendToApi);
|
|
@@ -196,39 +197,40 @@ export async function overview (params) {
|
|
|
196
197
|
}),
|
|
197
198
|
);
|
|
198
199
|
|
|
199
|
-
const applicationsWithParsedDomain = applicationsWithDomains
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
propertyPath.push(pathname);
|
|
219
|
-
|
|
220
|
-
return {
|
|
221
|
-
ownerId: app.ownerId,
|
|
222
|
-
ownerName: app.ownerName,
|
|
223
|
-
appId: app.id,
|
|
224
|
-
appName: app.name,
|
|
225
|
-
appConsoleUrl: `${consoleUrl}/goto/${app.id}`,
|
|
226
|
-
appVariantSlug: app.variantSlug,
|
|
227
|
-
domain: domain.fqdn,
|
|
228
|
-
propetyPath: propertyPath,
|
|
229
|
-
};
|
|
200
|
+
const applicationsWithParsedDomain = applicationsWithDomains.flatMap(({ app, domains }) => {
|
|
201
|
+
return domains
|
|
202
|
+
.filter((domain) => filter == null || domain.fqdn.includes(filter))
|
|
203
|
+
.map((domain) => {
|
|
204
|
+
// `validateHostname` is set to `false` so that wildcard domains may be parsed correctly
|
|
205
|
+
const parsedDomain = parseDomain(domain.fqdn, { validateHostname: false });
|
|
206
|
+
const pathname = new URL('https://' + domain.fqdn).pathname;
|
|
207
|
+
const subdomains = parsedDomain.subdomain !== '' ? parsedDomain.subdomain.split('.') : [];
|
|
208
|
+
|
|
209
|
+
// We're trying to create a propertyPath for lodash to create a tree structure object,
|
|
210
|
+
// the propertyPath for `aaa.bbb.ccc.example.com/the-path` would be:
|
|
211
|
+
// ["example.com", "example.com.ccc", "example.com.ccc.bbb", "example.com.ccc.bbb.aaa", "/path-aaa"]",
|
|
212
|
+
|
|
213
|
+
const sortSegments = [parsedDomain.domain, ...subdomains.reverse()];
|
|
214
|
+
const propertyPath = sortSegments.map((item, i, all) => {
|
|
215
|
+
return all
|
|
216
|
+
.slice(0, i + 1)
|
|
217
|
+
.reverse()
|
|
218
|
+
.join('.');
|
|
230
219
|
});
|
|
231
|
-
|
|
220
|
+
propertyPath.push(pathname);
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
ownerId: app.ownerId,
|
|
224
|
+
ownerName: app.ownerName,
|
|
225
|
+
appId: app.id,
|
|
226
|
+
appName: app.name,
|
|
227
|
+
appConsoleUrl: `${consoleUrl}/goto/${app.id}`,
|
|
228
|
+
appVariantSlug: app.variantSlug,
|
|
229
|
+
domain: domain.fqdn,
|
|
230
|
+
propetyPath: propertyPath,
|
|
231
|
+
};
|
|
232
|
+
});
|
|
233
|
+
});
|
|
232
234
|
|
|
233
235
|
const applicationsWithParsedDomainAsTree = {};
|
|
234
236
|
for (const { propetyPath, ...appWithDomain } of applicationsWithParsedDomain) {
|
|
@@ -246,12 +248,10 @@ export async function overview (params) {
|
|
|
246
248
|
if (Object.keys(applicationsWithParsedDomainAsSortedTree).length === 0) {
|
|
247
249
|
if (filter?.length > 0) {
|
|
248
250
|
Logger.println(`No matches for filter "${filter}"`);
|
|
249
|
-
}
|
|
250
|
-
else {
|
|
251
|
+
} else {
|
|
251
252
|
Logger.println('No domains');
|
|
252
253
|
}
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
254
|
+
} else {
|
|
255
255
|
recursiveDisplay(applicationsWithParsedDomainAsSortedTree);
|
|
256
256
|
}
|
|
257
257
|
break;
|
|
@@ -259,8 +259,7 @@ export async function overview (params) {
|
|
|
259
259
|
}
|
|
260
260
|
|
|
261
261
|
/** @param {DomainDiag & { resolvedDnsConfig: ResolveDnsResult }} domainDiag */
|
|
262
|
-
function reportDomainDiagnostics
|
|
263
|
-
|
|
262
|
+
function reportDomainDiagnostics({ hostname, pathPrefix, resolvedDnsConfig, diagDetails, diagSummary }) {
|
|
264
263
|
const validDiags = diagDetails.filter((diag) => diag.code === 'valid-a');
|
|
265
264
|
const unknownDiags = diagDetails.filter((diag) => diag.code === 'unknown-a');
|
|
266
265
|
const missingDiags = diagDetails.filter((diag) => diag.code === 'missing-a');
|
|
@@ -271,24 +270,24 @@ function reportDomainDiagnostics ({ hostname, pathPrefix, resolvedDnsConfig, dia
|
|
|
271
270
|
const hasARecords = resolvedDnsConfig.aRecords.length > 0;
|
|
272
271
|
const hasCnameRecord = resolvedDnsConfig.cnameRecords.length > 0;
|
|
273
272
|
|
|
274
|
-
Logger.println('\n' +
|
|
273
|
+
Logger.println('\n' + styleText('blue', hostname) + styleText('yellow', pathPrefix) + '\n');
|
|
275
274
|
|
|
276
275
|
switch (diagSummary) {
|
|
277
276
|
case 'managed':
|
|
278
|
-
printlnWithIndent(
|
|
277
|
+
printlnWithIndent(styleText('green', '✔ Managed by Clever Cloud'), 2);
|
|
279
278
|
printlnWithIndent('ⓘ cleverapps.io domains should only be used for testing purposes', 2);
|
|
280
279
|
break;
|
|
281
280
|
case 'no-config':
|
|
282
|
-
printlnWithIndent(
|
|
281
|
+
printlnWithIndent(styleText('red', '✘ No DNS configuration found'), 2);
|
|
283
282
|
break;
|
|
284
283
|
case 'valid':
|
|
285
|
-
printlnWithIndent(
|
|
284
|
+
printlnWithIndent(styleText('green', '✔ Your configuration is valid'), 2);
|
|
286
285
|
break;
|
|
287
286
|
case 'invalid':
|
|
288
|
-
printlnWithIndent(
|
|
287
|
+
printlnWithIndent(styleText('red', '✘ Something is wrong with your configuration'), 2);
|
|
289
288
|
break;
|
|
290
289
|
case 'incomplete':
|
|
291
|
-
printlnWithIndent(
|
|
290
|
+
printlnWithIndent(styleText('yellow', '⚠ Your configuration is incomplete'), 2);
|
|
292
291
|
break;
|
|
293
292
|
}
|
|
294
293
|
|
|
@@ -297,7 +296,7 @@ function reportDomainDiagnostics ({ hostname, pathPrefix, resolvedDnsConfig, dia
|
|
|
297
296
|
Logger.println('');
|
|
298
297
|
validDiags.forEach((diag) => {
|
|
299
298
|
const source = hasCnameRecord ? `(from CNAME ${resolvedDnsConfig.cnameRecords[0]}.)` : '';
|
|
300
|
-
printlnWithIndent(`${diag.record.value} ${
|
|
299
|
+
printlnWithIndent(`${diag.record.value} ${styleText('green', '✔ A Record OK')} ${source}`, 2);
|
|
301
300
|
});
|
|
302
301
|
}
|
|
303
302
|
|
|
@@ -320,7 +319,7 @@ function reportDomainDiagnostics ({ hostname, pathPrefix, resolvedDnsConfig, dia
|
|
|
320
319
|
}
|
|
321
320
|
|
|
322
321
|
// Replace unknown CNAME with missing CNAME
|
|
323
|
-
if (
|
|
322
|
+
if (diagSummary === 'invalid' && missingCname != null && unknownCname != null) {
|
|
324
323
|
Logger.println('');
|
|
325
324
|
printlnWithIndent('➖Remove this CNAME record:', 2);
|
|
326
325
|
printlnWithIndent(unknownCname.record.value + '. ', 6);
|
|
@@ -367,7 +366,7 @@ function reportDomainDiagnostics ({ hostname, pathPrefix, resolvedDnsConfig, dia
|
|
|
367
366
|
* @param {Array<{ fqdn: string }>} vhosts
|
|
368
367
|
* @returns {Array<Partial<DomainInfo>>} Array of parsed domain objects
|
|
369
368
|
*/
|
|
370
|
-
function getParsedDomains
|
|
369
|
+
function getParsedDomains(vhosts) {
|
|
371
370
|
return vhosts.map(({ fqdn }) => {
|
|
372
371
|
const { hostname, pathname } = new URL('https://' + fqdn);
|
|
373
372
|
const { subdomain } = parseDomain(fqdn);
|
|
@@ -382,44 +381,43 @@ function getParsedDomains (vhosts) {
|
|
|
382
381
|
* @param {string} text - The text to be printed.
|
|
383
382
|
* @param {number} indentLevel - The number of spaces to indent the text.
|
|
384
383
|
*/
|
|
385
|
-
function printlnWithIndent
|
|
384
|
+
function printlnWithIndent(text, indentLevel) {
|
|
386
385
|
Logger.println(' '.repeat(indentLevel) + text);
|
|
387
386
|
}
|
|
388
387
|
|
|
389
|
-
function recursiveSort
|
|
390
|
-
|
|
388
|
+
function recursiveSort(obj) {
|
|
391
389
|
if (typeof obj === 'object' && obj.appId != null) {
|
|
392
390
|
return obj;
|
|
393
391
|
}
|
|
394
392
|
|
|
395
393
|
const sortedObj = {};
|
|
396
|
-
Object.keys(obj)
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
394
|
+
Object.keys(obj)
|
|
395
|
+
.sort((a, b) => {
|
|
396
|
+
// if the domain contains a wildcard, we want it to be the first of subdomains
|
|
397
|
+
const aWithReplacedWildcard = a.replace(/^\*/, 'a');
|
|
398
|
+
const bWithReplacedWildcard = b.replace(/^\*/, 'a');
|
|
399
|
+
return aWithReplacedWildcard.localeCompare(bWithReplacedWildcard);
|
|
400
|
+
})
|
|
401
|
+
.forEach((key) => {
|
|
402
|
+
sortedObj[key] = recursiveSort(obj[key]);
|
|
403
|
+
});
|
|
404
404
|
|
|
405
405
|
return sortedObj;
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
-
function recursiveDisplay
|
|
409
|
-
|
|
408
|
+
function recursiveDisplay(obj, indentLevel = 0) {
|
|
410
409
|
if (typeof obj === 'object' && obj.appId != null) {
|
|
411
410
|
printlnWithIndent(`${obj.ownerName} | ${obj.appName} (${obj.appVariantSlug})`, indentLevel);
|
|
412
|
-
printlnWithIndent(
|
|
411
|
+
printlnWithIndent(styleText('blue', obj.appConsoleUrl), indentLevel);
|
|
413
412
|
return;
|
|
414
413
|
}
|
|
415
414
|
|
|
416
415
|
for (const [propertyPath, subObj] of Object.entries(obj)) {
|
|
417
416
|
if (propertyPath !== '/') {
|
|
418
417
|
Logger.println('');
|
|
419
|
-
printlnWithIndent(
|
|
418
|
+
printlnWithIndent(styleText('yellow', propertyPath), indentLevel);
|
|
420
419
|
recursiveDisplay(subObj, indentLevel + 2);
|
|
421
|
-
}
|
|
422
|
-
else {
|
|
420
|
+
} else {
|
|
423
421
|
recursiveDisplay(subObj, indentLevel);
|
|
424
422
|
}
|
|
425
423
|
}
|
package/src/commands/drain.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
+
import { createDrain, deleteDrain, getDrains, updateDrainState } from '@clevercloud/client/esm/api/v2/log.js';
|
|
2
|
+
import { Logger } from '../logger.js';
|
|
1
3
|
import * as Application from '../models/application.js';
|
|
2
4
|
import { createDrainBody } from '../models/drain.js';
|
|
3
|
-
import { Logger } from '../logger.js';
|
|
4
|
-
|
|
5
|
-
import { getDrains, createDrain, deleteDrain, updateDrainState } from '@clevercloud/client/esm/api/v2/log.js';
|
|
6
5
|
import { sendToApi } from '../models/send-to-api.js';
|
|
7
6
|
|
|
8
7
|
// TODO: This could be useful in other commands
|
|
9
|
-
async function getAppOrAddonId
|
|
10
|
-
return
|
|
11
|
-
? addonId
|
|
12
|
-
: await Application.resolveId(appIdOrName, alias).then(({ appId }) => appId);
|
|
8
|
+
async function getAppOrAddonId({ alias, appIdOrName, addonId }) {
|
|
9
|
+
return addonId != null ? addonId : await Application.resolveId(appIdOrName, alias).then(({ appId }) => appId);
|
|
13
10
|
}
|
|
14
11
|
|
|
15
|
-
export async function list
|
|
12
|
+
export async function list(params) {
|
|
16
13
|
const { alias, app: appIdOrName, addon: addonId, format } = params.options;
|
|
17
14
|
|
|
18
15
|
const appIdOrAddonId = await getAppOrAddonId({ alias, appIdOrName, addonId });
|
|
@@ -52,20 +49,35 @@ export async function list (params) {
|
|
|
52
49
|
}
|
|
53
50
|
}
|
|
54
51
|
|
|
55
|
-
export async function create
|
|
52
|
+
export async function create(params) {
|
|
56
53
|
const [drainTargetType, drainTargetURL] = params.args;
|
|
57
|
-
const {
|
|
54
|
+
const {
|
|
55
|
+
alias,
|
|
56
|
+
app: appIdOrName,
|
|
57
|
+
addon: addonId,
|
|
58
|
+
username,
|
|
59
|
+
password,
|
|
60
|
+
'api-key': apiKey,
|
|
61
|
+
'index-prefix': indexPrefix,
|
|
62
|
+
'sd-params': structuredDataParameters,
|
|
63
|
+
} = params.options;
|
|
58
64
|
const drainTargetCredentials = { username, password };
|
|
59
65
|
const drainTargetConfig = { apiKey, indexPrefix, structuredDataParameters };
|
|
60
66
|
|
|
61
67
|
const appIdOrAddonId = await getAppOrAddonId({ alias, appIdOrName, addonId });
|
|
62
|
-
const body = createDrainBody(
|
|
68
|
+
const body = createDrainBody(
|
|
69
|
+
appIdOrAddonId,
|
|
70
|
+
drainTargetURL,
|
|
71
|
+
drainTargetType,
|
|
72
|
+
drainTargetCredentials,
|
|
73
|
+
drainTargetConfig,
|
|
74
|
+
);
|
|
63
75
|
await createDrain({ appId: appIdOrAddonId }, body).then(sendToApi);
|
|
64
76
|
|
|
65
77
|
Logger.println('Your drain has been successfully saved');
|
|
66
78
|
}
|
|
67
79
|
|
|
68
|
-
export async function rm
|
|
80
|
+
export async function rm(params) {
|
|
69
81
|
const [drainId] = params.args;
|
|
70
82
|
const { alias, app: appIdOrName, addon: addonId } = params.options;
|
|
71
83
|
|
|
@@ -75,7 +87,7 @@ export async function rm (params) {
|
|
|
75
87
|
Logger.println('Your drain has been successfully removed');
|
|
76
88
|
}
|
|
77
89
|
|
|
78
|
-
export async function enable
|
|
90
|
+
export async function enable(params) {
|
|
79
91
|
const [drainId] = params.args;
|
|
80
92
|
const { alias, app: appIdOrName, addon: addonId } = params.options;
|
|
81
93
|
|
|
@@ -85,7 +97,7 @@ export async function enable (params) {
|
|
|
85
97
|
Logger.println('Your drain has been enabled');
|
|
86
98
|
}
|
|
87
99
|
|
|
88
|
-
export async function disable
|
|
100
|
+
export async function disable(params) {
|
|
89
101
|
const [drainId] = params.args;
|
|
90
102
|
const { alias, app: appIdOrName, addon: addonId } = params.options;
|
|
91
103
|
|