@sap/cds-dk 6.0.2 → 6.1.1
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 +63 -0
- package/bin/add.js +29 -16
- package/bin/cds.js +7 -3
- package/bin/compile/index.js +6 -1
- package/bin/deploy/index.js +7 -1
- package/bin/fix-redirects.js +4 -2
- package/bin/init.js +5 -0
- package/bin/login.js +8 -2
- package/bin/pull.js +58 -0
- package/bin/push.js +52 -0
- package/bin/subscribe.js +45 -0
- package/lib/bind/bindingResolver.js +1 -2
- package/lib/bind/bindingUtil.js +1 -2
- package/lib/bind/cfKeyProvider.js +3 -3
- package/lib/client/activate.js +1 -1
- package/lib/client/auth_manager.js +7 -3
- package/lib/client/extend.js +1 -1
- package/lib/client/helper/cf_helper.js +1 -0
- package/lib/client/helper/url_helper.js +7 -3
- package/lib/client/index.js +1 -1
- package/lib/client/params.js +4 -2
- package/lib/client/pull.js +51 -0
- package/lib/client/push.js +49 -0
- package/lib/client/settings_manager.js +74 -21
- package/lib/compile/openapi/csdl2openapi.js +135 -163
- package/lib/compile/openapi/index.js +0 -1
- package/lib/import/common.js +9 -1
- package/lib/import/odata/metadataconverter/MetadataConverter.js +17 -4
- package/lib/import/odata/v2parser.js +0 -1
- package/lib/import/odata/v4parser.js +103 -29
- package/lib/import/openapi/importOpenAPI.js +3 -3
- package/lib/init/constants.js +9 -3
- package/lib/init/template/_merging/registry-mta.js +290 -0
- package/lib/init/template/approuter/index.js +22 -32
- package/lib/init/template/auditlog/index.js +7 -9
- package/lib/init/template/extensibility/files/cds.package.json +7 -0
- package/lib/init/template/extensibility/files/cds.package.json.hbs +9 -0
- package/lib/init/template/extensibility/files/xs-security.json.hbs +26 -0
- package/lib/init/template/extensibility/index.js +48 -0
- package/lib/init/template/hana/files/java/cdsrc.json.hbs +1 -1
- package/lib/init/template/hana/files/java/profile.cdsrc.json.hbs +2 -2
- package/lib/init/template/hana/files/mta.yaml.hbs +10 -0
- package/lib/init/template/hana/files/nodejs/cds.package.json.hbs +1 -1
- package/lib/init/template/hana/files/nodejs/cds.profile.package.json.hbs +2 -2
- package/lib/init/template/hana/index.js +76 -63
- package/lib/init/template/kibana-logging/index.js +31 -37
- package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +14 -14
- package/lib/init/template/lint/index.js +1 -1
- package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
- package/lib/init/template/mta/index.js +13 -7
- package/lib/init/template/mtx/index.js +2 -142
- package/lib/init/template/multitenancy/files/cds.package.json +7 -0
- package/lib/init/template/multitenancy/files/cds.package.json.hbs +9 -0
- package/lib/init/template/{mtx → multitenancy}/files/dependencies.package.json +1 -1
- package/lib/init/template/multitenancy/files/java/.cdsrc.json +19 -0
- package/lib/init/template/multitenancy/files/java/package.json +31 -0
- package/lib/init/template/{mtx → multitenancy}/files/mta.yaml.hbs +13 -6
- package/lib/init/template/multitenancy/files/xs-security.json.hbs +18 -0
- package/lib/init/template/multitenancy/index.js +109 -0
- package/lib/init/template/nodejs/files/package.json.hbs +3 -0
- package/lib/init/template/templateBase.js +4 -3
- package/lib/init/template/toggles/files/cds.package.json +7 -0
- package/lib/init/template/toggles/files/cds.package.json.hbs +9 -0
- package/lib/init/template/toggles/index.js +24 -0
- package/lib/init/template/xsuaa/files/mta.yaml.hbs +10 -0
- package/lib/init/template/xsuaa/index.js +44 -33
- package/lib/init/util/projectReader.js +13 -8
- package/lib/init/util/templateUtil.js +112 -110
- package/lib/k8s/ChartAdder.js +11 -3
- package/lib/k8s/ChartBuilder.js +6 -0
- package/lib/k8s/buildModel.js +1 -3
- package/lib/k8s/connectivity/index.js +11 -5
- package/lib/k8s/connectivity/templates/connectivity-proxy-info.yaml +7 -3
- package/lib/k8s/deployment/index.js +2 -4
- package/lib/k8s/deployment/subchart/Chart.yaml +1 -1
- package/lib/k8s/deployment/subchart/templates/_helpers.tpl +22 -11
- package/lib/k8s/deployment/subchart/templates/deployment.yaml +12 -5
- package/lib/k8s/deployment/subchart/templates/network-policy.yaml +3 -1
- package/lib/k8s/deployment/subchart/templates/pod-disruption-budget.yaml +1 -1
- package/lib/k8s/deployment/subchart/values.md +812 -0
- package/lib/k8s/deployment/subchart/values.schema.json +125 -30
- package/lib/k8s/deployment/subchart/values.yaml +7 -3
- package/lib/k8s/hana-deployer/index.js +10 -0
- package/lib/k8s/hana-deployer/templates/hana-deployer-job.yaml +8 -0
- package/lib/k8s/html5-apps-deployer/index.js +10 -0
- package/lib/k8s/html5-apps-deployer/templates/html5-apps-deployer-job.yaml +8 -0
- package/lib/k8s/index.js +2 -2
- package/lib/k8s/resources/helm/chart/templates/_deployment_helpers.tpl +1 -159
- package/lib/k8s/resources/helm/chart/templates/_helpers.tpl +0 -33
- package/lib/k8s/resources/helm/chart/templates/_sapcp_helpers.tpl +1 -1
- package/lib/k8s/resources/helm/chart/values.schema.json +449 -0
- package/lib/k8s/xsuaa/lib.js +10 -7
- package/lib/lint/Linter.js +155 -158
- package/lib/lint/generators.js +1 -1
- package/lib/lint/io.js +13 -5
- package/npm-shrinkwrap.json +1053 -136
- package/package.json +5 -4
- package/lib/init/template/_merging/existences.js +0 -297
- package/lib/init/template/mtx/files/cds.package.json +0 -12
- package/lib/init/template/mtx/files/cds.package.json.hbs +0 -14
- package/lib/init/template/mtx/files/java/.cdsrc.json +0 -17
- package/lib/init/template/mtx/files/java/package.json +0 -43
- package/lib/init/template/mtx/files/java/server.js +0 -30
- package/lib/init/template/mtx/files/xs-security.json.hbs +0 -48
- package/lib/lint/.eslintrc.js +0 -3
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { join } = require('path');
|
|
3
|
+
const axios = require('axios');
|
|
4
|
+
|
|
5
|
+
const { login } = require('./auth_manager');
|
|
6
|
+
const BaseCommand = require('./base_command');
|
|
7
|
+
const Logger = require('./helper/logging');
|
|
8
|
+
|
|
9
|
+
module.exports = class Push extends BaseCommand {
|
|
10
|
+
|
|
11
|
+
static async run(paramValues) {
|
|
12
|
+
try {
|
|
13
|
+
const params = await login(paramValues);
|
|
14
|
+
|
|
15
|
+
const projectFolder = params.get('projectFolder');
|
|
16
|
+
Logger.log(`Pushing extension from project folder '${projectFolder}', for subdomain '${params.get('subdomain')}', to app URL ${params.get('appUrl')}`);
|
|
17
|
+
|
|
18
|
+
const tgzPath = join(projectFolder, 'gen', 'extension.tgz');
|
|
19
|
+
const tgz = fs.readFileSync(tgzPath, { encoding: 'base64' });
|
|
20
|
+
const extensionName = this.getExtensionName(projectFolder);
|
|
21
|
+
return this.pushTgz(params, tgz, extensionName);
|
|
22
|
+
|
|
23
|
+
} catch (mainError) {
|
|
24
|
+
Logger.error(undefined, mainError);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static getExtensionName(projectFolder) {
|
|
29
|
+
try {
|
|
30
|
+
return require(join(projectFolder, 'package.json')).name;
|
|
31
|
+
} catch (error) {
|
|
32
|
+
throw new Error(`Extension project at ${projectFolder} is missing package.json`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static async pushTgz(params, tgz, extensionName) {
|
|
37
|
+
const pushUrl = `${params.get('appUrl')}/-/cds/extensibility/push`;
|
|
38
|
+
const options = { ...params.get('reqAuth') };
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
return axios.post(pushUrl, {
|
|
42
|
+
extension: tgz,
|
|
43
|
+
tag: extensionName
|
|
44
|
+
}, options);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
return this.handleHttpError(error, params);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -9,9 +9,10 @@ const { getAppFromSuggestions, getAppName, getSubdomain } = require('./helper/cf
|
|
|
9
9
|
const isBas = require('./helper/env_helper');
|
|
10
10
|
const Logger = require('./helper/logging');
|
|
11
11
|
const Question = require('./helper/question');
|
|
12
|
-
const {
|
|
12
|
+
const { httpSchema, httpsSchema, extractSubdomain, schemaRegex, localhostRegex } = require('./helper/url_helper');
|
|
13
13
|
const { ParamCollection, Persistence } = require('./params');
|
|
14
14
|
const { capitalize } = require('./helper/string_helper');
|
|
15
|
+
const axios = require('axios');
|
|
15
16
|
|
|
16
17
|
const CONFIG_SUBDIRS = {
|
|
17
18
|
linux: '.config',
|
|
@@ -31,7 +32,8 @@ const KEYRING_DESC = {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
const MTX_FULLY_QUALIFIED = 'com.sap.cds.mtx';
|
|
34
|
-
const
|
|
35
|
+
const OAUTH_PATH_OLD_MTX = '/mtx/v1/oauth/token';
|
|
36
|
+
const OAUTH_PATH_STREAMLINED_MTX = '/-/cds/login/token';
|
|
35
37
|
|
|
36
38
|
const SETTINGS_DIR = path.join(os.homedir(), CONFIG_SUBDIRS[os.platform()] || '', MTX_FULLY_QUALIFIED);
|
|
37
39
|
const SETTINGS_FILE = 'projects.json';
|
|
@@ -88,7 +90,7 @@ async function getSubdomainFromCfAndNotify(appName) {
|
|
|
88
90
|
return subdomain;
|
|
89
91
|
}
|
|
90
92
|
|
|
91
|
-
function getTokenBaseUrl(params, renewUrl) {
|
|
93
|
+
async function getTokenBaseUrl(params, renewUrl) {
|
|
92
94
|
if (params.has('tokenUrl') && !renewUrl) {
|
|
93
95
|
return params.get('tokenUrl');
|
|
94
96
|
}
|
|
@@ -96,8 +98,30 @@ function getTokenBaseUrl(params, renewUrl) {
|
|
|
96
98
|
throw new Error('Failed to determine token URL: app URL not given');
|
|
97
99
|
}
|
|
98
100
|
const baseUrl = new URL(params.get('appUrl'));
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
const cleanPathname = pathname => baseUrl.pathname.replace(/\/?$/, pathname);
|
|
102
|
+
const getBaseUrl = pathname => {
|
|
103
|
+
const url = new URL(baseUrl.toString());
|
|
104
|
+
url.pathname = cleanPathname(pathname);
|
|
105
|
+
return url;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
let existingPath;
|
|
109
|
+
const oauthPaths = [OAUTH_PATH_STREAMLINED_MTX/*, OAUTH_PATH_OLD_MTX*/]; // The old MTX does not support HEAD requests
|
|
110
|
+
for (const path of oauthPaths) {
|
|
111
|
+
try {
|
|
112
|
+
await axios.head(getBaseUrl(path).toString());
|
|
113
|
+
existingPath = path;
|
|
114
|
+
break;
|
|
115
|
+
} catch (e) {
|
|
116
|
+
if (e.response?.status === 404) {
|
|
117
|
+
continue;
|
|
118
|
+
} else {
|
|
119
|
+
throw Error(`Failed with root cause ${e.message}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
existingPath = existingPath ?? OAUTH_PATH_OLD_MTX;
|
|
124
|
+
return getBaseUrl(existingPath).toString();
|
|
101
125
|
}
|
|
102
126
|
|
|
103
127
|
function getKeyringAccountName(params) {
|
|
@@ -134,7 +158,16 @@ class SettingsManager {
|
|
|
134
158
|
static async saveSettings(params) {
|
|
135
159
|
Logger.debug(`Saving settings for project ${params.get('projectFolder')}`);
|
|
136
160
|
|
|
137
|
-
|
|
161
|
+
const paramsMap = params.toValueMap(Persistence.setting);
|
|
162
|
+
if (localhostRegex.test(params.get('appUrl'))) {
|
|
163
|
+
Logger.log(`Saving username${(params.get('isEmptyPassword') ? ' and empty-password hint' : '')} with project settings.`);
|
|
164
|
+
} else {
|
|
165
|
+
// Save only against localhost for security reasons.
|
|
166
|
+
Logger.debug('Not saving username because app is not recognized to run on localhost.');
|
|
167
|
+
delete paramsMap.username;
|
|
168
|
+
delete paramsMap.isEmptyPassword;
|
|
169
|
+
}
|
|
170
|
+
await this._saveToFile(params.get('projectFolder'), paramsMap);
|
|
138
171
|
|
|
139
172
|
if (!params.has('token')) {
|
|
140
173
|
return;
|
|
@@ -173,15 +206,22 @@ class SettingsManager {
|
|
|
173
206
|
|
|
174
207
|
static async updateUrls(params, logout, loadedAppUrl) {
|
|
175
208
|
async function addAppUrlAndSubdomain() {
|
|
176
|
-
if (params.has('appUrl')
|
|
177
|
-
|
|
178
|
-
|
|
209
|
+
if (params.has('appUrl')) {
|
|
210
|
+
const appUrl = params.get('appUrl');
|
|
211
|
+
if (!schemaRegex.test(appUrl)) {
|
|
212
|
+
if (localhostRegex.test(appUrl)) {
|
|
213
|
+
params.set('appUrl', httpSchema + appUrl);
|
|
214
|
+
} else {
|
|
215
|
+
params.set('appUrl', httpsSchema + appUrl);
|
|
216
|
+
}
|
|
217
|
+
Logger.debug(`Added schema to app URL: ${params.get('appUrl')}`);
|
|
218
|
+
}
|
|
179
219
|
}
|
|
180
220
|
if (!logout) {
|
|
181
221
|
if (!params.has('appUrl')) {
|
|
182
222
|
Logger.debug('App URL not given');
|
|
183
223
|
await getAppUrlAndSubdomainFromSuggestions(params);
|
|
184
|
-
} else if (!params.has('subdomain')) {
|
|
224
|
+
} else if (!params.has('subdomain') && !localhostRegex.test(params.get('appUrl'))) {
|
|
185
225
|
Logger.debug('Subdomain not given');
|
|
186
226
|
const appName = await getAppName(params.get('appUrl'));
|
|
187
227
|
if (appName) {
|
|
@@ -193,24 +233,25 @@ class SettingsManager {
|
|
|
193
233
|
throw new Error('App URL not given. Please specify it or log in to Cloud Foundry and repeat this command.');
|
|
194
234
|
}
|
|
195
235
|
if (!params.has('subdomain')) {
|
|
196
|
-
|
|
197
|
-
if (!
|
|
236
|
+
const subdomain = extractSubdomain(params.get('appUrl'));
|
|
237
|
+
if (!subdomain) {
|
|
198
238
|
throw new Error('Subdomain not given');
|
|
199
239
|
}
|
|
200
|
-
|
|
240
|
+
params.set('subdomain', subdomain);
|
|
241
|
+
Logger.log(`Subdomain determined from app URL: ${subdomain}`);
|
|
201
242
|
}
|
|
202
243
|
}
|
|
203
|
-
function renewTokenUrl() {
|
|
244
|
+
async function renewTokenUrl() {
|
|
204
245
|
const renewUrl = params.get('appUrl') !== loadedAppUrl;
|
|
205
246
|
if (!params.get('tokenUrl') || renewUrl) {
|
|
206
|
-
params.set('tokenUrl', getTokenBaseUrl(params, renewUrl));
|
|
247
|
+
params.set('tokenUrl', await getTokenBaseUrl(params, renewUrl));
|
|
207
248
|
}
|
|
208
249
|
}
|
|
209
250
|
|
|
210
251
|
await addAppUrlAndSubdomain();
|
|
211
252
|
|
|
212
253
|
if (!logout) {
|
|
213
|
-
renewTokenUrl();
|
|
254
|
+
await renewTokenUrl();
|
|
214
255
|
}
|
|
215
256
|
}
|
|
216
257
|
|
|
@@ -236,13 +277,16 @@ class SettingsManager {
|
|
|
236
277
|
|
|
237
278
|
static async addAuth(params, logout) {
|
|
238
279
|
async function addPassword() {
|
|
239
|
-
params.
|
|
240
|
-
|
|
241
|
-
|
|
280
|
+
if (params.get('isEmptyPassword')) {
|
|
281
|
+
params.set('password', '');
|
|
282
|
+
} else {
|
|
283
|
+
params.set('password', await Question.askQuestion('Password: ', undefined, true));
|
|
284
|
+
console.log();
|
|
242
285
|
}
|
|
243
286
|
}
|
|
244
287
|
async function addClientSecret() {
|
|
245
288
|
params.set('clientsecret', await Question.askQuestion('clientsecret: ', undefined, true));
|
|
289
|
+
console.log();
|
|
246
290
|
if (params.get('clientsecret') === '') {
|
|
247
291
|
throw new Error('clientsecret cannot be empty');
|
|
248
292
|
}
|
|
@@ -250,7 +294,7 @@ class SettingsManager {
|
|
|
250
294
|
async function addPasscode() {
|
|
251
295
|
const prompt = `Passcode${params.get('passcodeUrl') ? ' (visit ' + params.get('passcodeUrl') + ' to generate)' : ''}: `;
|
|
252
296
|
params.set('passcode', await Question.askQuestion(prompt, undefined, true));
|
|
253
|
-
console.log();
|
|
297
|
+
console.log();
|
|
254
298
|
if (params.get('passcode') === '') {
|
|
255
299
|
throw new Error('Passcode cannot be empty');
|
|
256
300
|
}
|
|
@@ -288,10 +332,19 @@ class SettingsManager {
|
|
|
288
332
|
}
|
|
289
333
|
|
|
290
334
|
if (params.has('username')) {
|
|
291
|
-
if (!params.
|
|
335
|
+
if (!params.has('password') && !logout) {
|
|
292
336
|
await addPassword();
|
|
293
337
|
}
|
|
338
|
+
if (params.get('password') === '') {
|
|
339
|
+
params.set('isEmptyPassword', true);
|
|
340
|
+
// TODO check password only in production env
|
|
341
|
+
// throw new Error('Password cannot be empty');
|
|
342
|
+
} else {
|
|
343
|
+
params.delete('isEmptyPassword');
|
|
344
|
+
}
|
|
294
345
|
return;
|
|
346
|
+
} else {
|
|
347
|
+
params.delete('isEmptyPassword');
|
|
295
348
|
}
|
|
296
349
|
|
|
297
350
|
if (params.get('clientid') && !params.get('clientsecret') && !logout) {
|