@sap/cds-dk 7.5.1 → 7.6.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/add.js +28 -24
- package/bin/bind.js +59 -32
- package/bin/build.js +1 -1
- package/bin/cds.js +1 -1
- package/bin/env.js +1 -6
- package/bin/init.js +7 -3
- package/bin/logout.js +2 -2
- package/bin/migrate.js +1 -1
- package/bin/version.js +1 -0
- package/bin/watch.js +8 -1
- package/lib/bind/bindingUtil.js +14 -20
- package/lib/bind/cfKeyProvider.js +8 -10
- package/lib/bind/index.js +4 -2
- package/lib/build/buildTaskFactory.js +31 -20
- package/lib/build/constants.js +9 -8
- package/lib/build/provider/featureToggleBuildPlugin.js +1 -7
- package/lib/build/provider/hana/index.js +44 -9
- package/lib/build/provider/internalBuildTaskProvider.js +7 -5
- package/lib/build/provider/java/index.js +0 -6
- package/lib/build/provider/mtx-sidecar/index.js +5 -0
- package/lib/build/provider/nodejs/index.js +32 -47
- package/lib/build/util.js +134 -33
- package/lib/deploy/to-hana/hana.js +1 -1
- package/lib/env/schema.js +157 -17
- package/lib/env/schemas/cds-rc.js +118 -0
- package/lib/init/constants.js +1 -1
- package/lib/init/merge.js +2 -1
- package/lib/init/template/application-logging/index.js +1 -2
- package/lib/init/template/approuter/files/mta.yaml.hbs +2 -0
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/approuter/files/values.yaml.hbs +8 -1
- package/lib/init/template/hana/files/undeploy.json +3 -2
- package/lib/init/template/helm/files/chart/templates/NOTES.txt +2 -0
- package/lib/init/template/helm/files/chart/templates/_deployment_helpers.tpl +10 -2
- package/lib/init/template/helm/files/content-deployment/Chart.yaml +1 -1
- package/lib/init/template/helm/files/content-deployment/templates/_helpers.tpl +6 -5
- package/lib/init/template/helm/files/content-deployment/values.yaml +1 -1
- package/lib/init/template/helm/files/service-instance/Chart.yaml +1 -1
- package/lib/init/template/helm/files/service-instance/templates/_helpers.tpl +6 -5
- package/lib/init/template/helm/files/service-instance/values.yaml +1 -1
- package/lib/init/template/helm/files/web-application/Chart.yaml +1 -1
- package/lib/init/template/helm/files/web-application/templates/_api.tpl +6 -5
- package/lib/init/template/helm/files/web-application/values.yaml +1 -1
- package/lib/init/template/helm/index.js +1 -12
- package/lib/init/template/helm-unified-runtime/index.js +3 -2
- package/lib/init/template/html5-repo/files/values.yaml.hbs +9 -0
- package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +1 -2
- package/lib/init/template/multitenancy/index.js +3 -2
- package/lib/init/template/xsuaa/files/package.json.hbs +1 -2
- package/lib/mtx/activate.js +1 -1
- package/lib/mtx/auth_manager.js +4 -2
- package/lib/mtx/download_legacy.js +1 -1
- package/lib/mtx/extend.js +2 -2
- package/lib/mtx/pull.js +1 -1
- package/lib/mtx/push.js +1 -1
- package/lib/mtx/settings_manager.js +77 -26
- package/lib/mtx/tenant_action.js +1 -1
- package/lib/mtx/util/legacy_ext.js +0 -1
- package/lib/util/axios.js +1 -19
- package/lib/util/cf.js +15 -10
- package/npm-shrinkwrap.json +306 -278
- package/package.json +1 -1
- package/lib/env/schemas/cds-rc.json +0 -101
- package/lib/init/template/helm-unified-runtime/lib/build.js +0 -0
package/lib/mtx/activate.js
CHANGED
|
@@ -5,7 +5,7 @@ const axios = require('axios');
|
|
|
5
5
|
const cds = require('../cds');
|
|
6
6
|
const AuthManager = require('./auth_manager');
|
|
7
7
|
|
|
8
|
-
require('../util/axios').pruneErrors()
|
|
8
|
+
require('../util/axios').pruneErrors();
|
|
9
9
|
const { collectFileContent, collectFiles, toUnixPath } = require('./util/fs');
|
|
10
10
|
const { getMessage } = require('./util/logging');
|
|
11
11
|
const { handleHttpError } = require('./util/errors');
|
package/lib/mtx/auth_manager.js
CHANGED
|
@@ -4,7 +4,7 @@ const cds = require('../cds');
|
|
|
4
4
|
const { SettingsManager } = require('./settings_manager');
|
|
5
5
|
const { ParamCollection } = require('./params');
|
|
6
6
|
|
|
7
|
-
require('../util/axios').pruneErrors()
|
|
7
|
+
require('../util/axios').pruneErrors();
|
|
8
8
|
const { getMessage } = require('./util/logging');
|
|
9
9
|
|
|
10
10
|
const DEBUG = cds.debug('cli');
|
|
@@ -127,8 +127,10 @@ module.exports = class AuthManager {
|
|
|
127
127
|
static async logout(paramValues) {
|
|
128
128
|
SettingsManager.init();
|
|
129
129
|
const params = new ParamCollection(paramValues);
|
|
130
|
+
await SettingsManager.setKeytar(params, true);
|
|
130
131
|
if (params.get('clearInvalid')) {
|
|
131
|
-
await SettingsManager.
|
|
132
|
+
await SettingsManager.deleteInvalidSettings();
|
|
133
|
+
await SettingsManager.deleteInvalidTokens();
|
|
132
134
|
} else {
|
|
133
135
|
await SettingsManager.deleteToken(params);
|
|
134
136
|
if (params.get('deleteSettings')) {
|
|
@@ -4,7 +4,7 @@ const axios = require('axios');
|
|
|
4
4
|
|
|
5
5
|
const { login } = require('./auth_manager');
|
|
6
6
|
|
|
7
|
-
require('../util/axios').pruneErrors()
|
|
7
|
+
require('../util/axios').pruneErrors();
|
|
8
8
|
const { handleHttpError } = require('./util/errors');
|
|
9
9
|
|
|
10
10
|
const DOWNLOAD_FILE_NAME = 'migrated_projects.tgz'; // TODO try to add tenant later, if possible
|
package/lib/mtx/extend.js
CHANGED
|
@@ -4,7 +4,7 @@ const axios = require('axios');
|
|
|
4
4
|
|
|
5
5
|
const AuthManager = require('./auth_manager');
|
|
6
6
|
|
|
7
|
-
require('../util/axios').pruneErrors()
|
|
7
|
+
require('../util/axios').pruneErrors();
|
|
8
8
|
const { normalizePath, isParent } = require('./util/fs');
|
|
9
9
|
const Question = require('./util/question');
|
|
10
10
|
const { getMessage } = require('./util/logging');
|
|
@@ -163,7 +163,7 @@ module.exports = class Extend {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
static promptTemplateOverwrite() {
|
|
166
|
-
return Question.askBooleanQuestion(`This will overwrite
|
|
166
|
+
return Question.askBooleanQuestion(`This will overwrite existing templates in folder ${TEMPLATE_FOLDER}. Continue (yN)? `);
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
static _logWrittenFile(file) {
|
package/lib/mtx/pull.js
CHANGED
|
@@ -7,7 +7,7 @@ const axios = require('axios');
|
|
|
7
7
|
|
|
8
8
|
const { login } = require('./auth_manager');
|
|
9
9
|
|
|
10
|
-
require('../util/axios').pruneErrors()
|
|
10
|
+
require('../util/axios').pruneErrors();
|
|
11
11
|
const { getMessage } = require('./util/logging');
|
|
12
12
|
const { handleHttpError } = require('./util/errors');
|
|
13
13
|
|
package/lib/mtx/push.js
CHANGED
|
@@ -6,7 +6,7 @@ const axios = require('axios');
|
|
|
6
6
|
const { login } = require('./auth_manager');
|
|
7
7
|
const buildSystem = require('../build')
|
|
8
8
|
|
|
9
|
-
require('../util/axios').pruneErrors()
|
|
9
|
+
require('../util/axios').pruneErrors();
|
|
10
10
|
const { getMessage } = require('./util/logging');
|
|
11
11
|
const { schemaRegex } = require('./util/urls');
|
|
12
12
|
const { handleHttpError } = require('./util/errors');
|
|
@@ -50,6 +50,7 @@ const CONFIG = {
|
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
let keytar;
|
|
53
|
+
let keytarDisabled;
|
|
53
54
|
|
|
54
55
|
function other(tokenStorage) {
|
|
55
56
|
if (!tokenStorage) {
|
|
@@ -126,6 +127,14 @@ function getKeyringAccountName(params) {
|
|
|
126
127
|
return `${params.get('appUrl')}|${params.get('subdomain')}`;
|
|
127
128
|
}
|
|
128
129
|
|
|
130
|
+
function getAccountUrl(account) {
|
|
131
|
+
return account.includes('|') ? account.split('|')[0] : null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function getAccountSubdomain(account) {
|
|
135
|
+
return account.includes('|') ? account.split('|')[1] : null;
|
|
136
|
+
}
|
|
137
|
+
|
|
129
138
|
function logConfigPaths() {
|
|
130
139
|
DEBUG?.(`Settings are stored in ${CONFIG.paths.settings}`);
|
|
131
140
|
DEBUG?.(`Authentication data is stored in ${CONFIG.paths.auth} (${TOKEN_STORAGE_DESC.plain}) or ${CONFIG.keyringDesignation} (${TOKEN_STORAGE_DESC.keyring})`);
|
|
@@ -145,6 +154,8 @@ class SettingsManager {
|
|
|
145
154
|
|
|
146
155
|
static init() {
|
|
147
156
|
logConfigPaths();
|
|
157
|
+
keytar = undefined;
|
|
158
|
+
keytarDisabled = undefined;
|
|
148
159
|
}
|
|
149
160
|
|
|
150
161
|
static get config() {
|
|
@@ -175,7 +186,7 @@ class SettingsManager {
|
|
|
175
186
|
if (params.get('clearOtherTokenStorage')) {
|
|
176
187
|
// Delete token from the other storage.
|
|
177
188
|
params.delete('clearOtherTokenStorage');
|
|
178
|
-
await this.deleteToken(params, true);
|
|
189
|
+
await this.deleteToken(params, { fromOtherStorage: true });
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
if (params.get('tokenStorage') === 'plain') {
|
|
@@ -259,7 +270,7 @@ class SettingsManager {
|
|
|
259
270
|
}
|
|
260
271
|
|
|
261
272
|
static async setKeytar(params, logout = false) {
|
|
262
|
-
if (params.get('skipToken')) {
|
|
273
|
+
if (keytar || keytarDisabled || params.get('skipToken')) {
|
|
263
274
|
return;
|
|
264
275
|
}
|
|
265
276
|
if (isBas()) {
|
|
@@ -273,7 +284,7 @@ class SettingsManager {
|
|
|
273
284
|
if (keytar) {
|
|
274
285
|
return;
|
|
275
286
|
}
|
|
276
|
-
|
|
287
|
+
keytarDisabled = true;
|
|
277
288
|
|
|
278
289
|
if (params.get('tokenStorage') === 'keyring' && params.get('saveData')) {
|
|
279
290
|
// Explicit login w/o plain-text storage enabled
|
|
@@ -318,7 +329,19 @@ class SettingsManager {
|
|
|
318
329
|
throw 'Passcode cannot be empty';
|
|
319
330
|
}
|
|
320
331
|
}
|
|
321
|
-
function
|
|
332
|
+
async function addAuthSettings() {
|
|
333
|
+
function removeObsoleteToken() {
|
|
334
|
+
if (params.get('renewLogin') || params.get('tokenExpirationDate') <= Date.now()) {
|
|
335
|
+
DEBUG?.((params.get('renewLogin') ? 'Renewing' : 'Refreshing expired') + ' authentication token');
|
|
336
|
+
params.delete('token');
|
|
337
|
+
params.delete('tokenExpirationDate');
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const auth = {
|
|
342
|
+
plain: await SettingsManager._loadAuthFromFile(params.get('appUrl'), params.get('subdomain')),
|
|
343
|
+
keyring: await SettingsManager._loadAuthFromKeyring(params.get('appUrl'), params.get('subdomain'))
|
|
344
|
+
};
|
|
322
345
|
if (!(auth.keyring.has('tokenStorage') || auth.plain.has('tokenStorage'))) {
|
|
323
346
|
// Saved auth data not present.
|
|
324
347
|
return;
|
|
@@ -348,12 +371,8 @@ class SettingsManager {
|
|
|
348
371
|
|
|
349
372
|
params.merge(auth[storage]);
|
|
350
373
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
if (params.get('renewLogin') || params.get('tokenExpirationDate') <= Date.now()) {
|
|
354
|
-
DEBUG?.((params.get('renewLogin') ? 'Renewing' : 'Refreshing expired') + ' authentication token');
|
|
355
|
-
params.delete('token');
|
|
356
|
-
params.delete('tokenExpirationDate');
|
|
374
|
+
if (params.has('token')) {
|
|
375
|
+
removeObsoleteToken();
|
|
357
376
|
}
|
|
358
377
|
}
|
|
359
378
|
|
|
@@ -387,21 +406,13 @@ class SettingsManager {
|
|
|
387
406
|
}
|
|
388
407
|
}
|
|
389
408
|
|
|
390
|
-
|
|
391
|
-
plain: await this._loadAuthFromFile(params.get('appUrl'), params.get('subdomain')),
|
|
392
|
-
keyring: await this._loadAuthFromKeyring(params.get('appUrl'), params.get('subdomain'))
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
setRelevantAuth(auth);
|
|
396
|
-
if (params.has('token')) {
|
|
397
|
-
removeObsoleteToken();
|
|
398
|
-
}
|
|
409
|
+
await addAuthSettings();
|
|
399
410
|
if (!logout && !params.has('token') && !params.has('refreshToken') && !params.has('passcode') && !params.has('clientsecret') && !params.has('key')) {
|
|
400
411
|
await addPasscode();
|
|
401
412
|
}
|
|
402
413
|
}
|
|
403
414
|
|
|
404
|
-
static async deleteToken(params, fromOtherStorage = false) {
|
|
415
|
+
static async deleteToken(params, { fromOtherStorage = false, invalid = false } = {}) {
|
|
405
416
|
const allParams = params.clone();
|
|
406
417
|
await this.loadAndMergeSettings(allParams, true);
|
|
407
418
|
|
|
@@ -409,11 +420,13 @@ class SettingsManager {
|
|
|
409
420
|
let fromStorage = fromOtherStorage && other(params.get('tokenStorage'));
|
|
410
421
|
const deleteBoth = !fromStorage && allParams.get('tokenStorage') && allParams.get('clearOtherTokenStorage');
|
|
411
422
|
|
|
412
|
-
DEBUG?.(`Deleting authentication data${fromOtherStorage ? ' from other storage' : ''} for ${target}`);
|
|
423
|
+
DEBUG?.(`Deleting${invalid ? ' invalid' : ''} authentication data${fromOtherStorage ? ' from other storage' : ''} for ${target}`);
|
|
413
424
|
|
|
414
425
|
fromStorage = fromStorage || allParams.get('tokenStorage');
|
|
415
426
|
if (!fromStorage) {
|
|
416
|
-
|
|
427
|
+
if (!invalid) {
|
|
428
|
+
console.log('Failed to delete authentication data: none found for', target);
|
|
429
|
+
}
|
|
417
430
|
return;
|
|
418
431
|
}
|
|
419
432
|
|
|
@@ -430,7 +443,7 @@ class SettingsManager {
|
|
|
430
443
|
await this._saveToFile(projectFolder, null);
|
|
431
444
|
}
|
|
432
445
|
|
|
433
|
-
static async
|
|
446
|
+
static async deleteInvalidSettings() {
|
|
434
447
|
const settingsByFolder = await this._loadFromFile(undefined);
|
|
435
448
|
const deletionFolders = [];
|
|
436
449
|
const deletionUrlsAndSubdomains = new Set();
|
|
@@ -451,15 +464,33 @@ class SettingsManager {
|
|
|
451
464
|
const subdomain = urlAndSubdomain.replace(/.*\|/, '');
|
|
452
465
|
const urlReference = Object.values(settingsByFolder).find(settings => settings.appUrl === appUrl && settings.subdomain === subdomain);
|
|
453
466
|
if (!urlReference) {
|
|
454
|
-
await this.deleteToken(new ParamCollection({ appUrl, subdomain }));
|
|
467
|
+
await this.deleteToken(new ParamCollection({ appUrl, subdomain }), { invalid: true });
|
|
455
468
|
}
|
|
456
469
|
}
|
|
457
470
|
console.log('Deleted settings for nonexistent project folders:', deletionFolders.map(folder => ' ' + folder));
|
|
458
471
|
} else {
|
|
459
|
-
console.log('All
|
|
472
|
+
console.log('All saved project folders seem valid');
|
|
460
473
|
}
|
|
461
474
|
}
|
|
462
475
|
|
|
476
|
+
static async deleteInvalidTokens() {
|
|
477
|
+
async function deleteFrom(allAuth) {
|
|
478
|
+
for (const [appUrl, authForUrl = {}] of Object.entries(allAuth)) {
|
|
479
|
+
for (const [subdomain, auth] of Object.entries(authForUrl)) {
|
|
480
|
+
if (!auth.token) {
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
if (auth.tokenExpirationDate <= Date.now()) {
|
|
484
|
+
await SettingsManager.deleteToken(new ParamCollection({ appUrl, subdomain }), { invalid: true });
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
await deleteFrom(await this._loadAuthFromFile(undefined, undefined));
|
|
491
|
+
await deleteFrom(await this._loadAllAuthFromKeyring());
|
|
492
|
+
}
|
|
493
|
+
|
|
463
494
|
static async _saveToFile(projectFolder, paramValues) {
|
|
464
495
|
const paramValuesByFolder = await this._loadFromFile(undefined);
|
|
465
496
|
if (paramValues !== null) {
|
|
@@ -559,7 +590,7 @@ class SettingsManager {
|
|
|
559
590
|
try {
|
|
560
591
|
allAuth = JSON.parse((await fs.promises.readFile(CONFIG.paths.auth)).toString());
|
|
561
592
|
} catch (err) {
|
|
562
|
-
DEBUG?.('
|
|
593
|
+
DEBUG?.('File contains invalid saved auth');
|
|
563
594
|
return emptyData(all);
|
|
564
595
|
}
|
|
565
596
|
|
|
@@ -613,6 +644,26 @@ class SettingsManager {
|
|
|
613
644
|
return new ParamCollection(auth);
|
|
614
645
|
}
|
|
615
646
|
|
|
647
|
+
static async _loadAllAuthFromKeyring() {
|
|
648
|
+
if (!keytar) {
|
|
649
|
+
return {};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
return (await keytar.findCredentials(MTX_FULLY_QUALIFIED))
|
|
653
|
+
.reduce((result, { account, password: authString }) => {
|
|
654
|
+
const appUrl = getAccountUrl(account);
|
|
655
|
+
const subdomain = getAccountSubdomain(account);
|
|
656
|
+
if (appUrl && subdomain) {
|
|
657
|
+
try {
|
|
658
|
+
(result[appUrl] ??= {})[subdomain] = JSON.parse(authString);
|
|
659
|
+
} catch (error) {
|
|
660
|
+
throw new Error(`${capitalize(TOKEN_STORAGE_DESC.keyring)} contains invalid saved auth for URL ${appUrl} and subdomain ${subdomain}`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return result;
|
|
664
|
+
}, {});
|
|
665
|
+
}
|
|
666
|
+
|
|
616
667
|
}
|
|
617
668
|
|
|
618
669
|
module.exports = {
|
package/lib/mtx/tenant_action.js
CHANGED
|
@@ -2,7 +2,7 @@ const cds = require('../cds');
|
|
|
2
2
|
const { ParamCollection } = require('./params');
|
|
3
3
|
const AuthManager = require('./auth_manager');
|
|
4
4
|
|
|
5
|
-
require('../util/axios').pruneErrors()
|
|
5
|
+
require('../util/axios').pruneErrors();
|
|
6
6
|
const { getMessage } = require('./util/logging');
|
|
7
7
|
const { capitalize } = require('./util/strings');
|
|
8
8
|
const { handleHttpError } = require('./util/errors');
|
package/lib/util/axios.js
CHANGED
|
@@ -1,25 +1,7 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
-
pruneErrors
|
|
3
|
-
setReqTimeout
|
|
2
|
+
pruneErrors
|
|
4
3
|
};
|
|
5
4
|
|
|
6
|
-
// Will only count the time until the server starts responding, not the time until the request is finished.
|
|
7
|
-
const GENERIC_REQUEST_TIMEOUT_MS = 1500;
|
|
8
|
-
|
|
9
|
-
function setReqTimeout() {
|
|
10
|
-
require('axios').interceptors.request.use(
|
|
11
|
-
config => {
|
|
12
|
-
config.timeout = GENERIC_REQUEST_TIMEOUT_MS;
|
|
13
|
-
return config;
|
|
14
|
-
},
|
|
15
|
-
error => {
|
|
16
|
-
return Promise.reject(error)
|
|
17
|
-
}
|
|
18
|
-
);
|
|
19
|
-
return module.exports;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
5
|
function pruneErrors() {
|
|
24
6
|
function stacklessError(message) {
|
|
25
7
|
const { stackTraceLimit } = Error;
|
package/lib/util/cf.js
CHANGED
|
@@ -116,7 +116,7 @@ class CfUtil {
|
|
|
116
116
|
if (config) {
|
|
117
117
|
return {
|
|
118
118
|
apiEndpoint: this._extract(config.Target, /\s*(.+)\s*/, `CF API endpoint is missing. Use 'cf login' to login.`),
|
|
119
|
-
org: this._extract(config.OrganizationFields.Name, /\s*(.+)\s*/, `CF org is missing. Use 'cf target -o <ORG> to specify.`),
|
|
119
|
+
org: this._extract(config.OrganizationFields.Name, /\s*(.+)\s*/, `CF org is missing. Use 'cf target -o <ORG>' to specify.`),
|
|
120
120
|
space: this._extract(config.SpaceFields.Name, /\s*(.+)\s*/, `CF space is missing. Use 'cf target -s <SPACE>' to specify.`)
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -131,7 +131,7 @@ class CfUtil {
|
|
|
131
131
|
return {
|
|
132
132
|
apiEndpoint: this._extract(result.stdout, /api endpoint\s*:\s*([^\s]+)/i, `CF API endpoint is missing. Use 'cf login' to login.`),
|
|
133
133
|
user: this._extract(result.stdout, /user\s*:\s*(.+)/i, `CF user is missing. Use 'cf login' to login.`),
|
|
134
|
-
org: this._extract(result.stdout, /org\s*:\s*(.+)/i, `CF org is missing. Use 'cf target -o <ORG> to specify.`),
|
|
134
|
+
org: this._extract(result.stdout, /org\s*:\s*(.+)/i, `CF org is missing. Use 'cf target -o <ORG>' to specify.`),
|
|
135
135
|
space: this._extract(result.stdout, /space\s*:\s*(.+)/i, `CF space is missing. Use 'cf target -s <SPACE>' to specify.`),
|
|
136
136
|
};
|
|
137
137
|
}
|
|
@@ -189,6 +189,14 @@ Deployment will stop in the near future for Cloud Foundry client versions < ${CF
|
|
|
189
189
|
return this.spaceInfo;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
async getServices(app) {
|
|
193
|
+
const { spaceGuid: space_guids, orgGuid: organization_guids } = await this.getCfSpaceInfo();
|
|
194
|
+
const apps = await this._cfRequest('/v3/apps', { space_guids, organization_guids, names: app });
|
|
195
|
+
const guid = apps.resources[0].guid;
|
|
196
|
+
const env = await this._cfRequest('/v3/apps/'+guid+'/env', { space_guids, organization_guids, names: app });
|
|
197
|
+
return Object.values(env.system_env_json.VCAP_SERVICES).flat();
|
|
198
|
+
}
|
|
199
|
+
|
|
192
200
|
async getService(serviceName, showMessage = true) {
|
|
193
201
|
showMessage && console.log(`Getting service ${bold(serviceName)}`);
|
|
194
202
|
const spaceInfo = await this.getCfSpaceInfo();
|
|
@@ -323,15 +331,14 @@ Deployment will stop in the near future for Cloud Foundry client versions < ${CF
|
|
|
323
331
|
}
|
|
324
332
|
|
|
325
333
|
|
|
326
|
-
async getOrCreateServiceKey(serviceInstance, serviceKeyName) {
|
|
327
|
-
|
|
334
|
+
async getOrCreateServiceKey(serviceInstance, serviceKeyName, parameters, { silent = false, create = true } = {}) {
|
|
328
335
|
const serviceKey = await this.getServiceKey(serviceInstance, serviceKeyName, false);
|
|
329
|
-
if (serviceKey) {
|
|
330
|
-
console.log(`Getting service key ${bold(serviceKeyName)}`);
|
|
336
|
+
if (serviceKey || !create) {
|
|
337
|
+
if (serviceKey && !silent) console.log(`Getting service key ${bold(serviceKeyName)}`);
|
|
331
338
|
return serviceKey;
|
|
332
339
|
}
|
|
333
340
|
|
|
334
|
-
console.log(`Creating service key ${bold(serviceKeyName)} - please be patient...`);
|
|
341
|
+
if (!silent) console.log(`Creating service key ${bold(serviceKeyName)} - please be patient...`);
|
|
335
342
|
|
|
336
343
|
const body = {
|
|
337
344
|
type: 'key',
|
|
@@ -343,9 +350,7 @@ Deployment will stop in the near future for Cloud Foundry client versions < ${CF
|
|
|
343
350
|
}
|
|
344
351
|
}
|
|
345
352
|
},
|
|
346
|
-
parameters
|
|
347
|
-
permissions: 'development'
|
|
348
|
-
}
|
|
353
|
+
parameters
|
|
349
354
|
}
|
|
350
355
|
|
|
351
356
|
const postResult = await this._cfRequest('/v3/service_credential_bindings', undefined, body);
|