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
package/src/models/addon.js
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
create as createAddon,
|
|
3
|
+
get as getAddon,
|
|
4
|
+
getAll as getAllAddons,
|
|
5
|
+
getAllEnvVars,
|
|
6
|
+
remove as removeAddon,
|
|
7
|
+
update as updateAddon,
|
|
8
|
+
} from '@clevercloud/client/esm/api/v2/addon.js';
|
|
9
|
+
import { getAllLinkedAddons, linkAddon, unlinkAddon } from '@clevercloud/client/esm/api/v2/application.js';
|
|
4
10
|
import { getAllAddonProviders } from '@clevercloud/client/esm/api/v2/product.js';
|
|
5
11
|
import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
|
|
6
12
|
import { getAddonProvider } from '@clevercloud/client/esm/api/v4/addon-providers.js';
|
|
7
|
-
|
|
13
|
+
import cliparse from 'cliparse';
|
|
8
14
|
import { confirm } from '../lib/prompts.js';
|
|
9
15
|
import { Logger } from '../logger.js';
|
|
10
|
-
import { sendToApi } from '../models/send-to-api.js';
|
|
11
16
|
import { resolveOwnerId } from './ids-resolver.js';
|
|
12
|
-
import {
|
|
17
|
+
import { sendToApi } from './send-to-api.js';
|
|
13
18
|
|
|
14
|
-
export function listProviders
|
|
19
|
+
export function listProviders() {
|
|
15
20
|
return getAllAddonProviders({}).then(sendToApi);
|
|
16
21
|
}
|
|
17
22
|
|
|
18
|
-
export async function getProvider
|
|
23
|
+
export async function getProvider(providerName) {
|
|
19
24
|
const providers = await listProviders();
|
|
20
25
|
const provider = providers.find((p) => p.id === providerName);
|
|
21
26
|
if (provider == null) {
|
|
@@ -24,8 +29,9 @@ export async function getProvider (providerName) {
|
|
|
24
29
|
return provider;
|
|
25
30
|
}
|
|
26
31
|
|
|
27
|
-
export function getProviderInfos
|
|
28
|
-
return getAddonProvider({ providerId: providerName })
|
|
32
|
+
export function getProviderInfos(providerName) {
|
|
33
|
+
return getAddonProvider({ providerId: providerName })
|
|
34
|
+
.then(sendToApi)
|
|
29
35
|
.catch(() => {
|
|
30
36
|
// An error can occur because the add-on api doesn't implement this endpoint yet
|
|
31
37
|
// This is fine, just ignore it
|
|
@@ -34,7 +40,7 @@ export function getProviderInfos (providerName) {
|
|
|
34
40
|
});
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
export async function list
|
|
43
|
+
export async function list(ownerId, appId, showAll) {
|
|
38
44
|
const allAddons = await getAllAddons({ id: ownerId }).then(sendToApi);
|
|
39
45
|
|
|
40
46
|
if (appId == null) {
|
|
@@ -43,9 +49,8 @@ export async function list (ownerId, appId, showAll) {
|
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
const myAddons = await getAllLinkedAddons({ id: ownerId, appId }).then(sendToApi);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return myAddons;
|
|
52
|
+
if (!showAll) {
|
|
53
|
+
return myAddons.map((addon) => ({ ...addon, isLinked: true }));
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
const myAddonIds = myAddons.map((addon) => addon.id);
|
|
@@ -55,7 +60,7 @@ export async function list (ownerId, appId, showAll) {
|
|
|
55
60
|
});
|
|
56
61
|
}
|
|
57
62
|
|
|
58
|
-
function validateAddonVersionAndOptions
|
|
63
|
+
function validateAddonVersionAndOptions(region, version, addonOptions, providerInfos, planType) {
|
|
59
64
|
if (providerInfos != null) {
|
|
60
65
|
if (version != null) {
|
|
61
66
|
const type = planType.value.toLowerCase();
|
|
@@ -63,16 +68,18 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
|
|
|
63
68
|
const cluster = providerInfos.clusters.find(({ zone }) => zone === region);
|
|
64
69
|
if (cluster == null) {
|
|
65
70
|
throw new Error(`Can't find cluster for region ${region}`);
|
|
71
|
+
} else if (cluster.version !== version) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`Invalid version ${version}, selected shared cluster only supports version ${cluster.version}`,
|
|
74
|
+
);
|
|
66
75
|
}
|
|
67
|
-
|
|
68
|
-
throw new Error(`Invalid version ${version}, selected shared cluster only supports version ${cluster.version}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
else if (type === 'dedicated') {
|
|
76
|
+
} else if (type === 'dedicated') {
|
|
72
77
|
const availableVersions = Object.keys(providerInfos.dedicated);
|
|
73
78
|
const hasVersion = availableVersions.find((availableVersion) => availableVersion === version);
|
|
74
79
|
if (hasVersion == null) {
|
|
75
|
-
throw new Error(
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Invalid version ${addonOptions.version}, available versions are: ${availableVersions.join(', ')}`,
|
|
82
|
+
);
|
|
76
83
|
}
|
|
77
84
|
}
|
|
78
85
|
}
|
|
@@ -91,8 +98,7 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
|
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
availableOptions = cluster.features;
|
|
94
|
-
}
|
|
95
|
-
else if (type === 'dedicated') {
|
|
101
|
+
} else if (type === 'dedicated') {
|
|
96
102
|
availableOptions = providerInfos.dedicated[chosenVersion].features;
|
|
97
103
|
}
|
|
98
104
|
|
|
@@ -103,8 +109,7 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
|
|
|
103
109
|
let availableOptionsError = null;
|
|
104
110
|
if (optionNames.length > 0) {
|
|
105
111
|
availableOptionsError = `Available options are: ${optionNames}.`;
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
112
|
+
} else {
|
|
108
113
|
availableOptionsError = 'No options are available for this plan.';
|
|
109
114
|
}
|
|
110
115
|
|
|
@@ -117,17 +122,15 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
|
|
|
117
122
|
version: chosenVersion,
|
|
118
123
|
...addonOptions,
|
|
119
124
|
};
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
125
|
+
} else {
|
|
122
126
|
if (version != null) {
|
|
123
|
-
throw new Error(
|
|
127
|
+
throw new Error("You provided a version for an add-on that doesn't support choosing the version.");
|
|
124
128
|
}
|
|
125
129
|
return {};
|
|
126
130
|
}
|
|
127
131
|
}
|
|
128
132
|
|
|
129
|
-
export async function create
|
|
130
|
-
|
|
133
|
+
export async function create({ ownerId, name, providerName, planName, region, version, addonOptions }) {
|
|
131
134
|
// TODO: We should be able to use it without {}
|
|
132
135
|
const provider = await getProvider(providerName);
|
|
133
136
|
|
|
@@ -148,7 +151,9 @@ export async function create ({ ownerId, name, providerName, planName, region, s
|
|
|
148
151
|
// This missing feature should have been added during the add-on's development phase
|
|
149
152
|
// The console has a similar check so I believe we shouldn't hit this
|
|
150
153
|
if (providerInfos != null && planType == null) {
|
|
151
|
-
throw new Error(
|
|
154
|
+
throw new Error(
|
|
155
|
+
'Internal error. The selected plan misses the TYPE feature. Please contact our support with the command line you used',
|
|
156
|
+
);
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
const createOptions = validateAddonVersionAndOptions(region, version, addonOptions, providerInfos, planType);
|
|
@@ -167,7 +172,7 @@ export async function create ({ ownerId, name, providerName, planName, region, s
|
|
|
167
172
|
return createdAddon;
|
|
168
173
|
}
|
|
169
174
|
|
|
170
|
-
async function getByName
|
|
175
|
+
async function getByName(ownerId, addonNameOrRealId) {
|
|
171
176
|
const addons = await getAllAddons({ id: ownerId }).then(sendToApi);
|
|
172
177
|
const filteredAddons = addons.filter(({ name, realId }) => {
|
|
173
178
|
return name === addonNameOrRealId || realId === addonNameOrRealId;
|
|
@@ -181,7 +186,7 @@ async function getByName (ownerId, addonNameOrRealId) {
|
|
|
181
186
|
throw new Error('Ambiguous addon name');
|
|
182
187
|
}
|
|
183
188
|
|
|
184
|
-
async function getId
|
|
189
|
+
async function getId(ownerId, addon) {
|
|
185
190
|
if (addon.addon_id) {
|
|
186
191
|
return addon.addon_id;
|
|
187
192
|
}
|
|
@@ -189,44 +194,41 @@ async function getId (ownerId, addon) {
|
|
|
189
194
|
return addonDetails.id;
|
|
190
195
|
}
|
|
191
196
|
|
|
192
|
-
export async function link
|
|
197
|
+
export async function link(ownerId, appId, addon) {
|
|
193
198
|
const addonId = await getId(ownerId, addon);
|
|
194
199
|
return linkAddon({ id: ownerId, appId }, JSON.stringify(addonId)).then(sendToApi);
|
|
195
200
|
}
|
|
196
201
|
|
|
197
|
-
export async function unlink
|
|
202
|
+
export async function unlink(ownerId, appId, addon) {
|
|
198
203
|
const addonId = await getId(ownerId, addon);
|
|
199
204
|
return unlinkAddon({ id: ownerId, appId, addonId }).then(sendToApi);
|
|
200
205
|
}
|
|
201
206
|
|
|
202
|
-
export async function deleteAddon
|
|
207
|
+
export async function deleteAddon(ownerId, addonIdOrName, skipConfirmation) {
|
|
203
208
|
const addonId = await getId(ownerId, addonIdOrName);
|
|
204
209
|
|
|
205
210
|
if (!skipConfirmation) {
|
|
206
|
-
await confirm(
|
|
207
|
-
'Deleting the add-on can\'t be undone, are you sure?',
|
|
208
|
-
'No confirmation, aborting add-on deletion',
|
|
209
|
-
);
|
|
211
|
+
await confirm("Deleting the add-on can't be undone, are you sure?", 'No confirmation, aborting add-on deletion');
|
|
210
212
|
}
|
|
211
213
|
|
|
212
214
|
return removeAddon({ id: ownerId, addonId }).then(sendToApi);
|
|
213
215
|
}
|
|
214
216
|
|
|
215
|
-
export async function rename
|
|
217
|
+
export async function rename(ownerId, addon, name) {
|
|
216
218
|
const addonId = await getId(ownerId, addon);
|
|
217
219
|
return updateAddon({ id: ownerId, addonId }, { name }).then(sendToApi);
|
|
218
220
|
}
|
|
219
221
|
|
|
220
|
-
export function completeRegion
|
|
222
|
+
export function completeRegion() {
|
|
221
223
|
return cliparse.autocomplete.words(['par', 'mtl']);
|
|
222
224
|
}
|
|
223
225
|
|
|
224
226
|
// TODO: We need to fix this
|
|
225
|
-
export function completePlan
|
|
227
|
+
export function completePlan() {
|
|
226
228
|
return cliparse.autocomplete.words(['dev', 's', 'm', 'l', 'xl', 'xxl']);
|
|
227
229
|
}
|
|
228
230
|
|
|
229
|
-
export async function findById
|
|
231
|
+
export async function findById(addonId) {
|
|
230
232
|
const { user, organisations } = await getSummary({}).then(sendToApi);
|
|
231
233
|
for (const orga of [user, ...organisations]) {
|
|
232
234
|
for (const simpleAddon of orga.addons) {
|
|
@@ -242,7 +244,7 @@ export async function findById (addonId) {
|
|
|
242
244
|
throw new Error(`Could not find add-on with ID: ${addonId}`);
|
|
243
245
|
}
|
|
244
246
|
|
|
245
|
-
export async function findByName
|
|
247
|
+
export async function findByName(addonName) {
|
|
246
248
|
const { user, organisations } = await getSummary({}).then(sendToApi);
|
|
247
249
|
for (const orga of [user, ...organisations]) {
|
|
248
250
|
for (const simpleAddon of orga.addons) {
|
|
@@ -258,8 +260,7 @@ export async function findByName (addonName) {
|
|
|
258
260
|
throw new Error(`Could not find add-on with name ${addonName}`);
|
|
259
261
|
}
|
|
260
262
|
|
|
261
|
-
export async function findOwnerId
|
|
262
|
-
|
|
263
|
+
export async function findOwnerId(org, addonId) {
|
|
263
264
|
if (org != null && org.orga_id != null) {
|
|
264
265
|
return org.orga_id;
|
|
265
266
|
}
|
|
@@ -272,12 +273,12 @@ export async function findOwnerId (org, addonId) {
|
|
|
272
273
|
throw new Error(`Add-on ${addonId} does not exist`);
|
|
273
274
|
}
|
|
274
275
|
|
|
275
|
-
export function parseAddonOptions
|
|
276
|
+
export function parseAddonOptions(options) {
|
|
276
277
|
if (options == null) {
|
|
277
278
|
return {};
|
|
278
279
|
}
|
|
279
280
|
|
|
280
|
-
const pairs = options.split(/,(?=\w
|
|
281
|
+
const pairs = options.split(/,(?=\w+(?:-\w+)*=)/) || [];
|
|
281
282
|
|
|
282
283
|
return pairs.reduce((options, pair) => {
|
|
283
284
|
const [key, ...valueParts] = pair.split('=');
|
|
@@ -290,14 +291,11 @@ export function parseAddonOptions (options) {
|
|
|
290
291
|
let formattedValue = value;
|
|
291
292
|
if (value === 'true' || value === 'enabled') {
|
|
292
293
|
formattedValue = 'true';
|
|
293
|
-
}
|
|
294
|
-
else if (value === 'false' || value === 'disabled') {
|
|
294
|
+
} else if (value === 'false' || value === 'disabled') {
|
|
295
295
|
formattedValue = 'false';
|
|
296
|
-
}
|
|
297
|
-
else if (typeof key === 'string') {
|
|
296
|
+
} else if (typeof key === 'string') {
|
|
298
297
|
formattedValue = value;
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
298
|
+
} else {
|
|
301
299
|
throw new Error(`Can't parse option value: ${value}. Accepted values are: enabled, disabled, true, false`);
|
|
302
300
|
}
|
|
303
301
|
|
|
@@ -306,7 +304,7 @@ export function parseAddonOptions (options) {
|
|
|
306
304
|
}, {});
|
|
307
305
|
}
|
|
308
306
|
|
|
309
|
-
function getPlan
|
|
307
|
+
function getPlan(planName, plans) {
|
|
310
308
|
// if no plan specified, pick the cheapest one
|
|
311
309
|
if (planName == null || planName === '') {
|
|
312
310
|
return plans.sort((p1, p2) => p1.price - p2.price)[0];
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
1
2
|
import { promises as fs } from 'node:fs';
|
|
2
3
|
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
import _ from 'lodash';
|
|
5
4
|
import { slugify } from '../lib/slugify.js';
|
|
6
|
-
|
|
7
5
|
import { Logger } from '../logger.js';
|
|
8
|
-
import * as User from './user.js';
|
|
9
6
|
import { conf } from './configuration.js';
|
|
7
|
+
import * as User from './user.js';
|
|
10
8
|
|
|
11
9
|
// TODO: Maybe use fs-utils findPath()
|
|
12
|
-
export async function loadApplicationConf
|
|
10
|
+
export async function loadApplicationConf(ignoreParentConfig = false, pathToFolder) {
|
|
13
11
|
if (pathToFolder == null) {
|
|
14
12
|
pathToFolder = path.dirname(conf.APP_CONFIGURATION_FILE);
|
|
15
13
|
}
|
|
@@ -19,17 +17,16 @@ export async function loadApplicationConf (ignoreParentConfig = false, pathToFol
|
|
|
19
17
|
try {
|
|
20
18
|
const contents = await fs.readFile(fullPath);
|
|
21
19
|
return JSON.parse(contents);
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
20
|
+
} catch (error) {
|
|
24
21
|
Logger.info('Cannot load app configuration from ' + conf.APP_CONFIGURATION_FILE + ' (' + error + ')');
|
|
25
22
|
if (ignoreParentConfig || path.parse(pathToFolder).root === pathToFolder) {
|
|
26
23
|
return { apps: [] };
|
|
27
24
|
}
|
|
28
25
|
return loadApplicationConf(ignoreParentConfig, path.normalize(path.join(pathToFolder, '..')));
|
|
29
26
|
}
|
|
30
|
-
}
|
|
27
|
+
}
|
|
31
28
|
|
|
32
|
-
export async function addLinkedApplication
|
|
29
|
+
export async function addLinkedApplication(appData, alias, ignoreParentConfig) {
|
|
33
30
|
const currentConfig = await loadApplicationConf(ignoreParentConfig);
|
|
34
31
|
|
|
35
32
|
const appEntry = {
|
|
@@ -50,9 +47,9 @@ export async function addLinkedApplication (appData, alias, ignoreParentConfig)
|
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
return persistConfig(currentConfig);
|
|
53
|
-
}
|
|
50
|
+
}
|
|
54
51
|
|
|
55
|
-
export async function removeLinkedApplication
|
|
52
|
+
export async function removeLinkedApplication({ appId, alias }) {
|
|
56
53
|
const currentConfig = await loadApplicationConf();
|
|
57
54
|
const appToUnlink = currentConfig.apps.find((a) => a.app_id === appId || a.alias === alias);
|
|
58
55
|
if (appToUnlink == null) {
|
|
@@ -70,9 +67,9 @@ export async function removeLinkedApplication ({ appId, alias }) {
|
|
|
70
67
|
|
|
71
68
|
await persistConfig(newConfig);
|
|
72
69
|
return true;
|
|
73
|
-
}
|
|
70
|
+
}
|
|
74
71
|
|
|
75
|
-
export function findApp
|
|
72
|
+
export function findApp(config, alias) {
|
|
76
73
|
if (_.isEmpty(config.apps)) {
|
|
77
74
|
throw new Error('There is no linked or targeted application. Use `--app` option or `clever link` command.');
|
|
78
75
|
}
|
|
@@ -83,7 +80,9 @@ export function findApp (config, alias) {
|
|
|
83
80
|
throw new Error(`There are no applications matching alias ${alias}`);
|
|
84
81
|
}
|
|
85
82
|
if (secondAppByAlias != null) {
|
|
86
|
-
throw new Error(
|
|
83
|
+
throw new Error(
|
|
84
|
+
`There are several applications matching alias ${alias}. This should not happen, your \`.clever.json\` should be fixed.`,
|
|
85
|
+
);
|
|
87
86
|
}
|
|
88
87
|
return appByAlias;
|
|
89
88
|
}
|
|
@@ -91,7 +90,7 @@ export function findApp (config, alias) {
|
|
|
91
90
|
return findDefaultApp(config);
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
export function checkAlreadyLinked
|
|
93
|
+
export function checkAlreadyLinked(apps, name, alias) {
|
|
95
94
|
const appAliasExists = apps.some((app) => app.alias != null && app.alias === alias);
|
|
96
95
|
if (appAliasExists) {
|
|
97
96
|
throw new Error(`An application is already linked with the alias '${alias}'`);
|
|
@@ -103,7 +102,7 @@ export function checkAlreadyLinked (apps, name, alias) {
|
|
|
103
102
|
}
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
function findDefaultApp
|
|
105
|
+
function findDefaultApp(config) {
|
|
107
106
|
if (_.isEmpty(config.apps)) {
|
|
108
107
|
throw new Error('There is no linked or targeted application. Use `--app` option or `clever link` command.');
|
|
109
108
|
}
|
|
@@ -111,7 +110,9 @@ function findDefaultApp (config) {
|
|
|
111
110
|
if (config.default != null) {
|
|
112
111
|
const defaultApp = _.find(config.apps, { app_id: config.default });
|
|
113
112
|
if (defaultApp == null) {
|
|
114
|
-
throw new Error(
|
|
113
|
+
throw new Error(
|
|
114
|
+
'The default application is not listed anymore. This should not happen, your `.clever.json` should be fixed.',
|
|
115
|
+
);
|
|
115
116
|
}
|
|
116
117
|
return defaultApp;
|
|
117
118
|
}
|
|
@@ -121,10 +122,12 @@ function findDefaultApp (config) {
|
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
const aliases = _.map(config.apps, 'alias').join(', ');
|
|
124
|
-
throw new Error(
|
|
125
|
+
throw new Error(
|
|
126
|
+
`Several applications are linked. You can specify one with the "--alias" option. Run "clever applications" to list linked applications. Available aliases: ${aliases}`,
|
|
127
|
+
);
|
|
125
128
|
}
|
|
126
129
|
|
|
127
|
-
async function getAppDetailsForId
|
|
130
|
+
async function getAppDetailsForId(appId) {
|
|
128
131
|
const config = await loadApplicationConf();
|
|
129
132
|
|
|
130
133
|
if (_.isEmpty(config.apps)) {
|
|
@@ -136,19 +139,19 @@ async function getAppDetailsForId (appId) {
|
|
|
136
139
|
throw new Error(`There are no applications matching id '${appId}'`);
|
|
137
140
|
}
|
|
138
141
|
if (secondAppById != null) {
|
|
139
|
-
throw new Error(
|
|
140
|
-
|
|
142
|
+
throw new Error(
|
|
143
|
+
`There are several applications matching id '${appId}'.` +
|
|
144
|
+
'This should not happen, your `.clever.json` should be fixed.',
|
|
145
|
+
);
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
return appById;
|
|
144
149
|
}
|
|
145
150
|
|
|
146
|
-
export async function getAppDetails
|
|
151
|
+
export async function getAppDetails({ alias }) {
|
|
147
152
|
const config = await loadApplicationConf();
|
|
148
153
|
const app = findApp(config, alias);
|
|
149
|
-
const ownerId =
|
|
150
|
-
? app.org_id
|
|
151
|
-
: await User.getCurrentId();
|
|
154
|
+
const ownerId = app.org_id != null ? app.org_id : await User.getCurrentId();
|
|
152
155
|
return {
|
|
153
156
|
appId: app.app_id,
|
|
154
157
|
ownerId: ownerId,
|
|
@@ -156,24 +159,23 @@ export async function getAppDetails ({ alias }) {
|
|
|
156
159
|
name: app.name,
|
|
157
160
|
alias: app.alias,
|
|
158
161
|
};
|
|
159
|
-
}
|
|
162
|
+
}
|
|
160
163
|
|
|
161
|
-
export async function getMostNaturalName
|
|
164
|
+
export async function getMostNaturalName(appId) {
|
|
162
165
|
try {
|
|
163
166
|
const details = await getAppDetailsForId(appId);
|
|
164
167
|
return details.alias || details.name || appId;
|
|
165
|
-
}
|
|
166
|
-
catch {
|
|
168
|
+
} catch {
|
|
167
169
|
return appId;
|
|
168
170
|
}
|
|
169
171
|
}
|
|
170
172
|
|
|
171
|
-
function persistConfig
|
|
173
|
+
function persistConfig(modifiedConfig) {
|
|
172
174
|
const jsonContents = JSON.stringify(modifiedConfig, null, 2);
|
|
173
175
|
return fs.writeFile(conf.APP_CONFIGURATION_FILE, jsonContents);
|
|
174
|
-
}
|
|
176
|
+
}
|
|
175
177
|
|
|
176
|
-
export async function setDefault
|
|
178
|
+
export async function setDefault(alias) {
|
|
177
179
|
const config = await loadApplicationConf();
|
|
178
180
|
const app = findApp(config, alias);
|
|
179
181
|
const newConfig = { ...config, default: app.app_id };
|