@sap/cds-dk 7.7.1 → 7.8.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 +42 -17
- package/bin/bind.js +21 -12
- package/bin/build.js +14 -2
- package/bin/deploy/to-sqlite.js +1 -1
- package/bin/help.js +4 -1
- package/bin/import.js +5 -1
- package/bin/version.js +54 -22
- package/lib/bind/userCdsrcJsonStorageProvider.js +1 -1
- package/lib/build/buildTaskFactory.js +2 -2
- package/lib/build/provider/hana/index.js +1 -1
- package/lib/build/provider/internalBuildTaskProvider.js +19 -5
- package/lib/build/provider/java/index.js +4 -4
- package/lib/build/provider/mtx/resourcesTarBuilder.js +16 -4
- package/lib/build/provider/mtx-extension/extensionCompilation.js +13 -2
- package/lib/build/provider/mtx-extension/index.js +6 -2
- package/lib/build/provider/nodejs/index.js +4 -4
- package/lib/build/util.js +1 -12
- package/lib/compile/openapi/index.js +2 -1
- package/lib/deploy/to-hana/hana.js +19 -17
- package/lib/import/common.js +1 -1
- package/lib/import/importapi.js +1 -1
- package/lib/import/odata/v4parser.js +18 -11
- package/lib/index.js +2 -2
- package/lib/init/constants.js +2 -1
- package/lib/init/index.js +9 -23
- package/lib/init/mvn.js +1 -5
- package/lib/init/plugin.js +8 -0
- package/lib/init/registries/mta.js +6 -0
- package/lib/init/template/data/as-csv.js +60 -0
- package/lib/init/template/data/as-json.js +441 -0
- package/lib/init/template/data/index.js +115 -86
- package/lib/init/template/helm/files/content-deployment/Chart.yaml +1 -1
- package/lib/init/template/helm/files/content-deployment/templates/job.yaml +7 -0
- package/lib/init/template/helm/files/content-deployment/values.schema.json +17 -0
- package/lib/init/template/helm/files/content-deployment/values.yaml +6 -1
- package/lib/init/template/helm/files/service-instance/Chart.yaml +1 -1
- package/lib/init/template/helm/files/service-instance/templates/serviceinstance.yaml +4 -0
- package/lib/init/template/helm/files/service-instance/values.schema.json +17 -1
- package/lib/init/template/helm/files/service-instance/values.yaml +4 -1
- package/lib/init/template/helm/files/values.yaml.hbs +2 -2
- package/lib/init/template/helm/files/web-application/Chart.yaml +1 -1
- package/lib/init/template/helm/files/web-application/templates/api-rule.yaml +4 -0
- package/lib/init/template/helm/files/web-application/templates/network-policy.yaml +15 -0
- package/lib/init/template/helm/files/web-application/values.schema.json +41 -0
- package/lib/init/template/helm/files/web-application/values.yaml +19 -1
- package/lib/init/template/helm-unified-runtime/files/values.yaml.hbs +2 -2
- package/lib/init/template/helm-unified-runtime/index.js +9 -6
- package/lib/init/template/http/index.js +182 -0
- package/lib/init/template/kafka/files/mta.yaml.hbs +14 -0
- package/lib/init/template/kafka/files/package.json.hbs +22 -0
- package/lib/init/template/kafka/index.js +40 -0
- package/lib/init/template/lint/index.js +4 -4
- package/lib/init/template/mta/files/mta.yaml.hbs +4 -0
- package/lib/init/template/multitenancy/files/values.yaml.hbs +2 -2
- package/lib/util/cf.js +6 -2
- package/npm-shrinkwrap.json +300 -276
- package/package.json +1 -1
package/bin/add.js
CHANGED
|
@@ -1,10 +1,31 @@
|
|
|
1
|
-
const cds = require('../lib/cds')
|
|
2
|
-
const
|
|
1
|
+
const cds = require('../lib/cds'), { fs } = cds.utils
|
|
2
|
+
const DEBUG = cds.debug('add')
|
|
3
|
+
const { join } = require('path')
|
|
4
|
+
|
|
5
|
+
const fromDk = fs.readdirSync(join(__dirname, '../lib/init/template'))
|
|
6
|
+
const fromPlugins = require('../lib/init/add').registered
|
|
7
|
+
const conf = {}
|
|
8
|
+
for (const plugin of [...fromDk, ...Object.keys(Object.fromEntries(fromPlugins))]) {
|
|
9
|
+
const Plugin = fromPlugins.get(plugin) ?? require(join(__dirname, '../lib/init/template', plugin))
|
|
10
|
+
for (const [key, { type, help, short }] of Object.entries(new Plugin().options())) {
|
|
11
|
+
conf[plugin] ??= { options: [], flags: [], help: [] }
|
|
12
|
+
if (type === 'boolean') conf[plugin].flags.push({ key: '--'+key, short: short ? '-'+short : undefined, help })
|
|
13
|
+
else if (type === 'number') conf[plugin].options.push({ key: '--'+key, short: short ? '-'+short : undefined, help })
|
|
14
|
+
else if (type === 'string') conf[plugin].options.push({ key: '--'+key, short: short ? '-'+short : undefined, help })
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const byShortcut = (a, b) => (b.short ? 1 : 0) - (a.short ? 1 : 0)
|
|
19
|
+
|
|
20
|
+
const options = ['--for', ...Object.values(conf).flatMap(p => p.options).sort(byShortcut).map(o => o.key)]
|
|
21
|
+
const shortcuts = ['-4', ...Object.values(conf).flatMap(p => p.options).sort(byShortcut).map(o => o.short)]
|
|
22
|
+
const flags = ['--force', ...Object.values(conf).flatMap(p => p.flags).map(o => o.key)]
|
|
23
|
+
DEBUG?.('cli config ', { options, shortcuts, flags })
|
|
3
24
|
|
|
4
25
|
module.exports = Object.assign(add, {
|
|
5
|
-
options
|
|
6
|
-
shortcuts
|
|
7
|
-
flags
|
|
26
|
+
options,
|
|
27
|
+
shortcuts,
|
|
28
|
+
flags,
|
|
8
29
|
help: `
|
|
9
30
|
# SYNOPSIS
|
|
10
31
|
|
|
@@ -12,7 +33,7 @@ module.exports = Object.assign(add, {
|
|
|
12
33
|
|
|
13
34
|
Add one or more features to an existing project - grow as you go.
|
|
14
35
|
|
|
15
|
-
|
|
36
|
+
Pick any of these:
|
|
16
37
|
|
|
17
38
|
*hana* - add support for SAP HANA
|
|
18
39
|
|
|
@@ -65,23 +86,24 @@ module.exports = Object.assign(add, {
|
|
|
65
86
|
|
|
66
87
|
# OPTIONS
|
|
67
88
|
|
|
68
|
-
*--for* <profile>
|
|
89
|
+
*--for | -4* <profile>
|
|
69
90
|
|
|
70
91
|
Write configuration data for the given profile.
|
|
71
92
|
|
|
72
|
-
*--
|
|
93
|
+
*--force*
|
|
73
94
|
|
|
74
|
-
|
|
75
|
-
meta characters like '^' or '*', it is treated like a regular expression,
|
|
76
|
-
otherwise as a prefix.
|
|
95
|
+
Overwrite all files in case the target files already exist.
|
|
77
96
|
|
|
78
|
-
*-o* | *--out* <target folder>
|
|
79
97
|
|
|
80
|
-
|
|
98
|
+
# FEATURE OPTIONS
|
|
81
99
|
|
|
82
|
-
|
|
100
|
+
${Object.entries(conf).sort(([a], [b]) => a.localeCompare(b)).flatMap(([pluginName, { options, flags }]) => {
|
|
101
|
+
const text4 = arr => arr.map(({ key, help, short }) => help && ` ${key}${short ? ' | '+short : ''}\n\n ${help}`).join('\n\n')
|
|
102
|
+
const optionsText = text4(options), flagsText = text4(flags)
|
|
103
|
+
if (!optionsText && !flagsText) return []
|
|
104
|
+
return ` *cds add ${pluginName}*\n\n${optionsText}${flagsText}`
|
|
105
|
+
}).join('\n\n\n')}
|
|
83
106
|
|
|
84
|
-
Overwrite all files in case the target files already exist.
|
|
85
107
|
|
|
86
108
|
# EXAMPLES
|
|
87
109
|
|
|
@@ -98,9 +120,12 @@ module.exports = Object.assign(add, {
|
|
|
98
120
|
|
|
99
121
|
`})
|
|
100
122
|
|
|
101
|
-
async function add(
|
|
123
|
+
async function add(features) {
|
|
102
124
|
await cds.plugins
|
|
103
125
|
const CDSGenerator = require('../lib/init')
|
|
104
126
|
const generator = new CDSGenerator()
|
|
105
|
-
|
|
127
|
+
|
|
128
|
+
const args = features.map(f => f.split(/[,\s+]/)).flat()
|
|
129
|
+
|
|
130
|
+
await generator.add(args)
|
|
106
131
|
}
|
package/bin/bind.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
const { warn } = require('../lib/util/term')
|
|
2
|
+
|
|
1
3
|
module.exports = Object.assign(cds_bind, {
|
|
2
|
-
options: ['--to', '--for', '--on', '--kind', '--
|
|
4
|
+
options: ['--to', '--for', '--on', '--kind', '--out', '--to-app-services', '--no-create-service-key', '--output-file'],
|
|
3
5
|
flags: ['--exec'],
|
|
4
6
|
shortcuts: ['-2', '-4', '-n', '-k', '-o', '-a'],
|
|
5
7
|
help: `
|
|
@@ -12,7 +14,7 @@ module.exports = Object.assign(cds_bind, {
|
|
|
12
14
|
information in *.cdsrc-private.json*
|
|
13
15
|
in your project directory. Credentials are not stored in the file but rather
|
|
14
16
|
retrieved dynamically during *cds watch*.
|
|
15
|
-
Use option *--
|
|
17
|
+
Use option *--out* to specify a different path or file.
|
|
16
18
|
|
|
17
19
|
With *--exec* you can execute arbitrary commands with your service bindings.
|
|
18
20
|
The service bindings are provided
|
|
@@ -36,11 +38,11 @@ module.exports = Object.assign(cds_bind, {
|
|
|
36
38
|
|
|
37
39
|
Kind of the service.
|
|
38
40
|
|
|
39
|
-
*-o | --
|
|
41
|
+
*-o | --out* <path>
|
|
40
42
|
|
|
41
43
|
Output file for added binding information. Use this option if binding configuration should
|
|
42
|
-
be added to *package.json* or *.cdsrc.json*.
|
|
43
|
-
|
|
44
|
+
be added to *package.json* or *.cdsrc.json*. If *path* is a directory, the *.cdsrc.json*
|
|
45
|
+
file in that directory is used. Defaults to *.cdsrc-private.json*.
|
|
44
46
|
|
|
45
47
|
*-a | --to-app-services <app>* (Beta)
|
|
46
48
|
|
|
@@ -56,8 +58,7 @@ module.exports = Object.assign(cds_bind, {
|
|
|
56
58
|
cds bind --to bookshop-db,bookshop-auth
|
|
57
59
|
cds bind auth --to bookshop-auth:bookshop-auth-key --kind xsuaa --for my-profile
|
|
58
60
|
|
|
59
|
-
cds bind --to bookshop-db --
|
|
60
|
-
cds bind --to bookshop-db --output-file package.json
|
|
61
|
+
cds bind --to bookshop-db --out .cdsrc.json
|
|
61
62
|
|
|
62
63
|
cds bind --to bookshop-db --on k8s
|
|
63
64
|
cds bind --to bookshop-db --for my-profile
|
|
@@ -74,7 +75,9 @@ const { bind, parseProfile } = require('../lib/bind');
|
|
|
74
75
|
|
|
75
76
|
async function cds_bind(args, options) {
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
const { on, 'to-app-services': app, to, out, 'output-file': outputFile, exec } = options
|
|
79
|
+
|
|
80
|
+
if (exec) {
|
|
78
81
|
process.env.CDS_ENV = parseProfile(process.env.CDS_ENV);
|
|
79
82
|
if (options.for) {
|
|
80
83
|
console.warn('Parameter --for is not supported in combination with --exec. Its value will be ignored.');
|
|
@@ -87,7 +90,10 @@ async function cds_bind(args, options) {
|
|
|
87
90
|
throw 'Option --profile is no longer supported. Use --for instead to specify the profile to use when storing connection settings.';
|
|
88
91
|
}
|
|
89
92
|
|
|
90
|
-
|
|
93
|
+
if (outputFile) {
|
|
94
|
+
console.warn(warn('Option --output-file is deprecated. Please use --out instead.'))
|
|
95
|
+
options.out ??= outputFile
|
|
96
|
+
}
|
|
91
97
|
|
|
92
98
|
if (on === 'k8s' && app) {
|
|
93
99
|
throw 'Option --to-app-services is only supported for Cloud Foundry.';
|
|
@@ -97,12 +103,15 @@ async function cds_bind(args, options) {
|
|
|
97
103
|
throw `Use option --to or -2 to specify the target instance, e.g. cds bind --to myInstance:myService`;
|
|
98
104
|
}
|
|
99
105
|
|
|
100
|
-
|
|
106
|
+
if (app === true) {
|
|
107
|
+
throw `Option '--to-app-services' requires an app name, for example 'cds bind --to-app-services bookshop-srv'.`
|
|
108
|
+
}
|
|
109
|
+
|
|
101
110
|
if (app) {
|
|
102
111
|
const services = await require('../lib/util/cf').getServices(app)
|
|
103
112
|
// Later: optimize logging for parallelization, services.forEach(service => bind({ ...options, to: service.name, outputFile }))
|
|
104
113
|
for (const service of services.filter(s => Object.keys(s.credentials).length > 0)) {
|
|
105
|
-
await bind({ ...options, to: service.name,
|
|
114
|
+
await bind({ ...options, to: service.name, out })
|
|
106
115
|
}
|
|
107
116
|
} else {
|
|
108
117
|
if (args.length > 1) {
|
|
@@ -120,7 +129,7 @@ async function cds_bind(args, options) {
|
|
|
120
129
|
throw `The option '--kind' cannot be specified together with multiple targets ('--to') services. Use one service per call or omit the '--kind' option.`;
|
|
121
130
|
}
|
|
122
131
|
|
|
123
|
-
await bind({ ...options,
|
|
132
|
+
await bind({ ...options, out });
|
|
124
133
|
}
|
|
125
134
|
}
|
|
126
135
|
|
package/bin/build.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module.exports = Object.assign(build, {
|
|
2
2
|
options: ['--project', '--src', '--dest', '--for', '--use', '--opts', '--log-level', '--options-model'],
|
|
3
3
|
shortcuts: ['-in', '-s', '-o', '-4'],
|
|
4
|
-
flags: ['--clean', '--no-clean', '--ws'], // REVISIT: --clean is deprecated, backward compatibility
|
|
4
|
+
flags: ['--clean', '--no-clean', '--ws', '--ws-pack'], // REVISIT: --clean is deprecated, backward compatibility
|
|
5
5
|
help: `
|
|
6
6
|
# SYNOPSIS
|
|
7
7
|
|
|
@@ -73,13 +73,25 @@ module.exports = Object.assign(build, {
|
|
|
73
73
|
operation. Clients need to clean the output folder upfront to ensure
|
|
74
74
|
consistent build results.
|
|
75
75
|
|
|
76
|
-
*--ws* (beta)
|
|
76
|
+
*--ws-pack* (beta)
|
|
77
77
|
Enable tarball based packaging of npm workspace dependencies - typically defined for
|
|
78
78
|
Node.js mono or multi-repo setups.
|
|
79
79
|
For each workspace dependency of your project using '*' as version identifier,
|
|
80
80
|
a tarball will be created in folder 'gen/srv'. Dependencies in package.json
|
|
81
81
|
will be adapted to point to the correct tarball file URL.
|
|
82
82
|
Contents is packaged based on the rules of the 'npm pack' command.
|
|
83
|
+
|
|
84
|
+
*--ws* (beta)
|
|
85
|
+
Npm workspaces are typically used in mono or multi-repo setups whereas each workspace
|
|
86
|
+
folder represents a microservice CAP project with subfolders _db_, _srv_, _app_.
|
|
87
|
+
With the *ws* option the model scope used in executed build tasks is calculated based on
|
|
88
|
+
all workspaces. This also applies to the feature toggles. Feature toggles defined cross workspace
|
|
89
|
+
are merged. The output is created in the _mtx/sidecar_ for multitenant applications
|
|
90
|
+
or in the 'srv' folder for node.js apps if no sidecar exists.
|
|
91
|
+
HANA native content distributed across the workspaces is copied into the top-level 'db'
|
|
92
|
+
folder of the project. This 'db' folder represents the single database shared by all workspaces.
|
|
93
|
+
*Note:* Make sure to use consistent package versions in your workspace dependencies in order
|
|
94
|
+
to avoid compilation errors caused by duplicate model definitions.
|
|
83
95
|
|
|
84
96
|
# EXAMPLES
|
|
85
97
|
|
package/bin/deploy/to-sqlite.js
CHANGED
|
@@ -4,7 +4,7 @@ exports.deploy = function deploy_to_sqlite (_model, _db, options) {
|
|
|
4
4
|
|
|
5
5
|
const cds = require('../../lib/cds')
|
|
6
6
|
const conf = cds.env.requires.db ?? {}
|
|
7
|
-
const fts = cds.env.features.folders
|
|
7
|
+
const fts = cds.env.requires.toggles && cds.env.features.folders
|
|
8
8
|
const model = _model || conf.model || cds.resolve(!fts ? '*' : ['*',fts], false)
|
|
9
9
|
let file = 'db'
|
|
10
10
|
if (options.to) {
|
package/bin/help.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const cds = require('../lib/cds')
|
|
2
|
+
|
|
1
3
|
/* eslint-disable no-console */
|
|
2
4
|
module.exports = exports = Object.assign (help, {formatHelp, help:`
|
|
3
5
|
# USAGE
|
|
@@ -38,7 +40,8 @@ module.exports = exports = Object.assign (help, {formatHelp, help:`
|
|
|
38
40
|
|
|
39
41
|
`})
|
|
40
42
|
|
|
41
|
-
function help (topic) {
|
|
43
|
+
async function help (topic) {
|
|
44
|
+
await cds.plugins
|
|
42
45
|
if (Array.isArray(topic)) topic = topic[0]
|
|
43
46
|
const task = !topic ? help : this.load?.(this.Shortcuts[topic] || topic)
|
|
44
47
|
if (task?.help) console.log (formatHelp (task.help))
|
package/bin/import.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module.exports = Object.assign(_import, {
|
|
2
2
|
_name: 'import',
|
|
3
3
|
options: ['--out', '--as', '--include-namespaces', '--from', '--config'],
|
|
4
|
-
flags: ['--dry', '--force', '--no-copy', '--no-save', '--keep-namespace'],
|
|
4
|
+
flags: ['--dry', '--force', '--no-copy', '--no-save', '--keep-namespace', '--beta'],
|
|
5
5
|
shortcuts: ['-o', '-as', '-ns', undefined, '-c', '-', '-f'],
|
|
6
6
|
help: `
|
|
7
7
|
# SYNOPSIS
|
|
@@ -47,6 +47,10 @@ module.exports = Object.assign(_import, {
|
|
|
47
47
|
*-c | --config* <JSON Object>
|
|
48
48
|
Adds the provided JSON Object as custom configuration data to the package.json.
|
|
49
49
|
|
|
50
|
+
*--beta*
|
|
51
|
+
Enables beta mode in cds import.
|
|
52
|
+
- Populates default value for optional action and function parameters in the CSN or CDS.
|
|
53
|
+
|
|
50
54
|
*Below options are valid for OData only*
|
|
51
55
|
|
|
52
56
|
*--keep-namespace*
|
package/bin/version.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
const { join, resolve } = require ('path')
|
|
3
|
-
const { execSync } = require('child_process')
|
|
3
|
+
const { execSync, spawnSync } = require('child_process')
|
|
4
4
|
module.exports = Object.assign(list_versions, {
|
|
5
5
|
flags: [ '--info', '--markdown', '--all', '--npm-list', '--npm-tree', '--no-colors'],
|
|
6
6
|
shortcuts: [ '-i', '-m','-a', '-ls', '-ll' ],
|
|
@@ -35,38 +35,57 @@ module.exports = Object.assign(list_versions, {
|
|
|
35
35
|
const MISSING = '-- missing --'
|
|
36
36
|
|
|
37
37
|
function list_versions(args, options) {
|
|
38
|
+
const colorsOff = options['no-colors'] ?? !process.stdout.isTTY
|
|
39
|
+
|
|
38
40
|
if (options['npm-list'] || options['npm-tree']) {
|
|
39
41
|
let [pattern] = args, re = pattern ? RegExp(pattern) : /@sap\/cd[rs]|@sap\/eslint-plugin-cds/
|
|
40
42
|
let cmd = 'npm ls --depth ' + (options['npm-tree'] ? 11 : 0)
|
|
41
|
-
console.log (cmd,'| grep',
|
|
43
|
+
console.log (cmd,'| grep', re.source)
|
|
42
44
|
return require('child_process').exec(cmd, (e,stdout)=>{
|
|
43
45
|
// if (e) console.error(e)
|
|
44
|
-
const replacement = (
|
|
46
|
+
const replacement = (colorsOff ? '$1 $2$3$4' : '\x1b[91m$1 \x1b[32m$2\x1b[0m\x1b[2m$3\x1b[32m$4\x1b[0m');
|
|
45
47
|
for (let line of stdout.split(/\n/)) if (line.match(re)) console.log(
|
|
46
48
|
line.replace(/(@sap[^@]*)@([\S]+)( -> [\S]+)?(deduped)?/,replacement)
|
|
47
49
|
)
|
|
48
50
|
})
|
|
49
51
|
}
|
|
50
|
-
const versions = info ()
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
const versions = info (options)
|
|
53
|
+
|
|
54
|
+
process.stdout.isTTY && console.log()
|
|
55
|
+
if (options.markdown || options.info) {
|
|
56
|
+
_markdown (versions)
|
|
57
|
+
} else {
|
|
58
|
+
const mark = colorsOff ? s => s : require('../lib/util/term').info
|
|
59
|
+
for (let each of Object.keys(versions)) console.log(`${mark(each)}: ${versions[each]}`)
|
|
60
|
+
}
|
|
61
|
+
process.stdout.isTTY && console.log()
|
|
55
62
|
}
|
|
56
63
|
|
|
57
|
-
function info() {
|
|
58
|
-
const
|
|
64
|
+
function info({ root:cwd=process.cwd() }) {
|
|
65
|
+
const env = require('../lib').env.for('cds', cwd)
|
|
66
|
+
const isJava = env['project-nature'] === 'java'
|
|
67
|
+
if (isJava && process.stderr.isTTY) {
|
|
68
|
+
console.error('\x1b[2m'+'This takes a while. Collecting Java versions...', '\x1b[0m')
|
|
69
|
+
}
|
|
70
|
+
|
|
59
71
|
const npmRoot = execSync('npm root -g').toString().trim()
|
|
60
|
-
|
|
72
|
+
let versions = {
|
|
61
73
|
..._versions_from(_pkg_path('@sap/cds-dk', __dirname), '@sap/cds-dk (global)'), // ... linked in cap/dev setup
|
|
62
|
-
..._versions_from(_pkg_path('@sap/cds-dk', npmRoot),
|
|
63
|
-
..._versions_from(_pkg_path('@sap/cds-dk', cwd)),
|
|
74
|
+
..._versions_from(_pkg_path('@sap/cds-dk', npmRoot), '@sap/cds-dk (global)'), // ... or installed globally
|
|
75
|
+
..._versions_from(_pkg_path('@sap/cds-dk', cwd)), // local dk, important for Java projects
|
|
64
76
|
..._versions_from(_pkg_path('@sap/cds', __dirname)), // @sap/cds from here
|
|
65
|
-
..._versions_from(cwd),
|
|
77
|
+
..._versions_from(cwd), // ... or from local app dependencies
|
|
66
78
|
..._versions_from(_pkg_path('@sap/cds-compiler', cwd, __dirname)), // compiler is no direct dependency, so list it explicitly
|
|
67
79
|
'Node.js': process.version,
|
|
68
|
-
'home': require('../lib/cds').home // effective (local) cds
|
|
80
|
+
'home': require('../lib/cds').home, // effective (local) cds
|
|
69
81
|
}
|
|
82
|
+
// sort Node entries
|
|
83
|
+
versions = Object.keys(versions).sort().reduce((all, key) => { all[key] = versions[key]; return all }, {})
|
|
84
|
+
|
|
85
|
+
if (isJava) {
|
|
86
|
+
Object.assign(versions, capJavaVersion(cwd))
|
|
87
|
+
}
|
|
88
|
+
return versions
|
|
70
89
|
}
|
|
71
90
|
|
|
72
91
|
function _versions_from(pkg_path, pkg_label) {
|
|
@@ -95,7 +114,6 @@ function _markdown (versions) {
|
|
|
95
114
|
const repo = pkg.repository.url || pkg.repository || 'https://github.com/<your/repo>'
|
|
96
115
|
const valLength = Math.max(repo.length, versions.home.length)
|
|
97
116
|
|
|
98
|
-
console.log ()
|
|
99
117
|
console.log ('|', $(pkg.name, repo), '|')
|
|
100
118
|
console.log ('|', $('----------------------', '-'.repeat(valLength)), '|')
|
|
101
119
|
|
|
@@ -104,12 +122,6 @@ function _markdown (versions) {
|
|
|
104
122
|
.sort()
|
|
105
123
|
.forEach(id => console.log ('|', $(id, versions[id]), '|'))
|
|
106
124
|
|
|
107
|
-
// TODO get CAP Java version from mvn
|
|
108
|
-
// if (require('../lib').env['project-nature'] === 'java') {
|
|
109
|
-
// console.log ('|', $('CAP Java Runtime'), '|')
|
|
110
|
-
// }
|
|
111
|
-
console.log()
|
|
112
|
-
|
|
113
125
|
function $ (key, val=MISSING) {
|
|
114
126
|
return ( key + ' '.repeat(22)).slice(0,22)
|
|
115
127
|
+' | '+ (val + ' '.repeat(valLength)).slice(0,valLength)
|
|
@@ -124,3 +136,23 @@ function _pkg_path(id, ...paths) {
|
|
|
124
136
|
if (e.code !== 'MODULE_NOT_FOUND') throw e
|
|
125
137
|
}
|
|
126
138
|
}
|
|
139
|
+
|
|
140
|
+
function capJavaVersion(cwd) {
|
|
141
|
+
const cmd = 'mvn com.sap.cds:cds-maven-plugin:version -B -Dcds.version.excludeCds -Dcds.version.json'
|
|
142
|
+
|
|
143
|
+
let out = ''
|
|
144
|
+
try {
|
|
145
|
+
out = spawnSync(cmd, {cwd, shell: true}).stdout.toString().trim()
|
|
146
|
+
} catch (e) { /* ignored */ }
|
|
147
|
+
|
|
148
|
+
const match = out.match(/===\n(.*)\n===/ms)
|
|
149
|
+
if (match?.[1]) {
|
|
150
|
+
const res = {}
|
|
151
|
+
Object.entries(JSON.parse(match[1])).forEach(([k,v]) => {
|
|
152
|
+
const entries = Object.entries(v)
|
|
153
|
+
res[k] = entries.map(([k,v]) => (k === 'version' || k === 'name') ? v : `${k}: ${v}`).join(', ')
|
|
154
|
+
})
|
|
155
|
+
return res
|
|
156
|
+
}
|
|
157
|
+
return { 'CAP Java SDK': MISSING }
|
|
158
|
+
}
|
|
@@ -31,7 +31,7 @@ class UserCdsrcJsonStorageProvider {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
async storeServices(services, options = {}) {
|
|
34
|
-
let jsonPath = options.
|
|
34
|
+
let jsonPath = options.out || CDSRC_FILENAME;
|
|
35
35
|
|
|
36
36
|
if (jsonPath === CDSRC_FILENAME) {
|
|
37
37
|
await gitUtil.ensureFileIsGitignored(CDSRC_FILENAME);
|
|
@@ -106,12 +106,12 @@ class BuildTaskFactory {
|
|
|
106
106
|
const modelPaths = await getDefaultModelOptions()
|
|
107
107
|
let wsModelPaths
|
|
108
108
|
// calculate only once
|
|
109
|
-
if (tasks.some(task => hasOptionValue(task.options?.[CONTENT_WS], true))) {
|
|
109
|
+
if (cds.cli.options?.ws || tasks.some(task => hasOptionValue(task.options?.[CONTENT_WS], true))) {
|
|
110
110
|
wsModelPaths = await getDefaultModelOptions(true)
|
|
111
111
|
}
|
|
112
112
|
// set default model options
|
|
113
113
|
tasks.forEach(task => {
|
|
114
|
-
this._setTaskModelOptions(task, hasOptionValue(task.options?.[CONTENT_WS], true) ? wsModelPaths : modelPaths)
|
|
114
|
+
this._setTaskModelOptions(task, cds.cli.options?.ws || hasOptionValue(task.options?.[CONTENT_WS], true) ? wsModelPaths : modelPaths)
|
|
115
115
|
if (!task.src) {
|
|
116
116
|
throw new Error(`Invalid build task definition - value of property 'src' is missing in [${task.for || task.use}].`)
|
|
117
117
|
}
|
|
@@ -50,7 +50,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
50
50
|
await this._copyResourcesExt(src, dest, model)
|
|
51
51
|
}
|
|
52
52
|
// copy native hana artifacts from workspace dependencies
|
|
53
|
-
if (hasOptionValue(this.task.options?.[CONTENT_WS], true)) {
|
|
53
|
+
if (cds.cli.options?.ws || hasOptionValue(this.task.options?.[CONTENT_WS], true)) {
|
|
54
54
|
await this._addWorkspaceContent()
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const cds = require('../../cds')
|
|
4
|
-
const { hasJavaNature, getDefaultModelOptions, BuildError, hasOptionValue,
|
|
4
|
+
const { hasJavaNature, getDefaultModelOptions, BuildError, hasOptionValue, normalizePath } = require('../util')
|
|
5
5
|
const BuildTaskProvider = require('../buildTaskProvider')
|
|
6
6
|
const { FILE_EXT_CDS, BUILD_TASK_HANA, BUILD_TASK_FIORI, BUILD_TASK_JAVA, BUILD_TASK_JAVA_CF, BUILD_TASK_NODEJS, BUILD_TASK_NODE_CF, BUILD_TASK_MTX,
|
|
7
7
|
BUILD_TASK_PREFIX, BUILD_TASKS, BUILD_TASK_MTX_SIDECAR, MTX_SIDECAR_FOLDER, BUILD_TASK_MTX_EXTENSION, NODEJS_MODEL_EXCLUDE_LIST,
|
|
8
8
|
IGNORE_DEFAULT_MODELS, CONTENT_WS } = require("../constants")
|
|
9
|
+
const ResourcesTarBuilder = require('./mtx/resourcesTarBuilder')
|
|
9
10
|
const DEBUG = cds.debug('cli|build')
|
|
10
11
|
|
|
11
12
|
class InternalBuildTaskProvider extends BuildTaskProvider {
|
|
12
13
|
constructor() {
|
|
13
14
|
super()
|
|
14
15
|
// ensure that classic mtx is not used in combination with cds-dk@7
|
|
15
|
-
if (
|
|
16
|
+
if (InternalBuildTaskProvider._isClassicMtx()) {
|
|
16
17
|
throw new BuildError(`@sap/cds-mtx is deprecated and not supported by @sap/cds-dk >= 7.
|
|
17
18
|
Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/docs/guides/multitenancy/old-mtx-migration or install @sap/cds-dk version 6 instead.`)
|
|
18
19
|
}
|
|
@@ -78,10 +79,12 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
|
|
|
78
79
|
}
|
|
79
80
|
})
|
|
80
81
|
}
|
|
81
|
-
let dbTask =
|
|
82
|
+
let dbTask = ResourcesTarBuilder.getHanaTenantDbTask(tasks, mtxTask)
|
|
82
83
|
if (!dbTask) {
|
|
83
84
|
// db task might be missing if mtx task is enforced by 'cds build --for mtx'
|
|
84
|
-
|
|
85
|
+
if (cds.env.build.tasks) {
|
|
86
|
+
dbTask = ResourcesTarBuilder.getHanaTenantDbTask(cds.env.build.tasks, mtxTask)
|
|
87
|
+
}
|
|
85
88
|
if (!dbTask) {
|
|
86
89
|
dbTask = this._createDbTask(db, dbOptions)
|
|
87
90
|
}
|
|
@@ -251,6 +254,17 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
|
|
|
251
254
|
return !!cds.env.extends
|
|
252
255
|
}
|
|
253
256
|
|
|
257
|
+
static _isClassicMtx() {
|
|
258
|
+
function _hasMtxDependency() {
|
|
259
|
+
try {
|
|
260
|
+
return !!require(path.join(cds.root, 'package.json'))?.dependencies?.['@sap/cds-mtx']
|
|
261
|
+
} catch (e) {
|
|
262
|
+
return false
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return /true/i.test(process.env.OLD_MTX) || _hasMtxDependency()
|
|
266
|
+
}
|
|
267
|
+
|
|
254
268
|
/**
|
|
255
269
|
* Distinguishes whether the Nodejs project is a Streamlined MTX (cds >=6) or an old MTX project.
|
|
256
270
|
*/
|
|
@@ -294,7 +308,7 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
|
|
|
294
308
|
}
|
|
295
309
|
|
|
296
310
|
static async _setDefaultModel(task) {
|
|
297
|
-
const ws = hasOptionValue(task.options?.[CONTENT_WS], true)
|
|
311
|
+
const ws = hasOptionValue(task.options?.[CONTENT_WS], true) || cds.cli.options?.ws
|
|
298
312
|
let taskModelPaths = task.options?.model
|
|
299
313
|
if (taskModelPaths && !Array.isArray(taskModelPaths)) {
|
|
300
314
|
taskModelPaths = [taskModelPaths]
|
|
@@ -21,16 +21,16 @@ class JavaBuildPlugin extends EdmxBuildPlugin {
|
|
|
21
21
|
if (!model) {
|
|
22
22
|
return
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
await this._compileForJava(model, compileDest)
|
|
25
25
|
|
|
26
26
|
if (!this.hasBuildOption(CONTENT_EDMX, false)) {
|
|
27
27
|
// generate edmx files containing all features
|
|
28
28
|
// REVISIT: localized edmx for backward compatibility
|
|
29
29
|
if (!this.hasBuildOption(CONTENT_LOCALIZED_EDMX, false)) {
|
|
30
|
-
await this.compileToEdmx(
|
|
30
|
+
await this.compileToEdmx(model, compileDest, { [FLAVOR_LOCALIZED_EDMX]: true })
|
|
31
31
|
}
|
|
32
32
|
// non-localized edmx
|
|
33
|
-
await this.compileToEdmx(
|
|
33
|
+
await this.compileToEdmx(model, path.join(compileDest, 'odata', cds.env.odata.version), { [FLAVOR_LOCALIZED_EDMX]: this.hasBuildOption(FLAVOR_LOCALIZED_EDMX, true) })
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
if (!this.hasBuildOption(CONTENT_LANGUAGE_BUNDLES, false)) {
|
|
@@ -65,7 +65,7 @@ class JavaBuildPlugin extends EdmxBuildPlugin {
|
|
|
65
65
|
})
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
async
|
|
68
|
+
async _compileForJava(model, csnDest, compileOptions = {}) {
|
|
69
69
|
// csn for service providers
|
|
70
70
|
const m = cds.compile.for.java(model, {
|
|
71
71
|
...this._options4odata(),
|
|
@@ -41,7 +41,7 @@ class ResourcesTarBuilder {
|
|
|
41
41
|
|
|
42
42
|
async _getResources(model) {
|
|
43
43
|
// distinguish HANA and SQLITE deployment
|
|
44
|
-
let root =
|
|
44
|
+
let root = this._getHanaTenantDbPath()
|
|
45
45
|
let resources
|
|
46
46
|
if (root) {
|
|
47
47
|
resources = this._getHanaResources(root)
|
|
@@ -82,9 +82,21 @@ class ResourcesTarBuilder {
|
|
|
82
82
|
return Object.keys(await resources(model))
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
_getHanaTenantDbPath() {
|
|
86
|
+
return ResourcesTarBuilder.getHanaTenantDbTask(this.plugin.context.tasks, this.plugin.task)?.dest
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static getHanaTenantDbTask(tasks, mtxTask) {
|
|
90
|
+
const hanaTasks = tasks.filter(task => task.for === BUILD_TASK_HANA)
|
|
91
|
+
if (hanaTasks.length === 1) return hanaTasks[0]
|
|
92
|
+
|
|
93
|
+
return hanaTasks.find(hanaTask => {
|
|
94
|
+
// if called from internalBuildTaskProvider, the src folder for the tenant db task might still not set
|
|
95
|
+
// while an existing second shared db always requires src to be configured using a relative path
|
|
96
|
+
if (!hanaTask.src) return true
|
|
97
|
+
const srcFolder = path.isAbsolute(hanaTask.src) ? path.relative(cds.root, hanaTask.src) : hanaTask.src
|
|
98
|
+
return mtxTask.options?.model?.includes(srcFolder)
|
|
99
|
+
})
|
|
88
100
|
}
|
|
89
101
|
}
|
|
90
102
|
module.exports = ResourcesTarBuilder
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
2
|
const cds = require('../../../cds')
|
|
3
|
-
const {
|
|
3
|
+
const { SEVERITY_WARNING, SEVERITY_INFO } = require('../../constants')
|
|
4
4
|
|
|
5
5
|
class ExtensionCompilation {
|
|
6
6
|
constructor(plugin) {
|
|
@@ -38,7 +38,7 @@ class ExtensionCompilation {
|
|
|
38
38
|
const pkgNames = [...[...duplicates].reduce((acc, dir) => acc.add(getPkgName(dir)), new Set())]
|
|
39
39
|
const modelPaths = this.plugin.task.options.model.filter(m => !pkgNames.some(pkg => m === pkg || m.startsWith(pkg + '/')))
|
|
40
40
|
this.plugin.task.options.model = modelPaths
|
|
41
|
-
this.plugin.pushMessage(`Duplicate CDS model definitions found. Using CDS artifacts from base model instead and recompiling with model options ${JSON.stringify(modelPaths)}.\nMake sure to use compatible versions for the dependencies '${pkgNames.join(', ')}'.`,
|
|
41
|
+
this.plugin.pushMessage(`Duplicate CDS model definitions found. Using CDS artifacts from base model instead and recompiling with model options ${JSON.stringify(modelPaths)}.\nMake sure to use compatible versions for the dependencies '${pkgNames.join(', ')}'.`, SEVERITY_WARNING)
|
|
42
42
|
// recompile without duplicates
|
|
43
43
|
return this.plugin.model()
|
|
44
44
|
}
|
|
@@ -46,5 +46,16 @@ class ExtensionCompilation {
|
|
|
46
46
|
resolveExtensionFiles(model, saasPkgFolder) {
|
|
47
47
|
return model['$sources'].filter(file => file.startsWith(cds.root) && !file.startsWith(saasPkgFolder))
|
|
48
48
|
}
|
|
49
|
+
|
|
50
|
+
reclassifyBaseModelMessages(messages, saasPkgPath) {
|
|
51
|
+
const severities = cds.env.cdsc?.severities ?? {}
|
|
52
|
+
messages.forEach(m => {
|
|
53
|
+
if (m.$location?.file && m.severity === SEVERITY_WARNING) {
|
|
54
|
+
if (path.resolve(cds.root, m.$location.file).startsWith(saasPkgPath) && !severities[m.messageId]) {
|
|
55
|
+
m.severity = SEVERITY_INFO
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
49
60
|
}
|
|
50
61
|
module.exports = ExtensionCompilation
|
|
@@ -28,7 +28,7 @@ class MtxExtensionBuildPlugin extends InternalBuildPlugin {
|
|
|
28
28
|
const saasPkgPath = MtxExtensionBuildPlugin._getSaasPkgPath()
|
|
29
29
|
const extensionCompilation = new ExtensionCompilation(this)
|
|
30
30
|
|
|
31
|
-
// full
|
|
31
|
+
// full model compilation including base model ensures consistency
|
|
32
32
|
try {
|
|
33
33
|
model = await this.model()
|
|
34
34
|
} catch (e) {
|
|
@@ -39,8 +39,8 @@ class MtxExtensionBuildPlugin extends InternalBuildPlugin {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
// extension model compilation with parsed format
|
|
42
43
|
if (model) {
|
|
43
|
-
// extension CSN using parsed format
|
|
44
44
|
const options = { ...this.options(), flavor: 'parsed' }
|
|
45
45
|
const extensionFiles = extensionCompilation.resolveExtensionFiles(model, saasPkgPath)
|
|
46
46
|
if (extensionFiles.length > 0) {
|
|
@@ -50,6 +50,10 @@ class MtxExtensionBuildPlugin extends InternalBuildPlugin {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
|
|
54
|
+
// reclassify base model warnings as info messages
|
|
55
|
+
extensionCompilation.reclassifyBaseModelMessages(this.messages, saasPkgPath)
|
|
56
|
+
|
|
53
57
|
if (extensionModel) {
|
|
54
58
|
// IMPORTANT NOTE: perform all model operations before the linter is called as the linter
|
|
55
59
|
// will modify the model causing the creation of 'unresolved' associations
|
|
@@ -36,7 +36,7 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
36
36
|
}
|
|
37
37
|
// by default model contains all features
|
|
38
38
|
const model = await this.model()
|
|
39
|
-
if (!model && !this.context.options['ws']) {
|
|
39
|
+
if (!model && !this.context.options['ws-pack']) {
|
|
40
40
|
return
|
|
41
41
|
}
|
|
42
42
|
if (model) {
|
|
@@ -55,8 +55,8 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
55
55
|
if (this.isStagingBuild() && this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM)) {
|
|
56
56
|
const srcSrv = this.task.src === cds.root ? path.resolve(this.task.src, cds.env.folders.srv) : this.task.src
|
|
57
57
|
await this._copyNativeContent(cds.root, srcSrv, destRoot, destSrv)
|
|
58
|
-
if (this.context.options['ws']) {
|
|
59
|
-
await this.
|
|
58
|
+
if (this.context.options['ws-pack']) {
|
|
59
|
+
await this._packWorkspaceDependencies(destRoot)
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
return this._result
|
|
@@ -158,7 +158,7 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
158
158
|
})
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
async
|
|
161
|
+
async _packWorkspaceDependencies(dest) {
|
|
162
162
|
const wsRoot = NodejsBuildPlugin._findWorkspaceRoot(cds.root)
|
|
163
163
|
const appPkg = require(path.join(dest, 'package.json'))
|
|
164
164
|
let workspaces
|