clever-tools 3.13.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -37
- package/bin/clever.js +1427 -718
- package/package.json +62 -77
- package/src/clever-client/auth-bridge.js +9 -12
- package/src/clever-client/ng.js +1 -1
- package/src/clever-client/operators.js +7 -7
- package/src/command-options.js +6 -6
- package/src/command-promise-handler.js +6 -6
- package/src/commands/accesslogs.js +38 -29
- package/src/commands/activity.js +62 -40
- package/src/commands/addon.js +65 -69
- package/src/commands/applications.js +33 -31
- package/src/commands/cancel-deploy.js +7 -7
- package/src/commands/config.js +9 -7
- package/src/commands/console.js +3 -3
- package/src/commands/create.js +33 -32
- package/src/commands/curl.js +14 -36
- package/src/commands/database.js +10 -30
- package/src/commands/delete.js +8 -8
- package/src/commands/deploy.js +60 -46
- package/src/commands/diag.js +27 -25
- package/src/commands/domain.js +89 -91
- package/src/commands/drain.js +26 -14
- package/src/commands/emails.js +24 -28
- package/src/commands/env.js +18 -18
- package/src/commands/features.js +12 -18
- package/src/commands/keycloak.js +11 -11
- package/src/commands/kv.js +13 -13
- package/src/commands/link.js +9 -8
- package/src/commands/login.js +19 -27
- package/src/commands/logout.js +1 -1
- package/src/commands/logs.js +20 -12
- package/src/commands/makeDefault.js +5 -5
- package/src/commands/matomo.js +7 -7
- package/src/commands/metabase.js +9 -9
- package/src/commands/ng.js +32 -32
- package/src/commands/notify-email.js +11 -15
- package/src/commands/open.js +1 -1
- package/src/commands/otoroshi.js +11 -11
- package/src/commands/profile.js +8 -8
- package/src/commands/published-config.js +11 -11
- package/src/commands/restart.js +15 -8
- package/src/commands/scale.js +25 -16
- package/src/commands/service.js +28 -11
- package/src/commands/ssh-keys.js +25 -29
- package/src/commands/ssh.js +1 -2
- package/src/commands/status.js +31 -22
- package/src/commands/stop.js +3 -3
- package/src/commands/tcp-redirs.js +27 -26
- package/src/commands/tokens.js +44 -43
- package/src/commands/unlink.js +7 -5
- package/src/commands/version.js +2 -4
- package/src/commands/webhooks.js +8 -10
- package/src/experimental-features.js +7 -5
- package/src/format-table.js +46 -15
- package/src/initial-setup.js +2 -32
- package/src/initial-update-notifier.js +18 -0
- package/src/lib/has-param.js +16 -0
- package/src/lib/ng-print.js +21 -24
- package/src/lib/operator-commands.js +58 -53
- package/src/lib/prompts.js +5 -5
- package/src/lib/slugify.js +1 -1
- package/src/logger.js +26 -21
- package/src/models/activity.js +3 -3
- package/src/models/addon.js +54 -56
- package/src/models/app_configuration.js +34 -32
- package/src/models/application.js +90 -77
- package/src/models/application_configuration.js +19 -27
- package/src/models/configuration.js +30 -32
- package/src/models/deployments.js +9 -19
- package/src/models/domain.js +10 -9
- package/src/models/drain.js +16 -15
- package/src/models/exit-strategy-option.js +15 -5
- package/src/models/fs-utils.js +4 -3
- package/src/models/git.js +26 -32
- package/src/models/ids-resolver.js +37 -41
- package/src/models/isomorphic-http-with-agent.js +3 -3
- package/src/models/json-array.js +5 -6
- package/src/models/log-v4.js +44 -52
- package/src/models/log.js +40 -45
- package/src/models/namespaces.js +4 -4
- package/src/models/ng-resources.js +49 -39
- package/src/models/ng.js +41 -40
- package/src/models/node-dns-resolver.js +3 -3
- package/src/models/notification.js +7 -10
- package/src/models/operator.js +8 -10
- package/src/models/organisation.js +5 -8
- package/src/models/send-to-api.js +18 -11
- package/src/models/user.js +6 -5
- package/src/models/utils.js +5 -8
- package/src/models/variables.js +18 -20
- package/src/parsers.js +34 -34
- package/src/load-package-json.cjs +0 -5
|
@@ -1,57 +1,77 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import {
|
|
3
2
|
addDependency,
|
|
4
3
|
create as createApplication,
|
|
5
|
-
get as getApplication,
|
|
6
4
|
getAll as getAllApplications,
|
|
7
5
|
getAllDependencies,
|
|
6
|
+
get as getApplication,
|
|
8
7
|
redeploy as redeployApplication,
|
|
9
8
|
remove as removeApplication,
|
|
10
9
|
removeDependency,
|
|
11
10
|
update as updateApplication,
|
|
12
11
|
} from '@clevercloud/client/esm/api/v2/application.js';
|
|
13
|
-
import
|
|
12
|
+
import { getAvailableInstances } from '@clevercloud/client/esm/api/v2/product.js';
|
|
14
13
|
import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
|
|
15
|
-
import
|
|
16
|
-
|
|
17
|
-
import
|
|
14
|
+
import cliparse from 'cliparse';
|
|
15
|
+
import _ from 'lodash';
|
|
16
|
+
import { styleText } from 'node:util';
|
|
18
17
|
import { confirmAnswer } from '../lib/prompts.js';
|
|
19
18
|
import { Logger } from '../logger.js';
|
|
19
|
+
import * as AppConfiguration from './app_configuration.js';
|
|
20
|
+
import { resolveOwnerId } from './ids-resolver.js';
|
|
20
21
|
import * as Organisation from './organisation.js';
|
|
22
|
+
import { sendToApi } from './send-to-api.js';
|
|
21
23
|
import * as User from './user.js';
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
export function listAvailableTypes() {
|
|
26
|
+
return cliparse.autocomplete.words([
|
|
27
|
+
'docker',
|
|
28
|
+
'elixir',
|
|
29
|
+
'frankenphp',
|
|
30
|
+
'go',
|
|
31
|
+
'gradle',
|
|
32
|
+
'haskell',
|
|
33
|
+
'jar',
|
|
34
|
+
'linux',
|
|
35
|
+
'maven',
|
|
36
|
+
'meteor',
|
|
37
|
+
'node',
|
|
38
|
+
'php',
|
|
39
|
+
'play1',
|
|
40
|
+
'play2',
|
|
41
|
+
'python',
|
|
42
|
+
'ruby',
|
|
43
|
+
'rust',
|
|
44
|
+
'sbt',
|
|
45
|
+
'static',
|
|
46
|
+
'static-apache',
|
|
47
|
+
'v',
|
|
48
|
+
'war',
|
|
49
|
+
]);
|
|
50
|
+
}
|
|
30
51
|
|
|
31
52
|
export const AVAILABLE_ZONES = ['par', 'parhds', 'grahds', 'rbx', 'rbxhds', 'scw', 'ldn', 'mtl', 'sgp', 'syd', 'wsw'];
|
|
32
53
|
|
|
33
|
-
export function listAvailableZones
|
|
54
|
+
export function listAvailableZones() {
|
|
34
55
|
return cliparse.autocomplete.words(AVAILABLE_ZONES);
|
|
35
|
-
}
|
|
56
|
+
}
|
|
36
57
|
|
|
37
|
-
export function listAvailableAliases
|
|
58
|
+
export function listAvailableAliases() {
|
|
38
59
|
return AppConfiguration.loadApplicationConf().then(({ apps }) => cliparse.autocomplete.words(_.map(apps, 'alias')));
|
|
39
|
-
}
|
|
60
|
+
}
|
|
40
61
|
|
|
41
|
-
export function listAvailableFlavors
|
|
62
|
+
export function listAvailableFlavors() {
|
|
42
63
|
return ['pico', 'nano', 'XS', 'S', 'M', 'L', 'XL', '2XL', '3XL'];
|
|
43
|
-
}
|
|
64
|
+
}
|
|
44
65
|
|
|
45
|
-
async function getId
|
|
66
|
+
async function getId(ownerId, dependency) {
|
|
46
67
|
if (dependency.app_id) {
|
|
47
68
|
return dependency.app_id;
|
|
48
69
|
}
|
|
49
70
|
const app = await getByName(ownerId, dependency.app_name);
|
|
50
71
|
return app.id;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function getInstanceType (type) {
|
|
72
|
+
}
|
|
54
73
|
|
|
74
|
+
async function getInstanceType(type) {
|
|
55
75
|
// TODO: We should be able to use it without {}
|
|
56
76
|
const types = await getAvailableInstances({}).then(sendToApi);
|
|
57
77
|
|
|
@@ -62,14 +82,12 @@ async function getInstanceType (type) {
|
|
|
62
82
|
throw new Error(type + ' type does not exist.');
|
|
63
83
|
}
|
|
64
84
|
return instanceVariant;
|
|
65
|
-
}
|
|
85
|
+
}
|
|
66
86
|
|
|
67
|
-
export async function create
|
|
87
|
+
export async function create(name, typeName, region, orgaIdOrName, github, isTask, envVars) {
|
|
68
88
|
Logger.debug('Create the application…');
|
|
69
89
|
|
|
70
|
-
const ownerId =
|
|
71
|
-
? await Organisation.getId(orgaIdOrName)
|
|
72
|
-
: await User.getCurrentId();
|
|
90
|
+
const ownerId = orgaIdOrName != null ? await Organisation.getId(orgaIdOrName) : await User.getCurrentId();
|
|
73
91
|
|
|
74
92
|
const instanceType = await getInstanceType(typeName);
|
|
75
93
|
|
|
@@ -95,24 +113,23 @@ export async function create (name, typeName, region, orgaIdOrName, github, isTa
|
|
|
95
113
|
}
|
|
96
114
|
|
|
97
115
|
return createApplication({ id: ownerId }, newApp).then(sendToApi);
|
|
98
|
-
}
|
|
116
|
+
}
|
|
99
117
|
|
|
100
|
-
export async function deleteApp
|
|
118
|
+
export async function deleteApp(app, skipConfirmation) {
|
|
101
119
|
Logger.debug('Deleting app: ' + app.name + ' (' + app.id + ')');
|
|
102
120
|
|
|
103
121
|
if (!skipConfirmation) {
|
|
104
122
|
await confirmAnswer(
|
|
105
|
-
`Deleting an application can't be undone, please type ${
|
|
123
|
+
`Deleting an application can't be undone, please type ${styleText('green', app.name)} to confirm:`,
|
|
106
124
|
'No confirmation, aborting application deletion',
|
|
107
125
|
app.name,
|
|
108
126
|
);
|
|
109
127
|
}
|
|
110
128
|
|
|
111
129
|
return removeApplication({ id: app.ownerId, appId: app.id }).then(sendToApi);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export async function getAllApps (ownerId) {
|
|
130
|
+
}
|
|
115
131
|
|
|
132
|
+
export async function getAllApps(ownerId) {
|
|
116
133
|
const summary = await getSummary().then(sendToApi);
|
|
117
134
|
|
|
118
135
|
const orgaWithApps = await Promise.all(
|
|
@@ -131,9 +148,9 @@ export async function getAllApps (ownerId) {
|
|
|
131
148
|
);
|
|
132
149
|
|
|
133
150
|
return orgaWithApps;
|
|
134
|
-
}
|
|
151
|
+
}
|
|
135
152
|
|
|
136
|
-
async function getApplicationsForOwner
|
|
153
|
+
async function getApplicationsForOwner(ownerId) {
|
|
137
154
|
const rawApplications = await getAllApplications({ id: ownerId }).then(sendToApi);
|
|
138
155
|
return rawApplications.map((app) => {
|
|
139
156
|
return {
|
|
@@ -149,52 +166,51 @@ async function getApplicationsForOwner (ownerId) {
|
|
|
149
166
|
});
|
|
150
167
|
}
|
|
151
168
|
|
|
152
|
-
function getApplicationByName
|
|
169
|
+
function getApplicationByName(apps, name) {
|
|
153
170
|
const filteredApps = apps.filter((app) => app.name === name);
|
|
154
171
|
if (filteredApps.length === 1) {
|
|
155
172
|
return filteredApps[0];
|
|
156
|
-
}
|
|
157
|
-
else if (filteredApps.length === 0) {
|
|
173
|
+
} else if (filteredApps.length === 0) {
|
|
158
174
|
throw new Error('Application not found');
|
|
159
175
|
}
|
|
160
176
|
throw new Error('Ambiguous application name');
|
|
161
|
-
}
|
|
177
|
+
}
|
|
162
178
|
|
|
163
|
-
async function getByName
|
|
179
|
+
async function getByName(ownerId, name) {
|
|
164
180
|
const apps = await getAllApplications({ id: ownerId }).then(sendToApi);
|
|
165
181
|
return getApplicationByName(apps, name);
|
|
166
|
-
}
|
|
182
|
+
}
|
|
167
183
|
|
|
168
|
-
function addInstanceLifetime
|
|
184
|
+
function addInstanceLifetime(app) {
|
|
169
185
|
// Patch to help config commands
|
|
170
186
|
app.instanceLifetime = app.instance.lifetime;
|
|
171
187
|
return app;
|
|
172
188
|
}
|
|
173
189
|
|
|
174
|
-
export function get
|
|
190
|
+
export function get(ownerId, appId) {
|
|
175
191
|
Logger.debug(`Get information for the app: ${appId}`);
|
|
176
192
|
return getApplication({ id: ownerId, appId }).then(sendToApi).then(addInstanceLifetime);
|
|
177
|
-
}
|
|
193
|
+
}
|
|
178
194
|
|
|
179
|
-
export function updateOptions
|
|
195
|
+
export function updateOptions(ownerId, appId, options) {
|
|
180
196
|
Logger.debug(`Update app: ${appId}`);
|
|
181
197
|
return updateApplication({ id: ownerId, appId }, options).then(sendToApi).then(addInstanceLifetime);
|
|
182
|
-
}
|
|
198
|
+
}
|
|
183
199
|
|
|
184
|
-
function getFromSelf
|
|
200
|
+
function getFromSelf(appId) {
|
|
185
201
|
Logger.debug(`Get information for the app: ${appId}`);
|
|
186
202
|
// /self differs from /organisations only for this one:
|
|
187
203
|
// it fallbacks to the organisations of which the user
|
|
188
204
|
// is a member, if it doesn't belong to Personal Space.
|
|
189
205
|
return getApplication({ appId }).then(sendToApi);
|
|
190
|
-
}
|
|
206
|
+
}
|
|
191
207
|
|
|
192
208
|
/**
|
|
193
209
|
* @param {{app_id: string}|{app_name: string}} appIdOrName
|
|
194
210
|
* @param {string} alias
|
|
195
211
|
* @return {Promise<{appId: string, ownerId: string}>}
|
|
196
212
|
*/
|
|
197
|
-
export async function resolveId
|
|
213
|
+
export async function resolveId(appIdOrName, alias) {
|
|
198
214
|
if (appIdOrName != null && alias != null) {
|
|
199
215
|
throw new Error('Only one of the `--app` or `--alias` options can be set at a time');
|
|
200
216
|
}
|
|
@@ -245,32 +261,28 @@ export async function resolveId (appIdOrName, alias) {
|
|
|
245
261
|
throw new Error('Ambiguous application name, use the `--app` option with one of the IDs above');
|
|
246
262
|
}
|
|
247
263
|
|
|
248
|
-
export async function linkRepo
|
|
264
|
+
export async function linkRepo(app, orgaIdOrName, alias, ignoreParentConfig) {
|
|
249
265
|
Logger.debug(`Linking current repository to the app: ${app.app_id || app.app_name}`);
|
|
250
266
|
|
|
251
|
-
const ownerId =
|
|
252
|
-
? await Organisation.getId(orgaIdOrName)
|
|
253
|
-
: await User.getCurrentId();
|
|
267
|
+
const ownerId = orgaIdOrName != null ? await Organisation.getId(orgaIdOrName) : await User.getCurrentId();
|
|
254
268
|
|
|
255
|
-
const appData =
|
|
256
|
-
? await getFromSelf(app.app_id)
|
|
257
|
-
: await getByName(ownerId, app.app_name);
|
|
269
|
+
const appData = app.app_id != null ? await getFromSelf(app.app_id) : await getByName(ownerId, app.app_name);
|
|
258
270
|
|
|
259
271
|
return AppConfiguration.addLinkedApplication(appData, alias, ignoreParentConfig);
|
|
260
|
-
}
|
|
272
|
+
}
|
|
261
273
|
|
|
262
|
-
export function unlinkRepo
|
|
274
|
+
export function unlinkRepo(alias) {
|
|
263
275
|
Logger.debug(`Unlinking current repository from the app: ${alias}`);
|
|
264
276
|
return AppConfiguration.removeLinkedApplication({ alias });
|
|
265
|
-
}
|
|
277
|
+
}
|
|
266
278
|
|
|
267
|
-
export function redeploy
|
|
279
|
+
export function redeploy(ownerId, appId, commit, withoutCache) {
|
|
268
280
|
Logger.debug(`Redeploying the app: ${appId}`);
|
|
269
|
-
const useCache =
|
|
281
|
+
const useCache = withoutCache ? 'no' : null;
|
|
270
282
|
return redeployApplication({ id: ownerId, appId, commit, useCache }).then(sendToApi);
|
|
271
|
-
}
|
|
283
|
+
}
|
|
272
284
|
|
|
273
|
-
export function mergeScalabilityParameters
|
|
285
|
+
export function mergeScalabilityParameters(scalabilityParameters, instance) {
|
|
274
286
|
const flavors = listAvailableFlavors();
|
|
275
287
|
|
|
276
288
|
if (scalabilityParameters.minFlavor) {
|
|
@@ -281,8 +293,10 @@ export function mergeScalabilityParameters (scalabilityParameters, instance) {
|
|
|
281
293
|
}
|
|
282
294
|
if (scalabilityParameters.maxFlavor) {
|
|
283
295
|
instance.maxFlavor = scalabilityParameters.maxFlavor;
|
|
284
|
-
if (
|
|
285
|
-
|
|
296
|
+
if (
|
|
297
|
+
flavors.indexOf(instance.minFlavor) > flavors.indexOf(instance.maxFlavor) &&
|
|
298
|
+
scalabilityParameters.minFlavor == null
|
|
299
|
+
) {
|
|
286
300
|
instance.minFlavor = instance.maxFlavor;
|
|
287
301
|
}
|
|
288
302
|
}
|
|
@@ -300,9 +314,9 @@ export function mergeScalabilityParameters (scalabilityParameters, instance) {
|
|
|
300
314
|
}
|
|
301
315
|
}
|
|
302
316
|
return instance;
|
|
303
|
-
}
|
|
317
|
+
}
|
|
304
318
|
|
|
305
|
-
export async function setScalability
|
|
319
|
+
export async function setScalability(appId, ownerId, scalabilityParameters, buildFlavor) {
|
|
306
320
|
Logger.info('Scaling the app: ' + appId);
|
|
307
321
|
|
|
308
322
|
const app = await getApplication({ id: ownerId, appId }).then(sendToApi);
|
|
@@ -314,19 +328,18 @@ export async function setScalability (appId, ownerId, scalabilityParameters, bui
|
|
|
314
328
|
const newConfig = mergeScalabilityParameters(scalabilityParameters, instance);
|
|
315
329
|
|
|
316
330
|
if (buildFlavor != null) {
|
|
317
|
-
newConfig.separateBuild =
|
|
331
|
+
newConfig.separateBuild = buildFlavor !== 'disabled';
|
|
318
332
|
if (buildFlavor !== 'disabled') {
|
|
319
333
|
newConfig.buildFlavor = buildFlavor;
|
|
320
|
-
}
|
|
321
|
-
else {
|
|
334
|
+
} else {
|
|
322
335
|
Logger.info('No build size given, disabling dedicated build instance');
|
|
323
336
|
}
|
|
324
337
|
}
|
|
325
338
|
|
|
326
339
|
return updateApplication({ id: ownerId, appId }, newConfig).then(sendToApi);
|
|
327
|
-
}
|
|
340
|
+
}
|
|
328
341
|
|
|
329
|
-
export async function listDependencies
|
|
342
|
+
export async function listDependencies(ownerId, appId, showAll) {
|
|
330
343
|
const applicationDeps = await getAllDependencies({ id: ownerId, appId }).then(sendToApi);
|
|
331
344
|
|
|
332
345
|
if (!showAll) {
|
|
@@ -342,12 +355,12 @@ export async function listDependencies (ownerId, appId, showAll) {
|
|
|
342
355
|
});
|
|
343
356
|
}
|
|
344
357
|
|
|
345
|
-
export async function link
|
|
358
|
+
export async function link(ownerId, appId, dependency) {
|
|
346
359
|
const dependencyId = await getId(ownerId, dependency);
|
|
347
360
|
return addDependency({ id: ownerId, appId, dependencyId }).then(sendToApi);
|
|
348
|
-
}
|
|
361
|
+
}
|
|
349
362
|
|
|
350
|
-
export async function unlink
|
|
363
|
+
export async function unlink(ownerId, appId, dependency) {
|
|
351
364
|
const dependencyId = await getId(ownerId, dependency);
|
|
352
365
|
return removeDependency({ id: ownerId, appId, dependencyId }).then(sendToApi);
|
|
353
|
-
}
|
|
366
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import cliparse from 'cliparse';
|
|
2
|
-
import { Logger } from '../logger.js';
|
|
3
2
|
import dedent from 'dedent';
|
|
3
|
+
import { Logger } from '../logger.js';
|
|
4
4
|
|
|
5
5
|
const CONFIG_KEYS = [
|
|
6
6
|
{ id: 'name', name: 'name', displayName: 'Name', kind: 'string' },
|
|
@@ -12,17 +12,15 @@ const CONFIG_KEYS = [
|
|
|
12
12
|
{ id: 'task', name: 'instanceLifetime', displayName: 'Deploy an application as a Clever Task', kind: 'task' },
|
|
13
13
|
];
|
|
14
14
|
|
|
15
|
-
export function listAvailableIds
|
|
15
|
+
export function listAvailableIds(asText = false) {
|
|
16
16
|
const ids = CONFIG_KEYS.map((config) => config.id);
|
|
17
17
|
if (asText) {
|
|
18
|
-
return new Intl
|
|
19
|
-
.ListFormat('en', { style: 'short', type: 'disjunction' })
|
|
20
|
-
.format(ids);
|
|
18
|
+
return new Intl.ListFormat('en', { style: 'short', type: 'disjunction' }).format(ids);
|
|
21
19
|
}
|
|
22
20
|
return ids;
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
export function getById
|
|
23
|
+
export function getById(id) {
|
|
26
24
|
const config = CONFIG_KEYS.find((config) => config.id === id);
|
|
27
25
|
if (config != null) {
|
|
28
26
|
return config;
|
|
@@ -33,7 +31,7 @@ export function getById (id) {
|
|
|
33
31
|
`);
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
export function formatValue
|
|
34
|
+
export function formatValue(config, value) {
|
|
37
35
|
switch (config.kind) {
|
|
38
36
|
case 'bool': {
|
|
39
37
|
return value;
|
|
@@ -53,7 +51,7 @@ export function formatValue (config, value) {
|
|
|
53
51
|
}
|
|
54
52
|
}
|
|
55
53
|
|
|
56
|
-
export function parse
|
|
54
|
+
export function parse(config, value) {
|
|
57
55
|
switch (config.kind) {
|
|
58
56
|
case 'bool':
|
|
59
57
|
case 'inverted-bool':
|
|
@@ -63,16 +61,16 @@ export function parse (config, value) {
|
|
|
63
61
|
throw new Error('Invalid configuration value, it must be a boolean (true or false)');
|
|
64
62
|
}
|
|
65
63
|
if (config.kind === 'bool') {
|
|
66
|
-
return
|
|
64
|
+
return value === 'true';
|
|
67
65
|
}
|
|
68
66
|
if (config.kind === 'inverted-bool') {
|
|
69
|
-
return
|
|
67
|
+
return value === 'false';
|
|
70
68
|
}
|
|
71
69
|
if (config.kind === 'force-https') {
|
|
72
|
-
return
|
|
70
|
+
return value === 'true' ? 'ENABLED' : 'DISABLED';
|
|
73
71
|
}
|
|
74
72
|
if (config.kind === 'task') {
|
|
75
|
-
return
|
|
73
|
+
return value === 'false' ? 'REGULAR' : 'TASK';
|
|
76
74
|
}
|
|
77
75
|
return;
|
|
78
76
|
}
|
|
@@ -82,13 +80,11 @@ export function parse (config, value) {
|
|
|
82
80
|
}
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
export function getUpdateOptions
|
|
86
|
-
return CONFIG_KEYS
|
|
87
|
-
.map((config) => getConfigOptions(config))
|
|
88
|
-
.reduce((a, b) => [...a, ...b], []);
|
|
83
|
+
export function getUpdateOptions() {
|
|
84
|
+
return CONFIG_KEYS.map((config) => getConfigOptions(config)).reduce((a, b) => [...a, ...b], []);
|
|
89
85
|
}
|
|
90
86
|
|
|
91
|
-
function getConfigOptions
|
|
87
|
+
function getConfigOptions(config) {
|
|
92
88
|
switch (config.kind) {
|
|
93
89
|
case 'bool':
|
|
94
90
|
case 'inverted-bool':
|
|
@@ -100,21 +96,17 @@ function getConfigOptions (config) {
|
|
|
100
96
|
];
|
|
101
97
|
}
|
|
102
98
|
default: {
|
|
103
|
-
return [
|
|
104
|
-
cliparse.option(`${config.id}`, { description: `Set ${config.id}` }),
|
|
105
|
-
];
|
|
99
|
+
return [cliparse.option(`${config.id}`, { description: `Set ${config.id}` })];
|
|
106
100
|
}
|
|
107
101
|
}
|
|
108
102
|
}
|
|
109
103
|
|
|
110
|
-
export function parseOptions
|
|
111
|
-
const newOptions = CONFIG_KEYS
|
|
112
|
-
.map((config) => parseConfigOption(config, options))
|
|
113
|
-
.filter((a) => a != null);
|
|
104
|
+
export function parseOptions(options) {
|
|
105
|
+
const newOptions = CONFIG_KEYS.map((config) => parseConfigOption(config, options)).filter((a) => a != null);
|
|
114
106
|
return Object.fromEntries(newOptions);
|
|
115
107
|
}
|
|
116
108
|
|
|
117
|
-
function parseConfigOption
|
|
109
|
+
function parseConfigOption(config, options) {
|
|
118
110
|
switch (config.kind) {
|
|
119
111
|
case 'bool':
|
|
120
112
|
case 'inverted-bool':
|
|
@@ -144,12 +136,12 @@ function parseConfigOption (config, options) {
|
|
|
144
136
|
}
|
|
145
137
|
}
|
|
146
138
|
|
|
147
|
-
export function printValue
|
|
139
|
+
export function printValue(app, id) {
|
|
148
140
|
const config = getById(id);
|
|
149
141
|
Logger.println(formatValue(config, app[config.name]));
|
|
150
142
|
}
|
|
151
143
|
|
|
152
|
-
export function printAllValues
|
|
144
|
+
export function printAllValues(app) {
|
|
153
145
|
console.table(
|
|
154
146
|
Object.fromEntries(
|
|
155
147
|
CONFIG_KEYS.map((config) => {
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
import commonEnv from 'common-env';
|
|
5
|
-
import mkdirp from 'mkdirp';
|
|
6
3
|
import xdg from 'xdg';
|
|
7
|
-
|
|
8
4
|
import { Logger } from '../logger.js';
|
|
9
|
-
const env = commonEnv(Logger);
|
|
10
5
|
|
|
11
6
|
const CONFIG_FILES = {
|
|
12
7
|
MAIN: 'clever-tools.json',
|
|
@@ -14,22 +9,22 @@ const CONFIG_FILES = {
|
|
|
14
9
|
EXPERIMENTAL_FEATURES_FILE: 'clever-tools-experimental-features.json',
|
|
15
10
|
};
|
|
16
11
|
|
|
17
|
-
function getConfigDir
|
|
18
|
-
return
|
|
12
|
+
function getConfigDir() {
|
|
13
|
+
return process.platform === 'win32'
|
|
19
14
|
? path.resolve(process.env.APPDATA, 'clever-cloud')
|
|
20
15
|
: xdg.basedir.configPath('clever-cloud');
|
|
21
16
|
}
|
|
22
17
|
|
|
23
|
-
function getConfigPath
|
|
18
|
+
function getConfigPath(configFile) {
|
|
24
19
|
return path.resolve(getConfigDir(), configFile);
|
|
25
20
|
}
|
|
26
21
|
|
|
27
22
|
// Every function which need 'clever-cloud' directory, need to call it before
|
|
28
|
-
async function ensureConfigDirExists
|
|
29
|
-
await
|
|
23
|
+
async function ensureConfigDirExists() {
|
|
24
|
+
await fs.mkdir(getConfigDir(), { mode: 0o700, recursive: true });
|
|
30
25
|
}
|
|
31
26
|
|
|
32
|
-
export async function loadOAuthConf
|
|
27
|
+
export async function loadOAuthConf() {
|
|
33
28
|
Logger.debug('Load configuration from environment variables');
|
|
34
29
|
if (process.env.CLEVER_TOKEN != null && process.env.CLEVER_SECRET != null) {
|
|
35
30
|
return {
|
|
@@ -47,8 +42,7 @@ export async function loadOAuthConf () {
|
|
|
47
42
|
token,
|
|
48
43
|
secret,
|
|
49
44
|
};
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
45
|
+
} catch (error) {
|
|
52
46
|
Logger.info(`Cannot load configuration from ${conf.CONFIGURATION_FILE}\n${error.message}`);
|
|
53
47
|
return {
|
|
54
48
|
source: 'none',
|
|
@@ -56,24 +50,22 @@ export async function loadOAuthConf () {
|
|
|
56
50
|
}
|
|
57
51
|
}
|
|
58
52
|
|
|
59
|
-
export async function writeOAuthConf
|
|
53
|
+
export async function writeOAuthConf(oauthData) {
|
|
60
54
|
Logger.debug('Write the tokens in the configuration file…');
|
|
61
55
|
try {
|
|
62
56
|
await ensureConfigDirExists();
|
|
63
57
|
await fs.writeFile(conf.CONFIGURATION_FILE, JSON.stringify(oauthData));
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
58
|
+
} catch (error) {
|
|
66
59
|
throw new Error(`Cannot write configuration to ${conf.CONFIGURATION_FILE}\n${error.message}`);
|
|
67
60
|
}
|
|
68
61
|
}
|
|
69
62
|
|
|
70
|
-
export async function loadIdsCache
|
|
63
|
+
export async function loadIdsCache() {
|
|
71
64
|
const cachePath = getConfigPath(CONFIG_FILES.IDS_CACHE);
|
|
72
65
|
try {
|
|
73
66
|
const rawFile = await fs.readFile(cachePath);
|
|
74
67
|
return JSON.parse(rawFile);
|
|
75
|
-
}
|
|
76
|
-
catch (error) {
|
|
68
|
+
} catch (error) {
|
|
77
69
|
Logger.info(`Cannot load IDs cache from ${cachePath}\n${error.message}`);
|
|
78
70
|
return {
|
|
79
71
|
owners: {},
|
|
@@ -82,25 +74,23 @@ export async function loadIdsCache () {
|
|
|
82
74
|
}
|
|
83
75
|
}
|
|
84
76
|
|
|
85
|
-
export async function writeIdsCache
|
|
77
|
+
export async function writeIdsCache(ids) {
|
|
86
78
|
const cachePath = getConfigPath(CONFIG_FILES.IDS_CACHE);
|
|
87
79
|
const idsJson = JSON.stringify(ids);
|
|
88
80
|
try {
|
|
89
81
|
await ensureConfigDirExists();
|
|
90
82
|
await fs.writeFile(cachePath, idsJson);
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
83
|
+
} catch (error) {
|
|
93
84
|
throw new Error(`Cannot write IDs cache to ${cachePath}\n${error.message}`);
|
|
94
85
|
}
|
|
95
86
|
}
|
|
96
87
|
|
|
97
|
-
export async function getFeatures
|
|
88
|
+
export async function getFeatures() {
|
|
98
89
|
Logger.debug('Get features configuration from ' + conf.EXPERIMENTAL_FEATURES_FILE);
|
|
99
90
|
try {
|
|
100
91
|
const rawFile = await fs.readFile(conf.EXPERIMENTAL_FEATURES_FILE);
|
|
101
92
|
return JSON.parse(rawFile);
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
93
|
+
} catch (error) {
|
|
104
94
|
if (error.code !== 'ENOENT') {
|
|
105
95
|
throw new Error(`Cannot get experimental features configuration from ${conf.EXPERIMENTAL_FEATURES_FILE}`);
|
|
106
96
|
}
|
|
@@ -108,20 +98,19 @@ export async function getFeatures () {
|
|
|
108
98
|
}
|
|
109
99
|
}
|
|
110
100
|
|
|
111
|
-
export async function setFeature
|
|
101
|
+
export async function setFeature(feature, value) {
|
|
112
102
|
const currentFeatures = await getFeatures();
|
|
113
103
|
const newFeatures = { ...currentFeatures, ...{ [feature]: value } };
|
|
114
104
|
|
|
115
105
|
try {
|
|
116
106
|
await ensureConfigDirExists();
|
|
117
107
|
await fs.writeFile(conf.EXPERIMENTAL_FEATURES_FILE, JSON.stringify(newFeatures, null, 2));
|
|
118
|
-
}
|
|
119
|
-
catch (error) {
|
|
108
|
+
} catch {
|
|
120
109
|
throw new Error(`Cannot write experimental features configuration to ${conf.EXPERIMENTAL_FEATURES_FILE}`);
|
|
121
110
|
}
|
|
122
111
|
}
|
|
123
112
|
|
|
124
|
-
|
|
113
|
+
const defaultConf = {
|
|
125
114
|
API_HOST: 'https://api.clever-cloud.com',
|
|
126
115
|
AUTH_BRIDGE_HOST: 'https://api-bridge.clever-cloud.com',
|
|
127
116
|
SSH_GATEWAY: 'ssh@sshgateway-clevercloud-customers.services.clever-cloud.com',
|
|
@@ -134,9 +123,18 @@ export const conf = env.getOrElseAll({
|
|
|
134
123
|
CONFIGURATION_FILE: getConfigPath(CONFIG_FILES.MAIN),
|
|
135
124
|
EXPERIMENTAL_FEATURES_FILE: getConfigPath(CONFIG_FILES.EXPERIMENTAL_FEATURES_FILE),
|
|
136
125
|
|
|
137
|
-
API_DOC_URL: 'https://www.clever
|
|
138
|
-
DOC_URL: 'https://www.clever
|
|
126
|
+
API_DOC_URL: 'https://www.clever.cloud/developers/api',
|
|
127
|
+
DOC_URL: 'https://www.clever.cloud/developers/doc',
|
|
139
128
|
CONSOLE_URL: 'https://console.clever-cloud.com',
|
|
140
129
|
CONSOLE_TOKEN_URL: 'https://console.clever-cloud.com/cli-oauth',
|
|
141
130
|
GOTO_URL: 'https://console.clever-cloud.com/goto',
|
|
142
|
-
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export const conf = Object.fromEntries(
|
|
134
|
+
Object.entries(defaultConf).map(([name, value]) => {
|
|
135
|
+
if (process.env[name] != null) {
|
|
136
|
+
return [name, process.env[name]];
|
|
137
|
+
}
|
|
138
|
+
return [name, value];
|
|
139
|
+
}),
|
|
140
|
+
);
|