@sap/cds-dk 6.6.1 → 6.7.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/CHANGELOG.md +32 -1
- package/bin/add.js +5 -3
- package/bin/build/all.js +1 -1
- package/bin/cds.js +10 -8
- package/bin/env.js +4 -6
- package/bin/login.js +6 -4
- package/bin/migrate.js +0 -1
- package/bin/repl.js +1 -1
- package/bin/serve.js +7 -0
- package/bin/subscribe.js +5 -5
- package/bin/unsubscribe.js +4 -5
- package/bin/upgrade.js +67 -0
- package/bin/watch.js +8 -5
- package/lib/bind/bindingManager.js +3 -2
- package/lib/bind/cfKeyProvider.js +7 -6
- package/lib/bind/userCdsrcJsonStorageProvider.js +5 -4
- package/lib/client/activate.js +4 -3
- package/lib/client/auth_manager.js +4 -3
- package/lib/client/base_command.js +7 -2
- package/lib/client/helper/cf_helper.js +12 -11
- package/lib/client/helper/dependency_helper.js +3 -2
- package/lib/client/helper/logging.js +0 -7
- package/lib/client/params.js +4 -2
- package/lib/client/settings_manager.js +35 -34
- package/lib/client/tenant_action.js +78 -0
- package/lib/init/constants.js +1 -1
- package/lib/init/index.js +6 -4
- package/lib/init/template/_merging/registry-mta.js +31 -46
- package/lib/init/template/approuter/files/mta.yaml.hbs +12 -8
- package/lib/init/template/approuter/files/xs-app.json.hbs +0 -3
- package/lib/init/template/approuter/index.js +26 -34
- package/lib/init/template/auditlog/files/mta.yaml.hbs +2 -1
- package/lib/init/template/auditlog/index.js +8 -21
- package/lib/init/template/cf-manifest/files/manifest.yml.hbs +4 -4
- package/lib/init/template/cf-manifest/index.js +2 -1
- package/lib/init/template/connectivity/index.js +4 -5
- package/lib/init/template/data/index.js +19 -22
- package/lib/init/template/destinations/index.js +5 -17
- package/lib/init/template/enterprise-messaging/files/mta.yaml.hbs +2 -1
- package/lib/init/template/enterprise-messaging/index.js +7 -19
- package/lib/init/template/extensibility/index.js +3 -1
- package/lib/init/template/hana/files/mta.yaml.hbs +4 -5
- package/lib/init/template/hana/index.js +49 -84
- package/lib/init/template/helm/chart/templates/_helpers.tpl +4 -1
- package/lib/init/template/helm/files/Chart.yaml.hbs +1 -4
- package/lib/init/template/helm/index.js +45 -13
- package/lib/init/template/html5-repo/index.js +6 -29
- package/lib/init/template/java/index.js +1 -1
- package/lib/init/template/kibana-logging/files/mta.yaml.hbs +2 -1
- package/lib/init/template/kibana-logging/index.js +5 -8
- package/lib/init/template/lint/index.js +8 -8
- package/lib/init/template/mta/files/mta.yaml.hbs +3 -2
- package/lib/init/template/mta/index.js +3 -2
- package/lib/init/template/multitenancy/files/mta.yaml.hbs +25 -31
- package/lib/init/template/multitenancy/files/{java/mtxs-configmap.yaml → mtxs-configmap-java.yaml} +1 -1
- package/lib/init/template/multitenancy/files/{mtxs-configmap.yaml → mtxs-configmap-nodejs.yaml} +5 -1
- package/lib/init/template/multitenancy/files/package.json.hbs +28 -0
- package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +21 -0
- package/lib/init/template/multitenancy/files/values.yaml.hbs +15 -8
- package/lib/init/template/multitenancy/index.js +51 -99
- package/lib/init/template/nodejs/files/.vscode/extensions.json +1 -2
- package/lib/init/template/nodejs/files/.vscode/launch.json +2 -2
- package/lib/init/template/nodejs/files/.vscode/tasks.json +2 -2
- package/lib/init/template/nodejs/files/package.json.hbs +2 -2
- package/lib/init/template/nodejs/index.js +4 -3
- package/lib/init/template/pipeline/index.js +3 -2
- package/lib/init/template/samples/index.js +5 -4
- package/lib/init/template/sqlite/files/package.json.hbs +19 -0
- package/lib/init/template/sqlite/index.js +11 -0
- package/lib/init/template/toggles/index.js +3 -5
- package/lib/init/template/xsuaa/files/mta.yaml.hbs +4 -5
- package/lib/init/template/xsuaa/files/values.yaml.hbs +0 -2
- package/lib/init/template/xsuaa/index.js +14 -35
- package/lib/init/util/commandUtil.js +3 -2
- package/lib/init/util/fsUtil.js +19 -2
- package/lib/init/util/md5Tracking.js +36 -63
- package/lib/init/util/projectReader.js +13 -27
- package/lib/lint/Linter.js +0 -3
- package/lib/util/exec.js +2 -1
- package/lib/util/term.js +1 -1
- package/lib/watch/livereload-connect.js +5 -4
- package/lib/watch/livereload-server.js +3 -6
- package/lib/watch/node-watch.js +1 -1
- package/npm-shrinkwrap.json +91 -105
- package/package.json +4 -4
- package/readme.md +1 -1
- package/lib/client/subscription.js +0 -84
- package/lib/init/template/approuter/files/chart.yaml +0 -4
- package/lib/init/template/auditlog/files/auditlog.yaml +0 -4
- package/lib/init/template/destinations/files/destination.yaml +0 -4
- package/lib/init/template/enterprise-messaging/files/event-mesh.yaml +0 -4
- package/lib/init/template/hana/files/hana-deployer.yaml +0 -4
- package/lib/init/template/hana/files/hana.yaml +0 -4
- package/lib/init/template/html5-repo/files/html5-apps-deployer.yaml +0 -4
- package/lib/init/template/html5-repo/files/html5-apps-repo-host.yaml +0 -4
- package/lib/init/template/multitenancy/files/cds.package.json +0 -7
- package/lib/init/template/multitenancy/files/cds.package.json.hbs +0 -9
- package/lib/init/template/multitenancy/files/dependencies.package.json +0 -5
- package/lib/init/template/multitenancy/files/java/.cdsrc.json +0 -22
- package/lib/init/template/multitenancy/files/java/package.json +0 -33
- package/lib/init/template/multitenancy/files/saas-registry.yaml +0 -4
- package/lib/init/template/multitenancy/files/service-manager.yaml +0 -4
- package/lib/init/template/multitenancy/files/sidecar.yaml +0 -4
- package/lib/init/template/xsuaa/files/xsuaa.yaml +0 -4
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const os = require('os');
|
|
2
2
|
const { execFile } = require('child_process');
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const cds = require('../../cds');
|
|
5
|
+
const DEBUG = cds.debug('cli');
|
|
5
6
|
const Question = require('./question');
|
|
6
7
|
const { formatObjectsFixedWidth } = require('./string_helper');
|
|
7
8
|
const { schemaRegex } = require('./url_helper');
|
|
@@ -20,7 +21,7 @@ function getErrorMessage(error, stdout) {
|
|
|
20
21
|
async function getAppFromSuggestions() {
|
|
21
22
|
const apps = await getApps();
|
|
22
23
|
if (apps.length === 0) {
|
|
23
|
-
|
|
24
|
+
DEBUG?.('Failed to obtain list of apps from CF');
|
|
24
25
|
return undefined;
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -36,7 +37,7 @@ Your choice: `);
|
|
|
36
37
|
console.log();
|
|
37
38
|
|
|
38
39
|
if (!choice) {
|
|
39
|
-
|
|
40
|
+
DEBUG?.('No app URL selected');
|
|
40
41
|
return undefined;
|
|
41
42
|
}
|
|
42
43
|
choiceNr = Number(choice);
|
|
@@ -46,7 +47,7 @@ Your choice: `);
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
async function getApps(nameRegex = /(?<!-db)$/) {
|
|
49
|
-
|
|
50
|
+
DEBUG?.('Getting running apps from CF');
|
|
50
51
|
|
|
51
52
|
return new Promise(resolve => {
|
|
52
53
|
runCf(['apps'], function(error, stdout) {
|
|
@@ -120,13 +121,13 @@ async function getApps(nameRegex = /(?<!-db)$/) {
|
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
function errorResult(message) {
|
|
123
|
-
|
|
124
|
+
DEBUG?.(`Failed to get apps: ${message}`);
|
|
124
125
|
return [];
|
|
125
126
|
}
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
async function getSubdomain(appName) {
|
|
129
|
-
|
|
130
|
+
DEBUG?.('Getting subdomain from CF env');
|
|
130
131
|
|
|
131
132
|
return new Promise(resolve => {
|
|
132
133
|
runCf(['env', appName], function(error, stdout) {
|
|
@@ -155,13 +156,13 @@ async function getSubdomain(appName) {
|
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
|
|
159
|
+
DEBUG?.(`Subdomain determined from CF app environment: ${value}`);
|
|
159
160
|
return resolve(value);
|
|
160
161
|
});
|
|
161
162
|
});
|
|
162
163
|
|
|
163
164
|
function errorResult(message) {
|
|
164
|
-
|
|
165
|
+
DEBUG?.(`Failed to get subdomain: ${message}`);
|
|
165
166
|
return undefined;
|
|
166
167
|
}
|
|
167
168
|
}
|
|
@@ -171,14 +172,14 @@ async function getAppName(appUrl) {
|
|
|
171
172
|
return url1.replace(schemaRegex, '') === url2.replace(schemaRegex, '');
|
|
172
173
|
}
|
|
173
174
|
|
|
174
|
-
|
|
175
|
+
DEBUG?.('Getting app name from CF apps');
|
|
175
176
|
const apps = await getApps();
|
|
176
177
|
const app = apps.find(app => equalIgnoringTls(app.url, appUrl));
|
|
177
178
|
if (!app) {
|
|
178
|
-
|
|
179
|
+
DEBUG?.(`Failed to find app with URL ${appUrl}. Running apps: ${apps.map(app => app.name)}`);
|
|
179
180
|
return;
|
|
180
181
|
}
|
|
181
|
-
|
|
182
|
+
DEBUG?.(`App name determined from CF: ${app.name}`);
|
|
182
183
|
return app.name;
|
|
183
184
|
}
|
|
184
185
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const os = require('os');
|
|
2
2
|
const { execFileSync } = require('child_process');
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const cds = require('../../cds');
|
|
5
|
+
const DEBUG = cds.debug('cli');
|
|
5
6
|
|
|
6
7
|
let cachedDir;
|
|
7
8
|
|
|
@@ -21,7 +22,7 @@ function requireGlobal(packageId) {
|
|
|
21
22
|
return require(packagePath);
|
|
22
23
|
} catch (error) {
|
|
23
24
|
// Ignore error.
|
|
24
|
-
|
|
25
|
+
DEBUG?.(`Failed to find module '${packageId}' in ${globalModulesDir()}`, error);
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
|
|
3
|
-
function debug(debugText, error) {
|
|
4
|
-
if (process.env.DEBUG) {
|
|
5
|
-
console.log(getMessage(debugText, { error }));
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
3
|
function getMessage(errorText, { error, help } = {}) {
|
|
10
4
|
let message = errorText ? errorText : '';
|
|
11
5
|
if (error) {
|
|
@@ -25,6 +19,5 @@ function getMessage(errorText, { error, help } = {}) {
|
|
|
25
19
|
}
|
|
26
20
|
|
|
27
21
|
module.exports = {
|
|
28
|
-
debug,
|
|
29
22
|
getMessage
|
|
30
23
|
};
|
package/lib/client/params.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const
|
|
1
|
+
const cds = require('../cds');
|
|
2
|
+
const DEBUG = cds.debug('cli');
|
|
2
3
|
const { escapeRegex } = require('./helper/string_helper');
|
|
3
4
|
const { CliError } = require('./helper/errors');
|
|
4
5
|
|
|
@@ -179,6 +180,7 @@ class BasicParams {
|
|
|
179
180
|
this.url = this.appUrl.newAlias('url');
|
|
180
181
|
this.from = this.appUrl.newAlias('from');
|
|
181
182
|
this.to = this.appUrl.newAlias('to');
|
|
183
|
+
this.at = this.appUrl.newAlias('at');
|
|
182
184
|
this.subdomain = new Param('subdomain', '', { persist: Persistence.setting }); // only needed to fetch token
|
|
183
185
|
this.passcodeUrl = new Param('passcodeUrl', '', { persist: Persistence.setting, abbreviate: true });
|
|
184
186
|
this.passcode_url = this.passcodeUrl.newAlias('passcode_url');
|
|
@@ -316,7 +318,7 @@ class ParamCollection {
|
|
|
316
318
|
this.params[mainName] = ParamDefs[mainName].clone(val);
|
|
317
319
|
}
|
|
318
320
|
if (mainName !== name) {
|
|
319
|
-
|
|
321
|
+
DEBUG?.(`Migrated setting '${name}' to new key '${mainName}'`);
|
|
320
322
|
}
|
|
321
323
|
}
|
|
322
324
|
|
|
@@ -3,10 +3,9 @@ const os = require('os');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const axios = require('axios');
|
|
5
5
|
|
|
6
|
+
const cds = require('../cds');
|
|
7
|
+
const DEBUG = cds.debug('cli');
|
|
6
8
|
const { requireGlobal } = require('./helper/dependency_helper');
|
|
7
|
-
let keytar;
|
|
8
|
-
|
|
9
|
-
const log = require('./helper/logging');
|
|
10
9
|
const { getAppFromSuggestions, getAppName, getSubdomain } = require('./helper/cf_helper');
|
|
11
10
|
const isBas = require('./helper/env_helper');
|
|
12
11
|
const Question = require('./helper/question');
|
|
@@ -49,6 +48,8 @@ const CONFIG = {
|
|
|
49
48
|
keyringDesignation: KEYRING_DESC[os.platform()] || 'not supported'
|
|
50
49
|
};
|
|
51
50
|
|
|
51
|
+
let keytar;
|
|
52
|
+
|
|
52
53
|
function other(tokenStorage) {
|
|
53
54
|
if (!tokenStorage) {
|
|
54
55
|
return tokenStorage;
|
|
@@ -130,14 +131,14 @@ function getKeyringAccountName(params) {
|
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
function logConfigPaths() {
|
|
133
|
-
|
|
134
|
-
|
|
134
|
+
DEBUG?.(`Settings are stored in ${CONFIG.paths.settings}`);
|
|
135
|
+
DEBUG?.(`Authentication data is stored in ${CONFIG.paths.auth} (${TOKEN_STORAGE_DESC.plain}) or ${CONFIG.keyringDesignation} (${TOKEN_STORAGE_DESC.keyring})`);
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
function notifyLoggedIn(params) {
|
|
138
139
|
return params.get('renewLogin')
|
|
139
140
|
? console.log.bind(console)
|
|
140
|
-
:
|
|
141
|
+
: DEBUG;
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
function emptyData(all) {
|
|
@@ -156,7 +157,7 @@ class SettingsManager {
|
|
|
156
157
|
|
|
157
158
|
// Call with 'projectFolder' param as a resolved path.
|
|
158
159
|
static async saveSettings(params) {
|
|
159
|
-
|
|
160
|
+
DEBUG?.(`Saving settings for project ${params.get('projectFolder')}`);
|
|
160
161
|
|
|
161
162
|
const paramsMap = params.toEntries(Persistence.setting);
|
|
162
163
|
if (params.has('username')) {
|
|
@@ -164,7 +165,7 @@ class SettingsManager {
|
|
|
164
165
|
if (localhostRegex.test(params.get('appUrl'))) {
|
|
165
166
|
console.log(`Saving username${(params.get('isEmptyPassword') ? ' and empty-password hint' : '')} with project settings.`);
|
|
166
167
|
} else {
|
|
167
|
-
|
|
168
|
+
DEBUG?.('Not saving username because app is not recognized to run on localhost.');
|
|
168
169
|
delete paramsMap.username;
|
|
169
170
|
delete paramsMap.isEmptyPassword;
|
|
170
171
|
}
|
|
@@ -196,7 +197,7 @@ class SettingsManager {
|
|
|
196
197
|
params.set('projectFolder', projectFolder);
|
|
197
198
|
|
|
198
199
|
const loadedSettings = await this._loadFromFile(projectFolder);
|
|
199
|
-
|
|
200
|
+
DEBUG?.(`Loaded project settings for ${params.get('projectFolder')}: ${loadedSettings.format()}`);
|
|
200
201
|
const loadedAppUrl = loadedSettings.get('appUrl');
|
|
201
202
|
|
|
202
203
|
if (params.has('passcode') && loadedSettings.has('username')) {
|
|
@@ -213,7 +214,7 @@ class SettingsManager {
|
|
|
213
214
|
await this.updateUrls(params, logout, loadedAppUrl);
|
|
214
215
|
await this.setKeytar(params, logout);
|
|
215
216
|
await this.addAuth(params, logout);
|
|
216
|
-
|
|
217
|
+
DEBUG?.(`Effective project settings: ${params.format()}`);
|
|
217
218
|
}
|
|
218
219
|
|
|
219
220
|
static async updateUrls(params, logout, loadedAppUrl) {
|
|
@@ -232,20 +233,20 @@ class SettingsManager {
|
|
|
232
233
|
} else {
|
|
233
234
|
params.set('appUrl', httpsSchema + appUrl);
|
|
234
235
|
}
|
|
235
|
-
|
|
236
|
+
DEBUG?.(`Added schema to app URL: ${params.get('appUrl')}`);
|
|
236
237
|
}
|
|
237
238
|
}
|
|
238
239
|
|
|
239
240
|
if (!logout) {
|
|
240
241
|
// Get appUrl from CF
|
|
241
242
|
if (!params.has('appUrl')) {
|
|
242
|
-
|
|
243
|
+
DEBUG?.('App URL not given');
|
|
243
244
|
await getAppUrlAndSubdomainFromSuggestions(params);
|
|
244
245
|
}
|
|
245
246
|
|
|
246
247
|
// Get subdomain from CF
|
|
247
248
|
if (!params.has('subdomain') && needsSubdomain()) {
|
|
248
|
-
|
|
249
|
+
DEBUG?.('Subdomain not given');
|
|
249
250
|
const appName = await getAppName(params.get('appUrl'));
|
|
250
251
|
if (appName) {
|
|
251
252
|
params.set('subdomain', await getSubdomainFromCfAndNotify(appName));
|
|
@@ -307,8 +308,8 @@ class SettingsManager {
|
|
|
307
308
|
|
|
308
309
|
const doLog = params.get('saveData') || logout
|
|
309
310
|
? console.log.bind(console) // Explicit login/logout call
|
|
310
|
-
:
|
|
311
|
-
doLog(`Disabling ${TOKEN_STORAGE_DESC.keyring} functionality: keytar not found. Run \`npm install -g keytar\` to install it.`);
|
|
311
|
+
: DEBUG;
|
|
312
|
+
doLog?.(`Disabling ${TOKEN_STORAGE_DESC.keyring} functionality: keytar not found. Run \`npm install -g keytar\` to install it.`);
|
|
312
313
|
}
|
|
313
314
|
|
|
314
315
|
static async addAuth(params, logout) {
|
|
@@ -344,7 +345,7 @@ class SettingsManager {
|
|
|
344
345
|
if (auth.keyring.has('tokenStorage') && auth.plain.has('tokenStorage')) {
|
|
345
346
|
// Both storage places contain data: retrieve from selected or keyring.
|
|
346
347
|
storage = storage || 'keyring';
|
|
347
|
-
|
|
348
|
+
DEBUG?.('WARNING: authentication data found in both kinds of storage. ' +
|
|
348
349
|
`Using data from ${TOKEN_STORAGE_DESC[storage]}; other storage will be cleared when next saving.`);
|
|
349
350
|
|
|
350
351
|
params.merge(auth[storage]);
|
|
@@ -352,7 +353,7 @@ class SettingsManager {
|
|
|
352
353
|
|
|
353
354
|
} else if (storage && auth[other(storage)].has('tokenStorage')) {
|
|
354
355
|
// Selected storage contains no data, but other one does: retrieve from other storage, but earmark migration to selected one.
|
|
355
|
-
|
|
356
|
+
DEBUG?.(`Using authentication data from ${TOKEN_STORAGE_DESC[other(storage)]}; will be migrated to other storage on save.`);
|
|
356
357
|
|
|
357
358
|
params.merge(auth[other(storage)]);
|
|
358
359
|
params.set('tokenStorage', storage);
|
|
@@ -361,7 +362,7 @@ class SettingsManager {
|
|
|
361
362
|
} else {
|
|
362
363
|
// One storage contains data, and there's no conflict with selection.
|
|
363
364
|
const storage = auth.keyring.get('tokenStorage') || auth.plain.get('tokenStorage');
|
|
364
|
-
|
|
365
|
+
DEBUG?.(`Using authentication data from ${TOKEN_STORAGE_DESC[storage]}.`);
|
|
365
366
|
|
|
366
367
|
params.merge(auth[storage]);
|
|
367
368
|
}
|
|
@@ -376,7 +377,7 @@ class SettingsManager {
|
|
|
376
377
|
} else {
|
|
377
378
|
params.delete('isEmptyPassword');
|
|
378
379
|
}
|
|
379
|
-
|
|
380
|
+
DEBUG?.('Ignoring any saved authentication data because username is given');
|
|
380
381
|
return;
|
|
381
382
|
} else {
|
|
382
383
|
params.delete('isEmptyPassword');
|
|
@@ -410,7 +411,7 @@ class SettingsManager {
|
|
|
410
411
|
let fromStorage = fromOtherStorage && other(params.get('tokenStorage'));
|
|
411
412
|
const deleteBoth = !fromStorage && allParams.get('tokenStorage') && allParams.get('clearOtherTokenStorage');
|
|
412
413
|
|
|
413
|
-
|
|
414
|
+
DEBUG?.(`Deleting authentication data${fromOtherStorage ? ' from other storage' : ''} for ${target}`);
|
|
414
415
|
|
|
415
416
|
fromStorage = fromStorage || allParams.get('tokenStorage');
|
|
416
417
|
if (!fromStorage) {
|
|
@@ -466,7 +467,7 @@ class SettingsManager {
|
|
|
466
467
|
if (paramValues !== null) {
|
|
467
468
|
paramValuesByFolder[projectFolder] = paramValues;
|
|
468
469
|
await this._saveAllSettingsToFile(paramValuesByFolder);
|
|
469
|
-
|
|
470
|
+
DEBUG?.(`Saved project settings: ${JSON.stringify(paramValues)}`);
|
|
470
471
|
} else {
|
|
471
472
|
delete paramValuesByFolder[projectFolder];
|
|
472
473
|
await this._saveAllSettingsToFile(paramValuesByFolder);
|
|
@@ -475,10 +476,10 @@ class SettingsManager {
|
|
|
475
476
|
}
|
|
476
477
|
|
|
477
478
|
static async _saveAllSettingsToFile(paramValuesByFolder) {
|
|
478
|
-
|
|
479
|
+
DEBUG?.(`Saving all settings to ${CONFIG.paths.settings}`);
|
|
479
480
|
await fs.promises.mkdir(path.dirname(CONFIG.paths.settings), { recursive: true })
|
|
480
481
|
await fs.promises.writeFile(CONFIG.paths.settings, JSON.stringify(paramValuesByFolder, null, 2));
|
|
481
|
-
|
|
482
|
+
DEBUG?.('Saved settings');
|
|
482
483
|
}
|
|
483
484
|
|
|
484
485
|
static async _saveAuthToFile(params, authValues) {
|
|
@@ -490,7 +491,7 @@ class SettingsManager {
|
|
|
490
491
|
(allAuthValues[appUrl] || (allAuthValues[appUrl] = {}))[params.get('subdomain')] = authValues;
|
|
491
492
|
await fs.promises.mkdir(path.dirname(CONFIG.paths.auth), { recursive: true })
|
|
492
493
|
await fs.promises.writeFile(CONFIG.paths.auth, JSON.stringify(allAuthValues, null, 2));
|
|
493
|
-
notifyLoggedIn(params)(`Saved authentication data to ${location}`);
|
|
494
|
+
notifyLoggedIn(params)?.(`Saved authentication data to ${location}`);
|
|
494
495
|
} else if (allAuthValues[appUrl]) {
|
|
495
496
|
delete allAuthValues[appUrl][params.get('subdomain')];
|
|
496
497
|
if (Object.keys(allAuthValues[appUrl]).length === 0) {
|
|
@@ -500,7 +501,7 @@ class SettingsManager {
|
|
|
500
501
|
await fs.promises.writeFile(CONFIG.paths.auth, JSON.stringify(allAuthValues, null, 2));
|
|
501
502
|
console.log('Deleted authentication data from', location);
|
|
502
503
|
} else {
|
|
503
|
-
notifyLoggedIn(params)(`No authentication data to delete from ${location}`);
|
|
504
|
+
notifyLoggedIn(params)?.(`No authentication data to delete from ${location}`);
|
|
504
505
|
}
|
|
505
506
|
}
|
|
506
507
|
|
|
@@ -513,7 +514,7 @@ class SettingsManager {
|
|
|
513
514
|
|
|
514
515
|
if (auth !== null) {
|
|
515
516
|
await keytar.setPassword(MTX_FULLY_QUALIFIED, getKeyringAccountName(params), JSON.stringify(auth));
|
|
516
|
-
notifyLoggedIn(params)(`Saved authentication data to ${location}`);
|
|
517
|
+
notifyLoggedIn(params)?.(`Saved authentication data to ${location}`);
|
|
517
518
|
} else {
|
|
518
519
|
await keytar.deletePassword(MTX_FULLY_QUALIFIED, getKeyringAccountName(params));
|
|
519
520
|
console.log('Deleted authentication data from', location);
|
|
@@ -524,7 +525,7 @@ class SettingsManager {
|
|
|
524
525
|
const all = !projectFolder;
|
|
525
526
|
|
|
526
527
|
if (!fs.existsSync(CONFIG.paths.settings)) {
|
|
527
|
-
|
|
528
|
+
DEBUG?.('Settings file not found');
|
|
528
529
|
return emptyData(all);
|
|
529
530
|
}
|
|
530
531
|
|
|
@@ -532,7 +533,7 @@ class SettingsManager {
|
|
|
532
533
|
try {
|
|
533
534
|
settingsByFolder = JSON.parse((await fs.promises.readFile(CONFIG.paths.settings)).toString());
|
|
534
535
|
} catch (err) {
|
|
535
|
-
|
|
536
|
+
DEBUG?.('Empty settings file');
|
|
536
537
|
return emptyData(all);
|
|
537
538
|
}
|
|
538
539
|
|
|
@@ -541,7 +542,7 @@ class SettingsManager {
|
|
|
541
542
|
}
|
|
542
543
|
|
|
543
544
|
if (!settingsByFolder[projectFolder]) {
|
|
544
|
-
|
|
545
|
+
DEBUG?.(`No settings found for project ${projectFolder}`);
|
|
545
546
|
return new ParamCollection();
|
|
546
547
|
}
|
|
547
548
|
|
|
@@ -552,7 +553,7 @@ class SettingsManager {
|
|
|
552
553
|
const all = !appUrl;
|
|
553
554
|
|
|
554
555
|
if (!fs.existsSync(CONFIG.paths.auth)) {
|
|
555
|
-
|
|
556
|
+
DEBUG?.('Authentication-data file not found');
|
|
556
557
|
return emptyData(all);
|
|
557
558
|
}
|
|
558
559
|
|
|
@@ -560,7 +561,7 @@ class SettingsManager {
|
|
|
560
561
|
try {
|
|
561
562
|
allAuth = JSON.parse((await fs.promises.readFile(CONFIG.paths.auth)).toString());
|
|
562
563
|
} catch (err) {
|
|
563
|
-
|
|
564
|
+
DEBUG?.('Empty authentication-data file');
|
|
564
565
|
return emptyData(all);
|
|
565
566
|
}
|
|
566
567
|
|
|
@@ -569,14 +570,14 @@ class SettingsManager {
|
|
|
569
570
|
}
|
|
570
571
|
|
|
571
572
|
if (!allAuth[appUrl]) {
|
|
572
|
-
|
|
573
|
+
DEBUG?.(`File contains no authentication data for app URL ${appUrl}`);
|
|
573
574
|
return new ParamCollection();
|
|
574
575
|
}
|
|
575
576
|
|
|
576
577
|
const authForSubdomain = allAuth[appUrl][subdomain];
|
|
577
578
|
|
|
578
579
|
if (!authForSubdomain) {
|
|
579
|
-
|
|
580
|
+
DEBUG?.(`File contains no authentication data for subdomain ${subdomain} (app URL: ${appUrl})`);
|
|
580
581
|
return new ParamCollection();
|
|
581
582
|
}
|
|
582
583
|
|
|
@@ -595,7 +596,7 @@ class SettingsManager {
|
|
|
595
596
|
const authString = await keytar.getPassword(MTX_FULLY_QUALIFIED, getKeyringAccountName(new ParamCollection({ appUrl, subdomain })));
|
|
596
597
|
|
|
597
598
|
if (!authString) {
|
|
598
|
-
|
|
599
|
+
DEBUG?.(`${capitalize(TOKEN_STORAGE_DESC.keyring)} contains no authentication data for URL ${appUrl} and subdomain '${subdomain}'`);
|
|
599
600
|
return new ParamCollection();
|
|
600
601
|
}
|
|
601
602
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const cds = require('../cds');
|
|
2
|
+
const DEBUG = cds.debug('cli');
|
|
3
|
+
|
|
4
|
+
const BaseCommand = require('./base_command');
|
|
5
|
+
const { CliError } = require('./helper/errors');
|
|
6
|
+
const { ParamCollection } = require('./params');
|
|
7
|
+
const AuthManager = require('./auth_manager');
|
|
8
|
+
const { capitalize } = require('./helper/string_helper');
|
|
9
|
+
|
|
10
|
+
const COMMANDS = {
|
|
11
|
+
subscribe: 'to',
|
|
12
|
+
upgrade: 'at',
|
|
13
|
+
unsubscribe: 'from'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
module.exports = class TenantAction extends BaseCommand {
|
|
17
|
+
|
|
18
|
+
// TODO JSDoc
|
|
19
|
+
/**
|
|
20
|
+
* @param command {string} the command to execute: 'subscribe', 'upgrade' or 'unsubscribe'
|
|
21
|
+
*/
|
|
22
|
+
constructor(command) {
|
|
23
|
+
if (!(command in COMMANDS)) {
|
|
24
|
+
throw new Error(`invalid command: ${command}`);
|
|
25
|
+
}
|
|
26
|
+
super();
|
|
27
|
+
this.command = command;
|
|
28
|
+
this.gerund = command.replace(/e$/, 'ing');
|
|
29
|
+
this.preposition = COMMANDS[command];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async run(paramValues, { tenant, local } = {}) {
|
|
33
|
+
let params = new ParamCollection(paramValues);
|
|
34
|
+
params.set('skipToken', true); // Token would have insufficient scopes for this command.
|
|
35
|
+
if (local) {
|
|
36
|
+
// Connect to locally-served MTXS
|
|
37
|
+
await this.runWithServer(params, tenant);
|
|
38
|
+
} else {
|
|
39
|
+
// Connect to running MTXS server
|
|
40
|
+
params = await AuthManager.login(params.toEntries());
|
|
41
|
+
await this.runClientOnly(params, tenant);
|
|
42
|
+
}
|
|
43
|
+
console.log(`${capitalize(this.command)} successful.`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async runClientOnly(params, tenant) {
|
|
47
|
+
console.log(capitalize(this.gerund), { tenant }, this.preposition, { url: params.get('appUrl') });
|
|
48
|
+
const url = `${params.get('appUrl')}/-/cds/deployment/${this.command}`;
|
|
49
|
+
DEBUG?.(`Sending request to ${url}`);
|
|
50
|
+
try {
|
|
51
|
+
await require('axios').post(url, { tenant }, params.get('reqAuth'));
|
|
52
|
+
} catch (error) {
|
|
53
|
+
BaseCommand.handleHttpError(error, params, { url });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async runWithServer(params, tenant) {
|
|
58
|
+
const libId = '@sap/cds-mtxs/bin/cds-mtx';
|
|
59
|
+
let libPath;
|
|
60
|
+
try {
|
|
61
|
+
libPath = require.resolve(libId, { paths: [process.cwd()] });
|
|
62
|
+
DEBUG?.(`Using local @sap/cds-mtxs from ${libPath}`);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
try {
|
|
65
|
+
libPath = require.resolve(libId);
|
|
66
|
+
DEBUG?.(`Using cds-mtxs from ${libPath}`);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
throw new CliError('@sap/cds-mtxs not found or outdated. Have you changed into the directory of your SaaS app? If so, please upgrade to @sap/cds-mtxs@>=1.7.0', { error, command: this.command });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { cds_mtx } = require(libPath);
|
|
73
|
+
if (!cds_mtx) {
|
|
74
|
+
throw new CliError('@sap/cds-mtxs outdated. Please upgrade to @sap/cds-mtxs@>=1.7.0 and re-run this command.');
|
|
75
|
+
}
|
|
76
|
+
return cds_mtx(this.command, tenant);
|
|
77
|
+
}
|
|
78
|
+
}
|
package/lib/init/constants.js
CHANGED
package/lib/init/index.js
CHANGED
|
@@ -10,7 +10,7 @@ const { OPTIONS_PRIORITY, COMMAND_ADD, COMMAND_INIT,
|
|
|
10
10
|
|
|
11
11
|
const cds = require('../cds'), { exists, readdir } = cds.utils
|
|
12
12
|
const LOG = console
|
|
13
|
-
const DEBUG = /\b(y|all|cli)\b/.test(process.env.DEBUG)
|
|
13
|
+
const DEBUG = /\b(y|all|cli)\b/.test(process.env.DEBUG) ? console.debug : undefined
|
|
14
14
|
|
|
15
15
|
module.exports = class CDSGenerator {
|
|
16
16
|
constructor() {
|
|
@@ -24,6 +24,8 @@ module.exports = class CDSGenerator {
|
|
|
24
24
|
target: 'projectName',
|
|
25
25
|
validate: async (value) => {
|
|
26
26
|
try {
|
|
27
|
+
cds.root = path.resolve(this.cwd, value || '.');
|
|
28
|
+
|
|
27
29
|
await this._validateProjectName(value);
|
|
28
30
|
await this._validateProjectFolder(path.join(this.cwd, value), this.cwd);
|
|
29
31
|
|
|
@@ -194,7 +196,7 @@ module.exports = class CDSGenerator {
|
|
|
194
196
|
}
|
|
195
197
|
|
|
196
198
|
async _process() {
|
|
197
|
-
DEBUG
|
|
199
|
+
DEBUG?.(`Project path: ${cds.root}`);
|
|
198
200
|
|
|
199
201
|
await this._validateOptions();
|
|
200
202
|
await this._fillTemplateList();
|
|
@@ -238,7 +240,7 @@ module.exports = class CDSGenerator {
|
|
|
238
240
|
const template = await this._createTemplate(option);
|
|
239
241
|
|
|
240
242
|
if (await template.canRun()) {
|
|
241
|
-
DEBUG
|
|
243
|
+
DEBUG?.(`Adding feature '${template.name}'`);
|
|
242
244
|
|
|
243
245
|
templates.set(option, template);
|
|
244
246
|
const deps = await template.getDependencies();
|
|
@@ -254,7 +256,7 @@ module.exports = class CDSGenerator {
|
|
|
254
256
|
}).map((entry) => entry[1]);
|
|
255
257
|
|
|
256
258
|
// check debug to avoid lengthy computation when not in debug mode
|
|
257
|
-
DEBUG
|
|
259
|
+
DEBUG?.(`Features: ${this.templateList.map(({name}) => name).join(', ')}`);
|
|
258
260
|
}
|
|
259
261
|
|
|
260
262
|
async stepEnd() {
|