@sap/cds-dk 7.3.0 → 7.3.2
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 +3 -1
- package/bin/build.js +2 -1
- package/bin/cds.js +1 -1
- package/bin/compile/index.js +11 -0
- package/bin/extend.js +5 -1
- package/bin/init.js +31 -37
- package/bin/repl.js +23 -43
- package/bin/watch.js +5 -9
- package/lib/bind/bindingResolver.js +2 -1
- package/lib/bind/index.js +1 -1
- package/lib/build/buildPlugin.js +18 -3
- package/lib/build/buildTaskEngine.js +2 -1
- package/lib/build/buildTaskFactory.js +33 -9
- package/lib/build/buildTaskProvider.js +1 -1
- package/lib/build/buildTaskProviderFactory.js +15 -61
- package/lib/build/constants.js +2 -0
- package/lib/build/index.js +5 -2
- package/lib/build/plugins.js +35 -0
- package/lib/build/provider/edmxBuildPlugin.js +9 -1
- package/lib/build/provider/featureToggleBuildPlugin.js +2 -3
- package/lib/build/provider/internalBuildPlugin.js +4 -0
- package/lib/build/provider/internalBuildTaskProvider.js +1 -1
- package/lib/build/provider/java/index.js +12 -6
- package/lib/build/provider/nodejs/index.js +3 -2
- package/lib/build/util.js +5 -0
- package/lib/client/base_command.js +8 -18
- package/lib/client/download_legacy.js +2 -10
- package/lib/client/params.js +6 -4
- package/lib/client/settings_manager.js +38 -35
- package/lib/compile/openapi/csdl2openapi.js +1 -1
- package/lib/deploy/to-hana/hana.js +53 -35
- package/lib/index.js +7 -1
- package/lib/init/constants.js +4 -2
- package/lib/init/template/_merging/registry-mta.js +12 -0
- package/lib/init/template/enterprise-messaging/files/event-mesh.json.hbs +1 -1
- package/lib/init/template/enterprise-messaging/index.js +1 -1
- package/lib/init/template/enterprise-messaging-shared/files/event-mesh.json.hbs +1 -1
- package/lib/init/template/enterprise-messaging-shared/index.js +19 -5
- package/lib/init/template/helm/index.js +1 -1
- package/lib/init/template/helm/subcharts/content-deployment/Chart.yaml +4 -4
- package/lib/init/template/helm/subcharts/content-deployment/templates/_helpers.tpl +4 -2
- package/lib/init/template/helm/subcharts/content-deployment/templates/job.yaml +4 -3
- package/lib/init/template/helm/subcharts/content-deployment/values.schema.json +9 -83
- package/lib/init/template/helm/subcharts/content-deployment/values.yaml +54 -15
- package/lib/init/template/helm/subcharts/service-instance/Chart.yaml +4 -4
- package/lib/init/template/helm/subcharts/service-instance/templates/serviceinstance.yaml +1 -1
- package/lib/init/template/helm/subcharts/service-instance/values.schema.json +0 -17
- package/lib/init/template/helm/subcharts/service-instance/values.yaml +28 -0
- package/lib/init/template/helm/subcharts/web-application/Chart.yaml +5 -5
- package/lib/init/template/helm/subcharts/web-application/templates/_api.tpl +60 -0
- package/lib/init/template/helm/subcharts/web-application/templates/_helpers.tpl +34 -73
- package/lib/init/template/helm/subcharts/web-application/templates/api-rule.yaml +4 -4
- package/lib/init/template/helm/subcharts/web-application/templates/deployment.yaml +96 -17
- package/lib/init/template/helm/subcharts/web-application/templates/network-policy.yaml +19 -3
- package/lib/init/template/helm/subcharts/web-application/templates/pod-disruption-budget.yaml +3 -3
- package/lib/init/template/helm/subcharts/web-application/templates/rbac.yaml +26 -0
- package/lib/init/template/helm/subcharts/web-application/templates/secret.yaml +1 -1
- package/lib/init/template/helm/subcharts/web-application/templates/service-account.yaml +1 -1
- package/lib/init/template/helm/subcharts/web-application/templates/service-binding.yaml +1 -1
- package/lib/init/template/helm/subcharts/web-application/templates/service.yaml +21 -3
- package/lib/init/template/helm/subcharts/web-application/templates/virtual-service.yaml +36 -0
- package/lib/init/template/helm/subcharts/web-application/values.schema.json +535 -142
- package/lib/init/template/helm/subcharts/web-application/values.yaml +168 -44
- package/lib/init/template/local-messaging/files/package.json.hbs +15 -0
- package/lib/init/template/local-messaging/index.js +25 -0
- package/lib/init/template/mta/index.js +2 -2
- package/lib/init/template/nodejs/files/.gitignore.hbs +3 -0
- package/lib/init/template/nodejs/files/.vscode/launch.json +0 -3
- package/lib/init/template/notifications/files/mta.yaml.hbs +17 -0
- package/lib/init/template/notifications/files/package.json.hbs +5 -0
- package/lib/init/template/notifications/index.js +43 -0
- package/lib/init/template/typer/files/package.json +1 -1
- package/lib/init/util/projectReader.js +1 -0
- package/lib/util/pruneAxiosErrors.js +4 -1
- package/lib/util/term.js +1 -2
- package/lib/watch/livereload-server.js +38 -2
- package/lib/watch/node-watch.js +3 -2
- package/npm-shrinkwrap.json +438 -2205
- package/package.json +2 -2
- package/lib/init/template/helm/subcharts/content-deployment/templating.md +0 -37
- package/lib/init/template/helm/subcharts/content-deployment/values-lint.yaml +0 -5
- package/lib/init/template/helm/subcharts/content-deployment/values.md +0 -1011
- package/lib/init/template/helm/subcharts/service-instance/templating.md +0 -18
- package/lib/init/template/helm/subcharts/service-instance/values-lint.yaml +0 -2
- package/lib/init/template/helm/subcharts/service-instance/values.md +0 -186
- package/lib/init/template/helm/subcharts/web-application/templating.md +0 -51
- package/lib/init/template/helm/subcharts/web-application/values-lint.yaml +0 -8
- package/lib/init/template/helm/subcharts/web-application/values.md +0 -1363
package/lib/build/index.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const cds = require('../cds')
|
|
3
3
|
const BuildTaskEngine = require('./buildTaskEngine')
|
|
4
|
-
const BuildTaskFactory = require('./buildTaskFactory')
|
|
5
4
|
const BuildPlugin = require('./buildPlugin')
|
|
6
5
|
const { BuildError } = require('./util')
|
|
7
6
|
|
|
8
|
-
module.exports = { build,
|
|
7
|
+
module.exports = { build, register, BuildPlugin }
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Executes cds build in the directory defined by cds.root.
|
|
@@ -28,4 +27,8 @@ async function build(options = {}) {
|
|
|
28
27
|
}
|
|
29
28
|
throw e
|
|
30
29
|
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function register(id, options) {
|
|
33
|
+
return require('./plugins').register(id, options)
|
|
31
34
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const cds = require('../cds')
|
|
2
|
+
|
|
3
|
+
module.exports = new (class BuildPlugins {
|
|
4
|
+
constructor() {
|
|
5
|
+
this._plugins = new Map()
|
|
6
|
+
}
|
|
7
|
+
getPlugins() {
|
|
8
|
+
return this._plugins
|
|
9
|
+
}
|
|
10
|
+
getPlugin(id) {
|
|
11
|
+
return this._plugins.get(id)
|
|
12
|
+
}
|
|
13
|
+
register(id, options) {
|
|
14
|
+
if (!id || !options?.impl) {
|
|
15
|
+
throw Error("Invalid build plugin parameter")
|
|
16
|
+
}
|
|
17
|
+
if (this._plugins.has(id)) {
|
|
18
|
+
throw Error(`Build plugin ${id} already registered`)
|
|
19
|
+
}
|
|
20
|
+
this._plugins.set(id, {
|
|
21
|
+
id,
|
|
22
|
+
class: this._loadPlugin(id, options.impl),
|
|
23
|
+
description: options.description,
|
|
24
|
+
taskDefaults: options.taskDefaults ?? {}
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
_loadPlugin(id, impl) {
|
|
28
|
+
try {
|
|
29
|
+
// project-local module is preferred - otherwise from our own dependencies
|
|
30
|
+
return require(require.resolve(impl, { paths: [cds.root, __dirname] }))
|
|
31
|
+
} catch (e) {
|
|
32
|
+
throw new Error(`Custom build plugin implementation '${impl}' for '${id}' cannot be loaded:\n` + e)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
})
|
|
@@ -51,7 +51,15 @@ class EdmxBuildPlugin extends FeatureToggleBuildPlugin {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
_isOdataProtocol(srv) {
|
|
54
|
-
|
|
54
|
+
let protocols = cds.service.protocols4?.(srv)
|
|
55
|
+
if (!protocols) {
|
|
56
|
+
// compatibility with @sap/cds < 7.3.0
|
|
57
|
+
protocols = cds.service.protocols.protocol4(srv)
|
|
58
|
+
if (typeof protocols === "string") {
|
|
59
|
+
protocols = [protocols]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return protocols.some(p => p && p.startsWith('odata'))
|
|
55
63
|
}
|
|
56
64
|
|
|
57
65
|
_options4odata() {
|
|
@@ -124,9 +124,8 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
|
|
|
124
124
|
|
|
125
125
|
_validateFeature(ftCsn, baseCsn) {
|
|
126
126
|
// features must not have other dependencies than base model dependencies - cross feature dependencies are not supported
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
cds.compiler.compileSources({ '../..csn.json': baseCsn, 'feature.csn': ftCsn }, this.options())
|
|
127
|
+
// assuming only core compiler options are relevant for validation scenario
|
|
128
|
+
cds.compiler.compileSources({ [ftCsn.requires[0]]: baseCsn, 'feature.csn': ftCsn }, { ...super.options(), ...cds.env.cdsc ?? {}})
|
|
130
129
|
}
|
|
131
130
|
}
|
|
132
131
|
|
|
@@ -22,6 +22,10 @@ class InternalBuildPlugin extends BuildPlugin {
|
|
|
22
22
|
return InternalBuildPlugin.PRIORITY_MAX_VALUE
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
init() {
|
|
26
|
+
// REVISIT: no default gen folder for now
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
async clean() {
|
|
26
30
|
// build results are deleted by the BuildTaskEngine if the build.target !== '.'
|
|
27
31
|
// make sure that src is not a subfolder of dest
|
|
@@ -43,7 +43,7 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
|
|
|
43
43
|
InternalBuildTaskProvider._setDefaultModel(task)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
getPluginClass(task) {
|
|
47
47
|
return require(`./${InternalBuildTaskProvider._getForValueFromTask(task)}`)
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -2,8 +2,8 @@ const fs = require('fs')
|
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const cds = require('../../../cds')
|
|
4
4
|
const EdmxBuildPlugin = require('../edmxBuildPlugin')
|
|
5
|
-
const { OUTPUT_MODE, OUTPUT_MODE_RESULT, FILE_EXT_CDS, CONTENT_LANGUAGE_BUNDLES, CONTENT_DEFAULT_CSN, DEFAULT_CSN_FILE_NAME,
|
|
6
|
-
OUTPUT_MODE_FILESYSTEM, FLAVOR_LOCALIZED_EDMX } = require('../../constants')
|
|
5
|
+
const { OUTPUT_MODE, OUTPUT_MODE_RESULT, FILE_EXT_CDS, CONTENT_LANGUAGE_BUNDLES, CONTENT_DEFAULT_CSN, DEFAULT_CSN_FILE_NAME,
|
|
6
|
+
OUTPUT_MODE_FILESYSTEM, FLAVOR_LOCALIZED_EDMX, CONTENT_EDMX, CONTENT_LOCALIZED_EDMX } = require('../../constants')
|
|
7
7
|
const { getI18nDefaultFolder } = require('../../util')
|
|
8
8
|
const DEFAULT_COMPILE_DEST_FOLDER = path.normalize('src/main/resources/edmx')
|
|
9
9
|
|
|
@@ -20,11 +20,17 @@ class JavaBuildPlugin extends EdmxBuildPlugin {
|
|
|
20
20
|
if (!model) {
|
|
21
21
|
return
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
// generate edmx files containing all features
|
|
25
23
|
const odata = await this._compileForOdata(model, compileDest)
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
|
|
25
|
+
if (!this.hasBuildOption(CONTENT_EDMX, false)) {
|
|
26
|
+
// generate edmx files containing all features
|
|
27
|
+
// localized edmx for backward compatibility
|
|
28
|
+
if (!this.hasBuildOption(CONTENT_LOCALIZED_EDMX, false)) {
|
|
29
|
+
await this.compileToEdmx(odata, compileDest, { [FLAVOR_LOCALIZED_EDMX]: true })
|
|
30
|
+
}
|
|
31
|
+
// non-localized edmx
|
|
32
|
+
await this.compileToEdmx(odata, path.join(compileDest, 'odata', cds.env.odata.version), { [FLAVOR_LOCALIZED_EDMX]: false })
|
|
33
|
+
}
|
|
28
34
|
|
|
29
35
|
if (!this.hasBuildOption(CONTENT_LANGUAGE_BUNDLES, false)) {
|
|
30
36
|
// collect and write language bundles containing all features
|
|
@@ -44,9 +44,10 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
44
44
|
await this.collectAllLanguageBundles(dictionary, sources, destSrv, destRoot)
|
|
45
45
|
|
|
46
46
|
if (!this.hasBuildOption(CONTENT_EDMX, false)) {
|
|
47
|
-
//REVISIT: inferred model expected by cds.compile.to.edmx()
|
|
48
47
|
const compileOptions = { [FLAVOR_LOCALIZED_EDMX]: this.hasBuildOption(FLAVOR_LOCALIZED_EDMX, true) }
|
|
49
|
-
|
|
48
|
+
// inferred flavor is required by edmx compiler backend
|
|
49
|
+
// using cds.compile instead of cds.compiler.compileSources ensures that cds.env options are correctly read
|
|
50
|
+
const baseModel = dictionary.base.meta.flavor !== 'inferred' ? await cds.compile(sources.base, super.options(), 'inferred') : dictionary.base
|
|
50
51
|
await this.compileToEdmx(baseModel, path.join(this.destSrv, 'odata', cds.env.odata.version), compileOptions)
|
|
51
52
|
}
|
|
52
53
|
|
package/lib/build/util.js
CHANGED
|
@@ -208,6 +208,10 @@ function _locationString(loc) {
|
|
|
208
208
|
: `${loc.file}:${loc.line}.${loc.col}-${loc.endLine}.${loc.endCol}`;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
async function pathExists(path) {
|
|
212
|
+
return fs.promises.access(path).then(() => true).catch(() => false);
|
|
213
|
+
}
|
|
214
|
+
|
|
211
215
|
/**
|
|
212
216
|
* Class for individual build message.
|
|
213
217
|
*
|
|
@@ -271,6 +275,7 @@ module.exports = {
|
|
|
271
275
|
getI18nDefaultFolder,
|
|
272
276
|
isClassicMtx,
|
|
273
277
|
normalizePath,
|
|
278
|
+
pathExists,
|
|
274
279
|
BuildMessage,
|
|
275
280
|
BuildError
|
|
276
281
|
}
|
|
@@ -38,27 +38,17 @@ module.exports = class BaseCommand {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
static concatUrls(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return trimBeginSlash(trimEndSlash(str));
|
|
50
|
-
}
|
|
51
|
-
const concatenated = new URL(base);
|
|
52
|
-
concatenated.pathname = trimEndSlash(concatenated.pathname) + '/' +
|
|
53
|
-
paths.map((p, i) => i < paths.length - 1 ? trimSlashes(p) : trimBeginSlash(p)).join('/');
|
|
54
|
-
return concatenated.toString();
|
|
41
|
+
static concatUrls(...parts) {
|
|
42
|
+
return parts
|
|
43
|
+
.map((p, i) => i === 0
|
|
44
|
+
? p.replace(/\/$/ /*end slash*/, '')
|
|
45
|
+
: i === parts.length - 1
|
|
46
|
+
? p.replace(/^\// /*begin slash*/, '')
|
|
47
|
+
: p.replace(/^\/|\/$/g /*both*/, ''))
|
|
48
|
+
.join('/');
|
|
55
49
|
}
|
|
56
50
|
|
|
57
51
|
static getMtxApiUrl(url, action) {
|
|
58
52
|
return BaseCommand.concatUrls(url, MTX_URL_PATH_PREFIX, action);
|
|
59
53
|
}
|
|
60
|
-
|
|
61
|
-
static getMtxApiUrlSync(url, action) {
|
|
62
|
-
return BaseCommand.concatUrls(url, MTX_URL_PATH_PREFIX, action);
|
|
63
|
-
}
|
|
64
54
|
}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
const cds = require ('../cds')
|
|
2
|
-
const { tar } = cds.utils;
|
|
3
|
-
|
|
4
1
|
const fs = require('fs');
|
|
5
2
|
const { join } = require('path');
|
|
6
3
|
const axios = require('axios');
|
|
@@ -13,10 +10,6 @@ const DOWNLOAD_FILE_NAME = 'migrated_projects.tgz'; // TODO try to add tenant la
|
|
|
13
10
|
module.exports = class Download extends BaseCommand {
|
|
14
11
|
|
|
15
12
|
static async run(paramValues) {
|
|
16
|
-
if (!tar) {
|
|
17
|
-
throw `cds pull requires @sap/cds version >= 6.2. Current version is ${cds.version}\n`;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
13
|
const params = await login(paramValues);
|
|
21
14
|
|
|
22
15
|
const projectFolder = params.get('projectFolder');
|
|
@@ -31,17 +24,16 @@ module.exports = class Download extends BaseCommand {
|
|
|
31
24
|
const downloadedTgz = await this.getTgz(params);
|
|
32
25
|
await fs.promises.writeFile(downloadPath, downloadedTgz);
|
|
33
26
|
|
|
34
|
-
//await tar.xz(baseModelTgz).to(target); // expand if feature is requested later
|
|
35
|
-
|
|
36
27
|
console.log(`Finished.`);
|
|
37
28
|
}
|
|
38
29
|
|
|
39
30
|
static async getTgz(params) {
|
|
40
31
|
const tagRule = params.get('tagRule');
|
|
32
|
+
const defaultTag = params.get('defaultTag');
|
|
41
33
|
const downloadUrl = `${(params.get('appUrl'))}/-/cds/extensibility/getMigratedProjects`;
|
|
42
34
|
const options = { ...params.get('reqAuth'), responseType: 'arraybuffer' };
|
|
43
35
|
|
|
44
|
-
return axios.post(downloadUrl, { tagRule }, options)
|
|
36
|
+
return axios.post(downloadUrl, { tagRule, defaultTag }, options)
|
|
45
37
|
.then(response => Buffer.from(response.data))
|
|
46
38
|
.catch(error => this.handleHttpError(error, params, { url: downloadUrl }));
|
|
47
39
|
}
|
package/lib/client/params.js
CHANGED
|
@@ -163,13 +163,14 @@ class BasicParams {
|
|
|
163
163
|
this.directory = this.projectFolder.newAlias('directory');
|
|
164
164
|
|
|
165
165
|
this.tagRule = new Param('tagRule', '');
|
|
166
|
+
this.defaultTag = new Param('defaultTag', '');
|
|
166
167
|
|
|
167
168
|
// - non-persisted, internal
|
|
168
169
|
this.reqAuth = new Param('reqAuth', null, { obfuscate: ObfuscationLevel.full, internal: true });
|
|
169
170
|
this.clearOtherTokenStorage = new Param('clearOtherTokenStorage', false, { internal: true });
|
|
170
171
|
|
|
171
172
|
// - persisted
|
|
172
|
-
this.appUrl = new Param('appUrl', '', { persist: Persistence.setting });
|
|
173
|
+
this.appUrl = new Param('appUrl', '', { persist: Persistence.setting }); // any trailing slash (/) is removed
|
|
173
174
|
this.url = this.appUrl.newAlias('url');
|
|
174
175
|
this.from = this.appUrl.newAlias('from');
|
|
175
176
|
this.to = this.appUrl.newAlias('to');
|
|
@@ -275,6 +276,7 @@ class ParamCollection {
|
|
|
275
276
|
|
|
276
277
|
/**
|
|
277
278
|
* Get the name of a main param (as opposed to an alias).
|
|
279
|
+
* Throws an error if the param is not part of this collection.
|
|
278
280
|
* @param name the param in question
|
|
279
281
|
*/
|
|
280
282
|
static mainName(name) {
|
|
@@ -286,7 +288,7 @@ class ParamCollection {
|
|
|
286
288
|
}
|
|
287
289
|
|
|
288
290
|
/**
|
|
289
|
-
*
|
|
291
|
+
* Return whether the given param is included in this collection.
|
|
290
292
|
* @param name the param in question
|
|
291
293
|
*/
|
|
292
294
|
has(name) {
|
|
@@ -294,7 +296,7 @@ class ParamCollection {
|
|
|
294
296
|
}
|
|
295
297
|
|
|
296
298
|
/**
|
|
297
|
-
* Return the value of the given param.
|
|
299
|
+
* Return the value of the given param or `undefined` if not part of this collection.
|
|
298
300
|
* @param name the param in question
|
|
299
301
|
*/
|
|
300
302
|
get(name) {
|
|
@@ -303,7 +305,7 @@ class ParamCollection {
|
|
|
303
305
|
}
|
|
304
306
|
|
|
305
307
|
/**
|
|
306
|
-
* Return the `Param` object for the given param.
|
|
308
|
+
* Return the `Param` object for the given param or `undefined` if not part of this collection.
|
|
307
309
|
* @param name the param in question
|
|
308
310
|
*/
|
|
309
311
|
getParam(name) {
|
|
@@ -96,19 +96,17 @@ async function getTokenBaseUrl(params, renewUrl) {
|
|
|
96
96
|
if (!params.has('appUrl')) {
|
|
97
97
|
throw 'Failed to determine token URL: app URL not given';
|
|
98
98
|
}
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
url.pathname = cleanPathname(pathname);
|
|
104
|
-
return url;
|
|
99
|
+
const appUrlWith = pathname => {
|
|
100
|
+
const url = new URL(params.get('appUrl'));
|
|
101
|
+
url.pathname = url.pathname.replace(/\/*$/, pathname);
|
|
102
|
+
return url.toString();
|
|
105
103
|
};
|
|
106
104
|
|
|
107
105
|
let existingPath;
|
|
108
106
|
const oauthPaths = [OAUTH_PATH_STREAMLINED_MTX];
|
|
109
107
|
for (const path of oauthPaths) {
|
|
110
108
|
try {
|
|
111
|
-
await axios.head(
|
|
109
|
+
await axios.head(appUrlWith(path));
|
|
112
110
|
existingPath = path;
|
|
113
111
|
break;
|
|
114
112
|
} catch (error) {
|
|
@@ -119,7 +117,7 @@ async function getTokenBaseUrl(params, renewUrl) {
|
|
|
119
117
|
}
|
|
120
118
|
}
|
|
121
119
|
existingPath = existingPath ?? OAUTH_PATH_OLD_MTX; // REVISIT can this just be included in the array?
|
|
122
|
-
return
|
|
120
|
+
return appUrlWith(existingPath);
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
function getKeyringAccountName(params) {
|
|
@@ -194,7 +192,6 @@ class SettingsManager {
|
|
|
194
192
|
|
|
195
193
|
const loadedSettings = await this._loadFromFile(projectFolder);
|
|
196
194
|
DEBUG?.(`Loaded project settings for ${params.get('projectFolder')}: ${loadedSettings.format()}`);
|
|
197
|
-
const loadedAppUrl = loadedSettings.get('appUrl');
|
|
198
195
|
|
|
199
196
|
if (params.has('passcode') && loadedSettings.has('username')) {
|
|
200
197
|
console.log(`Unsetting username${(loadedSettings.has('isEmptyPassword') ? ' and empty-password hint' : '')}`);
|
|
@@ -207,50 +204,56 @@ class SettingsManager {
|
|
|
207
204
|
if (params.has('username')) {
|
|
208
205
|
params.set('skipToken', true);
|
|
209
206
|
}
|
|
210
|
-
await this.updateUrls(params, logout,
|
|
207
|
+
await this.updateUrls(params, logout, loadedSettings);
|
|
211
208
|
await this.setKeytar(params, logout);
|
|
212
209
|
await this.addAuth(params, logout);
|
|
213
210
|
DEBUG?.(`Effective project settings: ${params.format()}`);
|
|
214
211
|
}
|
|
215
212
|
|
|
216
|
-
static async updateUrls(params, logout,
|
|
217
|
-
async function
|
|
218
|
-
// Prefix URL schema
|
|
219
|
-
if (params.has('appUrl')) {
|
|
220
|
-
const appUrl = params.get('appUrl');
|
|
221
|
-
if (!schemaRegex.test(appUrl)) {
|
|
222
|
-
if (localhostRegex.test(appUrl)) {
|
|
223
|
-
params.set('appUrl', httpSchema + appUrl);
|
|
224
|
-
} else {
|
|
225
|
-
params.set('appUrl', httpsSchema + appUrl);
|
|
226
|
-
}
|
|
227
|
-
DEBUG?.(`Added schema to app URL: ${params.get('appUrl')}`);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
213
|
+
static async updateUrls(params, logout, loadedSettings) {
|
|
214
|
+
async function updateAppUrl() {
|
|
231
215
|
if (!logout && !params.has('appUrl')) {
|
|
232
216
|
// Get appUrl from CF
|
|
233
217
|
DEBUG?.('App URL not given');
|
|
234
218
|
await getAppUrlAndSubdomainFromSuggestions(params);
|
|
235
219
|
}
|
|
236
220
|
|
|
237
|
-
// Check required param: appUrl
|
|
238
221
|
if (!params.has('appUrl')) {
|
|
239
222
|
throw 'App URL not given. Please specify it or log in to Cloud Foundry and repeat this command.';
|
|
240
223
|
}
|
|
224
|
+
|
|
225
|
+
// Prefix URL schema
|
|
226
|
+
let appUrl = params.get('appUrl');
|
|
227
|
+
if (appUrl.endsWith('/')) {
|
|
228
|
+
appUrl = appUrl.replace(/\/+$/, '');
|
|
229
|
+
DEBUG?.(`Removed trailing slash from app URL: ${appUrl}`);
|
|
230
|
+
}
|
|
231
|
+
if (!schemaRegex.test(appUrl)) {
|
|
232
|
+
if (localhostRegex.test(appUrl)) {
|
|
233
|
+
appUrl = httpSchema + appUrl;
|
|
234
|
+
} else {
|
|
235
|
+
appUrl = httpsSchema + appUrl;
|
|
236
|
+
}
|
|
237
|
+
DEBUG?.(`Added schema to app URL: ${appUrl}`);
|
|
238
|
+
}
|
|
239
|
+
params.set('appUrl', appUrl);
|
|
240
|
+
if (params.get('appUrl') !== loadedSettings.get('appUrl')) {
|
|
241
|
+
DEBUG?.(`Updated app URL from '${loadedSettings.get('appUrl')}' (loaded) to '${appUrl}'`);
|
|
242
|
+
}
|
|
241
243
|
}
|
|
242
|
-
async function
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
params.
|
|
244
|
+
async function updateTokenUrl() {
|
|
245
|
+
const tokenUrl = params.get('tokenUrl');
|
|
246
|
+
const renewUrl = !logout && !params.get('skipToken')
|
|
247
|
+
&& (!tokenUrl || tokenUrl.includes('//-/cds') || params.get('appUrl') !== loadedSettings.get('appUrl'));
|
|
248
|
+
if (renewUrl) {
|
|
249
|
+
const tokenUrl = await getTokenBaseUrl(params, renewUrl);
|
|
250
|
+
params.set('tokenUrl', tokenUrl);
|
|
251
|
+
DEBUG?.(`Updated token URL from '${loadedSettings.get('tokenUrl')}' (loaded) to '${tokenUrl}'`);
|
|
246
252
|
}
|
|
247
253
|
}
|
|
248
254
|
|
|
249
|
-
await
|
|
250
|
-
|
|
251
|
-
if (!logout && !params.get('skipToken')) {
|
|
252
|
-
await renewTokenUrl();
|
|
253
|
-
}
|
|
255
|
+
await updateAppUrl();
|
|
256
|
+
await updateTokenUrl();
|
|
254
257
|
}
|
|
255
258
|
|
|
256
259
|
static async setKeytar(params, logout = false) {
|
|
@@ -64,7 +64,7 @@ module.exports.csdl2openapi = function (
|
|
|
64
64
|
csdl = JSON.parse(JSON.stringify(csdl))
|
|
65
65
|
csdl.$Version = odataVersion ? odataVersion : '4.01'
|
|
66
66
|
serviceRoot = serviceRoot || (scheme + '://' + host + basePath);
|
|
67
|
-
const queryOptionPrefix = csdl.$Version <= '4.
|
|
67
|
+
const queryOptionPrefix = csdl.$Version <= '4.01' ? '$' : '';
|
|
68
68
|
const typesToInline = {}; // filled in schema() and used in inlineTypes()
|
|
69
69
|
const boundOverloads = {};
|
|
70
70
|
const derivedTypes = {};
|
|
@@ -45,13 +45,16 @@ class HanaDeployer {
|
|
|
45
45
|
// arg object
|
|
46
46
|
// async deploy(model, serviceName, tunnelAddress, buildTaskOptions, vcapFile, undeployWhitelist, hdiOptions, bindCallback) { // NOSONAR
|
|
47
47
|
async deploy(options = {}) { // NOSONAR
|
|
48
|
-
let { model, serviceName, tunnelAddress, vcapFile, undeployWhitelist, hdiOptions } = options;
|
|
48
|
+
let { model, serviceName, tunnelAddress, vcapFile, undeployWhitelist, hdiOptions, dry } = options;
|
|
49
49
|
|
|
50
50
|
if (model) {
|
|
51
51
|
throw 'Specifying a model for hana deployment is not supported.';
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
if (dry) {
|
|
55
|
+
console.log('-- running in dry mode ---');
|
|
56
|
+
}
|
|
57
|
+
|
|
55
58
|
if (vcapFile) {
|
|
56
59
|
console.log(`Using VCAP_SERVICES from file ${vcapFile} (beta feature).`);
|
|
57
60
|
}
|
|
@@ -66,51 +69,66 @@ class HanaDeployer {
|
|
|
66
69
|
globalVcapEnv.TARGET_CONTAINER = process.env.TARGET_CONTAINER;
|
|
67
70
|
}
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
if (dry) {
|
|
73
|
+
for (const buildResult of buildResults) {
|
|
74
|
+
const model = await cds.load(buildResult.task.src);
|
|
75
|
+
const data = cds.compile.to.hdbtable(model);
|
|
76
|
+
for (const [src, { file }] of data) {
|
|
77
|
+
console.log(`-- ${file}`);
|
|
78
|
+
console.log(src);
|
|
79
|
+
console.log();
|
|
80
|
+
}
|
|
77
81
|
}
|
|
82
|
+
} else {
|
|
83
|
+
for (const buildResult of buildResults) {
|
|
84
|
+
let vcapEnv = globalVcapEnv;
|
|
85
|
+
let serviceKeyName;
|
|
86
|
+
const currentModelFolder = buildResult.task.dest;
|
|
87
|
+
|
|
88
|
+
if (undeployWhitelist) {
|
|
89
|
+
console.log('Writing undeploy.json');
|
|
90
|
+
await fs.write(path.join(currentModelFolder, 'undeploy.json'), JSON.stringify(undeployWhitelist, null, 2));
|
|
91
|
+
}
|
|
78
92
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
93
|
+
const hasVCAPEnv = Object.keys(vcapEnv).length > 0;
|
|
94
|
+
if (!serviceName && hasVCAPEnv) {
|
|
95
|
+
await fs.mkdir(currentModelFolder, { recursive: true });
|
|
96
|
+
} else {
|
|
97
|
+
const { cfServiceInstanceName, cfServiceInstanceKeyName, serviceKey } =
|
|
98
|
+
await this._getOrCreateCFService(projectPath, currentModelFolder, serviceName, tunnelAddress);
|
|
99
|
+
serviceKeyName = cfServiceInstanceKeyName;
|
|
100
|
+
serviceName = serviceName || cfServiceInstanceName;
|
|
87
101
|
|
|
88
|
-
|
|
102
|
+
vcapEnv = this._getVCAPServicesEntry(cfServiceInstanceName, serviceKey);
|
|
89
103
|
|
|
90
|
-
|
|
91
|
-
|
|
104
|
+
if (options.storeCredentials) {
|
|
105
|
+
await this._addInstanceToDefaultEnvJson([currentModelFolder, projectPath], cfServiceInstanceName, serviceKey);
|
|
106
|
+
}
|
|
92
107
|
}
|
|
93
|
-
}
|
|
94
108
|
|
|
95
|
-
|
|
96
|
-
|
|
109
|
+
console.log(`${bold('Starting deployment to SAP HANA ...')}`);
|
|
110
|
+
|
|
111
|
+
hdiOptions = hdiOptions || {}
|
|
112
|
+
await hdiDeployUtil.deploy(currentModelFolder, vcapEnv, hdiOptions);
|
|
97
113
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
114
|
+
if (!hasVCAPEnv) {
|
|
115
|
+
const bindOptions = {
|
|
116
|
+
...options,
|
|
117
|
+
to: `${serviceName}:${serviceKeyName}`,
|
|
118
|
+
for: options.for,
|
|
119
|
+
kind: buildResult.task.for
|
|
120
|
+
}
|
|
121
|
+
await bind(bindOptions);
|
|
104
122
|
}
|
|
105
|
-
await bind(bindOptions);
|
|
106
123
|
}
|
|
107
|
-
}
|
|
108
124
|
|
|
109
|
-
|
|
110
|
-
|
|
125
|
+
if (options.storeCredentials) {
|
|
126
|
+
await gitUtil.ensureFileIsGitignored('default-env.json', projectPath);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log(`If not already done, use ${info('cds add hana')} to configure the project for SAP HANA.\n`);
|
|
111
130
|
}
|
|
112
131
|
|
|
113
|
-
console.log(`If not already done, use ${info('cds add hana')} to configure the project for SAP HANA.\n`);
|
|
114
132
|
console.log(`Done.`);
|
|
115
133
|
|
|
116
134
|
return { buildResults };
|
package/lib/index.js
CHANGED
|
@@ -21,5 +21,11 @@ if (cds.compile.to.constructor.name === 'Object') { // not a class as in cds 7
|
|
|
21
21
|
|
|
22
22
|
cds.schema = cds.schema || {} // backward compatibility
|
|
23
23
|
cds.extend (cds.schema) .with ( {
|
|
24
|
-
overlay4
|
|
24
|
+
get overlay4() { return super.overlay4 = require('./env/schema') }
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
// set build API, potentially removing the old API facade from sap/cds 7
|
|
28
|
+
delete cds.__proto__?.build
|
|
29
|
+
cds.extend (cds.constructor) .with (class {
|
|
30
|
+
get build() { return super.build = require('./build') }
|
|
25
31
|
})
|
package/lib/init/constants.js
CHANGED
|
@@ -27,9 +27,10 @@ module.exports = {
|
|
|
27
27
|
POSTGRES: 'postgres',
|
|
28
28
|
SQLITE: 'sqlite',
|
|
29
29
|
H2: 'h2',
|
|
30
|
+
LOCAL_MESSAGING: 'local-messaging',
|
|
31
|
+
FILE_BASED_MESSAGING: 'file-based-messaging',
|
|
30
32
|
ENTERPRISE_MESSAGING: 'enterprise-messaging',
|
|
31
33
|
ENTERPRISE_MESSAGING_SHARED: 'enterprise-messaging-shared',
|
|
32
|
-
FILE_BASED_MESSAGING: 'file-based-messaging',
|
|
33
34
|
REDIS_MESSAGING: 'redis-messaging',
|
|
34
35
|
APPROUTER: 'approuter',
|
|
35
36
|
DESTINATION: 'destination',
|
|
@@ -40,7 +41,8 @@ module.exports = {
|
|
|
40
41
|
LINT_DEV: 'lint:dev',
|
|
41
42
|
HELM: 'helm',
|
|
42
43
|
TYPER: 'typer',
|
|
43
|
-
HTML5_REPO: 'html5-repo'
|
|
44
|
+
HTML5_REPO: 'html5-repo',
|
|
45
|
+
NOTIFICATIONS: 'notifications'
|
|
44
46
|
}),
|
|
45
47
|
|
|
46
48
|
PROJECT_TYPE: Object.freeze({ nodejs: 1, java: 2, unknown: 3 }),
|
|
@@ -112,6 +112,17 @@ const hdiContainer = {
|
|
|
112
112
|
}]
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
const notificationTypesDeployer = {
|
|
116
|
+
in: 'modules',
|
|
117
|
+
where: [{
|
|
118
|
+
property: 'name',
|
|
119
|
+
isEqualTo: 'notification-content-deployment'
|
|
120
|
+
}, {
|
|
121
|
+
property: 'type',
|
|
122
|
+
isEqualTo: 'nodejs'
|
|
123
|
+
}]
|
|
124
|
+
}
|
|
125
|
+
|
|
115
126
|
const serviceManager = {
|
|
116
127
|
in: 'resources',
|
|
117
128
|
where: [{
|
|
@@ -273,6 +284,7 @@ module.exports = {
|
|
|
273
284
|
enterpriseMessaging,
|
|
274
285
|
hdbDeployer,
|
|
275
286
|
hdiContainer,
|
|
287
|
+
notificationTypesDeployer,
|
|
276
288
|
serviceManager,
|
|
277
289
|
postgres,
|
|
278
290
|
postgresDeployer,
|
|
@@ -23,6 +23,7 @@ module.exports = class EnterpriseMessagingTemplate extends require('../templateB
|
|
|
23
23
|
const project = await readProject()
|
|
24
24
|
const { configFile } = project
|
|
25
25
|
await mergeJSON(configFile, join(__dirname, 'files', 'package.json.hbs'), project)
|
|
26
|
+
await mergeJSON('event-mesh.json', join(__dirname, 'files', 'event-mesh.json.hbs'), project)
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
async runDependentMerging(context = {}) {
|
|
@@ -30,7 +31,6 @@ module.exports = class EnterpriseMessagingTemplate extends require('../templateB
|
|
|
30
31
|
const { hasXsuaa, hasHelm, hasMta, isNodejs, srvPath, appName } = project
|
|
31
32
|
|
|
32
33
|
if (hasMta) {
|
|
33
|
-
await mergeJSON('event-mesh.json', join(__dirname, 'files', 'event-mesh.json.hbs'), project)
|
|
34
34
|
const srv = (isNodejs ? srvNode4 : srvJava4)(srvPath)
|
|
35
35
|
await mergeYAML(
|
|
36
36
|
'mta.yaml',
|