@sap/cds-dk 8.6.1 → 8.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 +25 -0
- package/bin/cds.js +1 -1
- package/bin/debug.js +122 -26
- package/bin/deploy/index.js +7 -0
- package/bin/import.js +54 -29
- package/bin/repl.js +2 -2
- package/bin/util/fuzzySearch.js +10 -10
- package/bin/watch.js +46 -16
- package/lib/build/buildTaskProviderFactory.js +8 -5
- package/lib/build/plugins/helm/files/subcharts/content-deployment/Chart.yaml +1 -1
- package/lib/build/plugins/helm/files/subcharts/content-deployment/templates/job.yaml +3 -2
- package/lib/build/plugins/helm/files/subcharts/content-deployment/values.yaml +1 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/Chart.yaml +1 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/templates/_helpers.tpl +3 -3
- package/lib/build/plugins/helm/files/subcharts/web-application/templates/api-rule.yaml +1 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/templates/deployment.yaml +13 -5
- package/lib/build/plugins/helm/files/subcharts/web-application/templates/service-binding.yaml +1 -0
- package/lib/build/plugins/helm/files/subcharts/web-application/values.schema.json +28 -15
- package/lib/build/plugins/helm/files/subcharts/web-application/values.yaml +22 -1
- package/lib/import/common.js +174 -44
- package/lib/import/importapi.js +1 -1
- package/lib/import/message.js +1 -1
- package/lib/import/odata/ParserContext.js +46 -0
- package/lib/import/odata/index.js +20 -11
- package/lib/import/odata/v4parser.js +25 -51
- package/lib/init/add.js +0 -2
- package/lib/init/constants.js +3 -3
- package/lib/init/index.js +1 -1
- package/lib/init/merge.js +67 -66
- package/lib/init/mvn.js +16 -12
- package/lib/init/projectReader.js +2 -2
- package/lib/init/template/approuter/files/mta.yaml.hbs +2 -4
- package/lib/init/template/hana/index.js +12 -8
- package/lib/init/template/ias/files/mta.yaml.hbs +15 -0
- package/lib/init/template/ias/index.js +22 -5
- package/lib/init/template/mta/files/mta.yaml.hbs +3 -13
- package/lib/init/template/multitenancy/files/mta.yaml.hbs +1 -0
- package/lib/init/template/multitenancy/index.js +5 -0
- package/lib/init/template/nodejs/files/package.json.hbs +1 -1
- package/lib/init/template/portal/files/portal-site/i18n/catalog.properties +1 -1
- package/lib/init/template/portal/files/portal-site/i18n/catalog_de.properties +1 -1
- package/lib/init/template/portal/files/portal-site/i18n/group.properties +1 -1
- package/lib/init/template/portal/files/portal-site/i18n/group_de.properties +1 -1
- package/lib/init/template/sample/files/typescript/admin-service.ts.hbs +16 -0
- package/lib/init/template/sample/files/typescript/cat-service.ts.hbs +38 -0
- package/lib/init/template/sample/index.js +16 -12
- package/lib/init/template/typescript/files/package.json +1 -1
- package/lib/lint/io.js +6 -16
- package/lib/watch/node-watch.js +3 -3
- package/npm-shrinkwrap.json +49 -33
- package/package.json +1 -1
- /package/lib/init/template/sample/files/{nodejs → javascript}/admin-service.js.hbs +0 -0
- /package/lib/init/template/sample/files/{nodejs → javascript}/cat-service.js.hbs +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,31 @@ This project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
9
9
|
|
|
10
|
+
## Version 8.7.0 - 2025-01-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `cds watch` supports `--exclude` and `--include` options to specify additional paths to include or exclude. Alternatively, set `cds.watch.[include|exclude]` in your CDS config.
|
|
15
|
+
- `cds import` now updates configuration for Java projects (in `application.yaml` etc.)
|
|
16
|
+
- `cds import --config` now also accepts a string with flat key-value pairs (like `--config "credentials.destination=foo"`), which is easier to write than the current JSON string (`--config "{\"credentials\": {\"destination\": \"foo\"}}"`).
|
|
17
|
+
- `cds debug` now supports Java applications, both local and remote.
|
|
18
|
+
- `cds import` can now import an odata-V4 file with external dependencies(odata-V4 file). Dependencies has to be provided with -d/--dependencies option and must not have any external dependencies.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- `cds add mta` sets backend and MTX `parameters.instances` to a default of `1` for improved discoverability.
|
|
23
|
+
- `cds add sample` generates sample .ts files if the project is a TypeScript project
|
|
24
|
+
- `cds import` now doesn't need beta flag to populate default value for optional action and function parameters as compiler now supports default value for @Core.OptionalParameters.
|
|
25
|
+
- `cds add portal` now uses a more generic sample translated title instead of "Bookshop".
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- `cds add mta` in combination with `cds add ias` correctly adds all routes to the backend module.
|
|
30
|
+
- `cds add mta` adds the DB deployer module without prior installation of `@cap-js/hana`.
|
|
31
|
+
- `cds add mta` adds the npm-ci builder for nodejs modules to use fixed package-lock versions for dependency vendoring.
|
|
32
|
+
- `cds build --ws` will no longer require a `db/` folder in the root directory of the project.
|
|
33
|
+
- `cds import` doesn't throw error while importing odata-V4 file with com.sap.vocabularies.
|
|
34
|
+
|
|
10
35
|
## Version 8.6.1 - 2024-12-18
|
|
11
36
|
|
|
12
37
|
### Fixed
|
package/bin/cds.js
CHANGED
|
@@ -204,7 +204,7 @@ function _dieForUnknownCommand(cmd) {
|
|
|
204
204
|
|
|
205
205
|
const commands = getCommands();
|
|
206
206
|
|
|
207
|
-
const bestMatches = fuzzySearch(cmd, commands, DEBUG);
|
|
207
|
+
const bestMatches = fuzzySearch(cmd, commands, DEBUG, { maxListLength: commands.length });
|
|
208
208
|
|
|
209
209
|
switch (bestMatches.length) {
|
|
210
210
|
case 0:
|
package/bin/debug.js
CHANGED
|
@@ -1,59 +1,133 @@
|
|
|
1
1
|
module.exports = Object.assign(debug, {
|
|
2
2
|
options: ['--port', '--host'],
|
|
3
|
-
shortcuts: [],
|
|
3
|
+
shortcuts: ['-p', '-h'],
|
|
4
4
|
flags: [/*'--vscode', '--k8s'*/],
|
|
5
5
|
help: `
|
|
6
6
|
# SYNOPSIS
|
|
7
7
|
|
|
8
8
|
*cds debug* [<app>]
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Debug applications running locally or remotely on Cloud Foundry.
|
|
11
|
+
Local applications will be started in debug mode, while remote applications
|
|
12
|
+
are put into debug mode.
|
|
11
13
|
|
|
12
|
-
If <app> is given, it's assumed to be running on the currently logged-in
|
|
14
|
+
If <app> is given, it's assumed to be running on the currently logged-in
|
|
15
|
+
Cloud Foundry space (check with 'cf target').
|
|
16
|
+
SSH access to the app is required (check with 'cf ssh-enabled').
|
|
13
17
|
|
|
14
|
-
If no <app> is given, the app in the current working is started
|
|
18
|
+
If no <app> is given, the app in the current working is started
|
|
19
|
+
(with 'cds watch --debug' for Node.js and 'mvn spring-boot:run' for Java).
|
|
15
20
|
|
|
16
21
|
# OPTIONS
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
*-h* | *--host*
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
the debug host (default: '127.0.0.1')
|
|
26
|
+
|
|
27
|
+
*-p* | *--port*
|
|
28
|
+
|
|
29
|
+
the debug port (default: '9229' for Node.js, '8000' for Java)
|
|
21
30
|
|
|
22
31
|
# EXAMPLES
|
|
23
32
|
|
|
24
33
|
*cds debug*
|
|
25
|
-
*cds debug* bookshop-srv
|
|
34
|
+
*cds debug* bookshop-srv --port 8001
|
|
26
35
|
`})
|
|
27
36
|
|
|
28
37
|
async function debug() {
|
|
29
|
-
const cds = require('../lib/cds')
|
|
30
38
|
const { fork, spawn, execSync, exec } = require('node:child_process')
|
|
31
39
|
const os = require('node:os').platform()
|
|
40
|
+
const cds = require('../lib/cds')
|
|
41
|
+
const DEBUG = /\b(y|all|debug)\b/.test(process.env.DEBUG) ? console.debug : undefined
|
|
32
42
|
|
|
33
43
|
const [appName] = cds.cli.argv
|
|
34
|
-
const { port
|
|
35
|
-
|
|
44
|
+
const { port, host = '127.0.0.1', vscode } = cds.cli.options
|
|
45
|
+
|
|
46
|
+
const maxAttempts = 15
|
|
47
|
+
let attempts = 0
|
|
36
48
|
|
|
37
49
|
if (!appName) { // local app
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
if (cds.env['project-nature'] === 'java') {
|
|
51
|
+
const portLocal = port || 8000
|
|
52
|
+
const cmd = `mvn`
|
|
53
|
+
const args = ['spring-boot:run', `-Dspring-boot.run.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${portLocal}"`]
|
|
54
|
+
console.log(`Starting '${cmd} ${args.join(' ')}'\n`)
|
|
55
|
+
spawn(cmd, args, { stdio: 'inherit' })
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const script = process.argv[1] // `.../cds` or `.../cds-tsx`
|
|
59
|
+
console.log(`Starting '${cds.utils.path.basename(script)} watch --debug'`)
|
|
60
|
+
fork(script, ['watch', '--debug']).on('error', e => { throw 'Failed to start debug process:' + e.message })
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else if (cds.cli.options.k8s) { // Kyma/Kubernetes
|
|
42
64
|
// to be implemented
|
|
43
|
-
} else { // Cloud Foundry
|
|
44
|
-
const script = `ps aux | grep '[n]ode' | awk '{print \\$2}' | head -n 1`
|
|
45
|
-
const pid = execSync(`cf ssh ${appName} -c "${script}"`, { encoding: 'utf-8', shell: true }).trim()
|
|
46
|
-
if (!pid) throw `Node.js process for app '${appName}' not found`
|
|
47
|
-
execSync(`cf ssh ${appName} -c "kill -usr1 ${pid}"`, { stdio: 'inherit' })
|
|
48
|
-
console.log(`Opening SSH tunnel for CF app '${appName}'`)
|
|
49
|
-
spawn('cf', ['ssh', '-N', '-L', `${port}:${host}:${port}`, appName], { stdio: 'inherit' })
|
|
50
65
|
}
|
|
66
|
+
else { // Cloud Foundry
|
|
67
|
+
const [pid, kind] = processInfo(appName)
|
|
68
|
+
console.log(`Found process of type ${kind}, ID: ${pid}`)
|
|
51
69
|
|
|
52
|
-
|
|
53
|
-
|
|
70
|
+
if (kind === 'node') {
|
|
71
|
+
enableNodeDebugging(pid, appName)
|
|
72
|
+
const portLocal = openTunnel(9229)
|
|
73
|
+
openDevTools(portLocal)
|
|
74
|
+
}
|
|
75
|
+
else if (kind === 'java') {
|
|
76
|
+
const portRemote = findJavaDebugPort(pid, appName)
|
|
77
|
+
const portLocal = openTunnel(portRemote)
|
|
78
|
+
printHints(portLocal)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function enableNodeDebugging(pid, appName) {
|
|
83
|
+
return _execSync(`cf ssh ${appName} -c "kill -usr1 ${pid}"`, { stdio: 'inherit' })
|
|
84
|
+
}
|
|
54
85
|
|
|
55
|
-
|
|
86
|
+
function findJavaDebugPort(pid, appName) {
|
|
87
|
+
assertSapMachine(appName)
|
|
88
|
+
const cmdLine = _execSync(`cf ssh ${appName} -c "~/app/META-INF/.sap_java_buildpack/sap_machine_jre/bin/jcmd ${pid} VM.command_line"`)
|
|
89
|
+
const address = cmdLine.match(/agentlib:jdwp=.*?address=.*?(\d+)/i)
|
|
90
|
+
if (address) {
|
|
91
|
+
console.log(`Found debug port ${address[1]}`)
|
|
92
|
+
return address[1]
|
|
93
|
+
}
|
|
94
|
+
throw `Failed to find debug port. JVM command line: ${cmdLine}`
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function assertSapMachine(appName) {
|
|
98
|
+
try {
|
|
99
|
+
_execSync(`cf ssh ${appName} -c "ls ~/app/META-INF/.sap_java_buildpack/sap_machine_jre/bin/jcmd"`)
|
|
100
|
+
} catch (err) {
|
|
101
|
+
const message = err.message || err
|
|
102
|
+
if (message.match(/cannot access.*jcmd/i)) {
|
|
103
|
+
throw `Debugging is only supported for apps running with SapMachine.`
|
|
104
|
+
+ `\n\nTo set it, add the following environment variable to your _mta.yaml_ or _manifest.yml_:\n\n`
|
|
105
|
+
+ ` JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SapMachine']"`
|
|
106
|
+
+ `\n\nSee https://help.sap.com/docs/btp/sap-business-technology-platform/sapmachine for more.\n`
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function openTunnel(portRemote) {
|
|
112
|
+
const portLocal = port || portRemote
|
|
113
|
+
console.log(`\nOpening SSH tunnel on ${portRemote}:${host}:${portLocal}`)
|
|
114
|
+
spawn('cf', ['ssh', '-N', '-L', `${portRemote}:${host}:${portLocal}`, appName], { stdio: 'inherit' })
|
|
115
|
+
return portLocal
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function processInfo(appName) {
|
|
119
|
+
const pidOf = exe => _execSyncSafe(`cf ssh ${appName} -c "pidof ${exe}"`)
|
|
120
|
+
const exeTypes = ['node', 'java']
|
|
121
|
+
for (const exe of exeTypes) {
|
|
122
|
+
const pid = pidOf(exe)
|
|
123
|
+
if (pid) return [pid, exe]
|
|
124
|
+
}
|
|
125
|
+
throw `No ${exeTypes.join(' or ')} process found for app '${appName}'`
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function openDevTools(port) {
|
|
56
129
|
attempts++
|
|
130
|
+
const ide = vscode ? 'vscode' : 'chrome'
|
|
57
131
|
try {
|
|
58
132
|
switch (ide) {
|
|
59
133
|
case 'chrome': {
|
|
@@ -78,13 +152,35 @@ async function debug() {
|
|
|
78
152
|
// to be implemented
|
|
79
153
|
}
|
|
80
154
|
}
|
|
155
|
+
printHints(port)
|
|
81
156
|
} catch (err) {
|
|
82
157
|
if (attempts < maxAttempts) {
|
|
83
|
-
setTimeout(openDevTools, 1000) // connection fails sometimes, retry
|
|
158
|
+
setTimeout(() => openDevTools(port), 1000).unref() // connection fails sometimes, retry
|
|
84
159
|
} else {
|
|
85
160
|
throw `Failed to connect to debugger after ${maxAttempts} attempts: ${err}`
|
|
86
161
|
}
|
|
87
162
|
}
|
|
88
163
|
}
|
|
89
|
-
|
|
164
|
+
|
|
165
|
+
function printHints(portLocal) {
|
|
166
|
+
console.log()
|
|
167
|
+
console.log(`> Now attach a debugger to port ${portLocal}.`)
|
|
168
|
+
console.log('> Keep this terminal open while debugging.')
|
|
169
|
+
console.log('> See https://cap.cloud.sap/docs/tools/cds-cli#cds-debug for more.')
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function _execSyncSafe(...args) {
|
|
173
|
+
try {
|
|
174
|
+
return _execSync(...args)
|
|
175
|
+
} catch (_) {/* ignore */ }
|
|
176
|
+
}
|
|
177
|
+
function _execSync(cmd, options={ encoding: 'utf-8', shell: true }) {
|
|
178
|
+
try {
|
|
179
|
+
return execSync(cmd, options)?.trim()
|
|
180
|
+
} catch (err) {
|
|
181
|
+
if (DEBUG) throw err
|
|
182
|
+
throw err.message
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
90
186
|
}
|
package/bin/deploy/index.js
CHANGED
|
@@ -148,6 +148,13 @@ async function deploy(_model, options) { // NOSONAR
|
|
|
148
148
|
options.schema_log = []
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
const isVersionLess8 = Number(cds.version.split('.')[0]) < 8
|
|
152
|
+
const localizedViewsSetting = cds.env?.sql?.transitive_localized_views
|
|
153
|
+
if (isVersionLess8 && !localizedViewsSetting ) {
|
|
154
|
+
cds.env.sql ??= {}
|
|
155
|
+
cds.env.sql.transitive_localized_views = true
|
|
156
|
+
console.warn(`transitive_localized_views = false requires @sap/cds >= 8.0.0, current version is ${cds.version}. transitive_localized_views has been set to true for this run. Will continue accordingly.`)
|
|
157
|
+
}
|
|
151
158
|
await deployer.deploy(_model, _db, options)
|
|
152
159
|
const log = this.log || _log
|
|
153
160
|
if (options.messages.length) log (options.messages, options)
|
package/bin/import.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module.exports = Object.assign(_import, {
|
|
2
2
|
_name: 'import',
|
|
3
|
-
options:
|
|
4
|
-
shortcuts: ['-o',
|
|
5
|
-
flags: ['--dry', '--force', '--no-copy', '--no-save', '--keep-namespace'
|
|
3
|
+
options: ['--for', '--out', '--as', '--name', '--include-namespaces', '--dependencies', '--from', '--config', '--destination', '--group'],
|
|
4
|
+
shortcuts: ['-4', '-o', '-as', '-n', '-ns', '-d', undefined, '-c', undefined, undefined, '-', '-f'],
|
|
5
|
+
flags: ['--dry', '--force', '--no-copy', '--no-save', '--keep-namespace'],
|
|
6
6
|
help: `
|
|
7
7
|
# SYNOPSIS
|
|
8
8
|
|
|
@@ -26,8 +26,9 @@ module.exports = Object.assign(_import, {
|
|
|
26
26
|
*--no-save*
|
|
27
27
|
Skips updating ./package.json.
|
|
28
28
|
|
|
29
|
-
*-o | --out* <filename>
|
|
29
|
+
*-o | --out* <filename/dirname>
|
|
30
30
|
Skips copying to ./srv/external and writes to the specified location.
|
|
31
|
+
Dirname is only applicable for importing odata-V4 file with dependencies.
|
|
31
32
|
|
|
32
33
|
*- | --dry*
|
|
33
34
|
Writes the converted csn to stdout only.
|
|
@@ -44,12 +45,12 @@ module.exports = Object.assign(_import, {
|
|
|
44
45
|
Imports the model from the one of the given options "edmx", "openapi" or
|
|
45
46
|
"asyncapi".
|
|
46
47
|
|
|
47
|
-
*-c | --config* <JSON
|
|
48
|
-
Adds the provided JSON
|
|
48
|
+
*-c | --config* <JSON string | comma-separated key-value pairs>
|
|
49
|
+
Adds the provided JSON or key-value pairs to the configuration.
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
*-4 | --for* <profile>
|
|
52
|
+
|
|
53
|
+
Write configuration data for the given profile.
|
|
53
54
|
|
|
54
55
|
*--destination*
|
|
55
56
|
Destination name under which the remote service can be reached.
|
|
@@ -66,6 +67,13 @@ module.exports = Object.assign(_import, {
|
|
|
66
67
|
For OData V2 attributes with the namespace "sap" & "m" are captured by
|
|
67
68
|
default.
|
|
68
69
|
|
|
70
|
+
*-d | --dependencies* <comma-separated list of dependencies>
|
|
71
|
+
Imports the given list of dependencies along with the main file. Valid for OData V4 only.
|
|
72
|
+
The dependencies are written to the given dirname(-o option) or ./srv/external.
|
|
73
|
+
If the cds files of dependencies are already present in the destination, it will be skipped
|
|
74
|
+
if -f option is not given.
|
|
75
|
+
NOTE: The dependencies must not have any dependency.
|
|
76
|
+
|
|
69
77
|
*Below options are valid for RFC only*
|
|
70
78
|
|
|
71
79
|
*-n | --name*
|
|
@@ -83,51 +91,68 @@ module.exports = Object.assign(_import, {
|
|
|
83
91
|
cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --from edmx --as cds
|
|
84
92
|
cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --include-namespaces "sap,c4c"
|
|
85
93
|
cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --include-namespaces "\x2A"
|
|
94
|
+
cds import ~/Downloads/sap.graph.edmx -d ./sap.c4c.edmx,./sap.s4.edmx --as cds -o ./graph
|
|
86
95
|
cds import ~/Downloads/Petstore_OpenAPI.json
|
|
87
96
|
cds import ~/Downloads/Petstore_OpenAPI.json --from openapi
|
|
88
97
|
cds import ~/Downloads/BookStore_AsyncAPI.json
|
|
89
98
|
cds import ~/Downloads/BookStore_AsyncAPI.json --from asyncapi
|
|
90
99
|
cds import ~/Downloads/API_BUSINESS_PARTNER.edmx -c "{\\"[production]\\":{\\"credentials\\":{\\"destination\\":\\"UI3_noauth\\",\\"path\\":\\"/sap/cap/odata\\"}}}"
|
|
100
|
+
cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --for sandbox -c "destination.properties.url=https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap"
|
|
101
|
+
cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --for production -c "http.suffix=/sap/opu/odata/sap,http.csrf.enabled=true"
|
|
91
102
|
|
|
92
103
|
`})
|
|
93
|
-
const messages = require('../lib/import/message').getMessages();
|
|
94
|
-
const common = require('../lib/import/common');
|
|
95
|
-
const cdsImport = require('../lib/index');
|
|
96
104
|
|
|
97
105
|
async function _import(args, options = {}) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
//
|
|
103
|
-
|
|
106
|
+
const messages = require('../lib/import/message').getMessages();
|
|
107
|
+
const common = require('../lib/import/common');
|
|
108
|
+
const cds = require('../lib/index');
|
|
109
|
+
|
|
110
|
+
// check if dependencies are provided and import them first
|
|
111
|
+
if (options.dependencies) {
|
|
112
|
+
const dependencies = options.dependencies.split(',');
|
|
113
|
+
delete options.dependencies;
|
|
114
|
+
for (let dependency of dependencies) {
|
|
115
|
+
const o = structuredClone(options);
|
|
116
|
+
o.isDependency = true;
|
|
117
|
+
if (dependency) await _import(dependency, o);
|
|
118
|
+
}
|
|
119
|
+
options.isDependent = true;
|
|
120
|
+
}
|
|
104
121
|
|
|
105
|
-
const cds = require('../lib/cds')
|
|
106
122
|
await cds.plugins
|
|
123
|
+
const cwd = process.cwd();
|
|
107
124
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
125
|
+
// process options
|
|
126
|
+
const apiOptions = {};
|
|
127
|
+
await common.processOptions(options, apiOptions);
|
|
128
|
+
|
|
129
|
+
const file = Array.isArray(args) ? args[0] : args
|
|
130
|
+
let input = file
|
|
131
|
+
if (!options.name) { // if no --name is given, use the positional file argument
|
|
112
132
|
if (!file) return this.help('import')
|
|
113
133
|
input = await common.preProcess(file, options, cwd);
|
|
114
134
|
}
|
|
115
135
|
|
|
116
|
-
|
|
117
|
-
|
|
136
|
+
const fileType = await common.identifyFile(input);
|
|
137
|
+
if ((options.isDependency || options.isDependent)
|
|
138
|
+
&& fileType !== 'edmx') {
|
|
139
|
+
throw messages.DEPENDENCY_NOT_SUPPORTED;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let csn
|
|
118
143
|
if (options.from) {
|
|
119
|
-
if (!
|
|
144
|
+
if (!cds.import.from[options.from]) {
|
|
120
145
|
// the required plugin might not be installed, e.g. rfc importer
|
|
121
146
|
throw messages.UNSUPPORTED_FROM_OPTION;
|
|
122
147
|
}
|
|
123
|
-
csn = await
|
|
148
|
+
csn = await cds.import.from[options.from](input, apiOptions);
|
|
124
149
|
} else {
|
|
125
|
-
csn = await
|
|
150
|
+
csn = await cds.import(input, apiOptions);
|
|
126
151
|
}
|
|
127
152
|
|
|
128
153
|
// reads the file version
|
|
129
154
|
options.inputFileKind = apiOptions.odataVersion ? apiOptions.odataVersion : apiOptions.inputFileKind;
|
|
130
155
|
|
|
131
156
|
// postprocess
|
|
132
|
-
return
|
|
157
|
+
return common.postProcess(apiOptions.file ?? file, options, csn, cwd);
|
|
133
158
|
}
|
package/bin/repl.js
CHANGED
|
@@ -83,7 +83,7 @@ async function repl (_, options={}) {
|
|
|
83
83
|
const fs = require('fs')
|
|
84
84
|
fs.readFile(history, 'utf-8', (e, txt) => e || Object.assign(repl.history, txt.split('\n')))
|
|
85
85
|
repl.on('exit', () => fs.writeFile(history, repl.history.join('\n'), () => {}))
|
|
86
|
-
|
|
86
|
+
repl.on('exit', cds.shutdown)
|
|
87
87
|
process.on('uncaughtException', console.error)
|
|
88
88
|
process.on('unhandledRejection', console.error)
|
|
89
89
|
|
|
@@ -108,7 +108,7 @@ async function repl (_, options={}) {
|
|
|
108
108
|
console.log (`}`)
|
|
109
109
|
console.log()
|
|
110
110
|
}
|
|
111
|
-
console.log('Simply type e.g.', GREEN+ Object.keys(context).at(-1) +RESET, 'in the prompt to use the respective objects.')
|
|
111
|
+
console.log('Simply type e.g.', GREEN+ Object.keys(repl.context).at(-1) +RESET, 'in the prompt to use the respective objects.')
|
|
112
112
|
console.log()
|
|
113
113
|
repl.displayPrompt()
|
|
114
114
|
}
|
package/bin/util/fuzzySearch.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
+
const cache = new Map();
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Levenshtein distance algorithm using recursive calls and cache
|
|
3
5
|
*
|
|
4
|
-
* @param input search the list for a best match for this string
|
|
5
|
-
* @param list a list of strings to match input against
|
|
6
|
-
* @param log logging method to use, might be null if no logging is wanted
|
|
7
|
-
* @
|
|
6
|
+
* @param {string} input - search the list for a best match for this string
|
|
7
|
+
* @param {string[]} list - a list of strings to match input against
|
|
8
|
+
* @param {null | (s:string) => unknown} log logging method to use, might be null if no logging is wanted
|
|
9
|
+
* @param {{maxListLength?: number, maxInputLength?: number}} [options] - optional parameters to control the search
|
|
10
|
+
* @returns {string[]} array with best matches, is never null but might be empty in case no search was possible
|
|
8
11
|
*/
|
|
12
|
+
module.exports = (input, list, log, options = {}) => {
|
|
13
|
+
const { maxListLength, maxInputLength } = {...{ maxListLength: 50, maxInputLength: 50 }, ...options};
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
const cache = new Map();
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
module.exports = (input, list, log) => {
|
|
15
15
|
let minDistWords = [];
|
|
16
16
|
|
|
17
|
-
if (input.length >
|
|
17
|
+
if (input.length > maxInputLength || list.length > maxListLength) {
|
|
18
18
|
return minDistWords;
|
|
19
19
|
}
|
|
20
20
|
|
package/bin/watch.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const watchOnlyOptions = ['--ext', '--livereload', '--open', '--debug', '--inspect', '--inspect-brk']
|
|
1
|
+
const watchOnlyOptions = ['--ext', '--livereload', '--open', '--debug', '--inspect', '--inspect-brk', '--include', '--exclude']
|
|
2
|
+
|
|
2
3
|
module.exports = Object.assign ( watch, {
|
|
3
4
|
flags: [ '--in-memory', '--in-memory?', '--with-mocks' ],
|
|
4
5
|
options: [ '--port', ...watchOnlyOptions ],
|
|
@@ -27,6 +28,14 @@ module.exports = Object.assign ( watch, {
|
|
|
27
28
|
Specify file extensions to watch for in a comma-separated list.
|
|
28
29
|
*Example:* cds w --ext cds,json,js.
|
|
29
30
|
|
|
31
|
+
*--include* <paths,...>
|
|
32
|
+
|
|
33
|
+
Comma-separated list of additional paths to watch.
|
|
34
|
+
|
|
35
|
+
*--exclude* <paths,...>
|
|
36
|
+
|
|
37
|
+
Comma-separated list of additional paths to ignore.
|
|
38
|
+
|
|
30
39
|
*--livereload* <port | false>
|
|
31
40
|
|
|
32
41
|
Specify the port for the livereload server. Defaults to '35729'.
|
|
@@ -65,22 +74,33 @@ const {codes} = require('../lib/util/term'), t = codes
|
|
|
65
74
|
const fs = require ('fs')
|
|
66
75
|
|
|
67
76
|
const extDefaults = 'cds,csn,csv,ts,mjs,cjs,js,json,properties,edmx,xml,env'
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
77
|
+
|
|
78
|
+
const ignoreDefaults = [
|
|
79
|
+
/\.git/,
|
|
80
|
+
/node_modules/,
|
|
81
|
+
/_out/,
|
|
82
|
+
/@types/,
|
|
83
|
+
/@cds-models/,
|
|
84
|
+
new RegExp(`app${sep}.+?${sep}webapp${sep}`),
|
|
85
|
+
new RegExp(`app${sep}.+?${sep}dist${sep}`),
|
|
86
|
+
new RegExp(`app${sep}.+?${sep}target${sep}`),
|
|
87
|
+
new RegExp(`app${sep}.+?${sep}tsconfig\\.json$`),
|
|
88
|
+
new RegExp(`app${sep}.+?${sep}.*\\.tsbuildinfo$`),
|
|
89
|
+
/package-lock\.json$/,
|
|
90
|
+
new RegExp(`\\${sep}gen\\${sep}`)
|
|
91
|
+
]
|
|
78
92
|
|
|
79
93
|
async function watch ([cwd], {
|
|
80
94
|
args = ['serve', 'all'],
|
|
81
95
|
ext = extDefaults,
|
|
96
|
+
include = cds.env.watch?.include ?? [],
|
|
97
|
+
exclude = cds.env.watch?.exclude ?? [],
|
|
82
98
|
...options
|
|
83
99
|
}={}) {
|
|
100
|
+
const paths4 = p => typeof p === 'string' ? p.split(',').map(p => p.trim()) : (p || [])
|
|
101
|
+
const included = paths4(include), excluded = paths4(exclude)
|
|
102
|
+
const nonexisting = included.filter(p => !fs.existsSync(p))
|
|
103
|
+
if (nonexisting.length > 0) throw `${nonexisting.length > 1 ? 'Paths do' : 'Path does'} not exist: ${nonexisting.join(', ')}`
|
|
84
104
|
if (cwd && !cds.utils.exists(cwd)) try { // try module name like `@capire/bookshop`
|
|
85
105
|
cwd = require.resolve(cwd+'/package.json', {paths:[ process.cwd() ]}).slice(0,-13)
|
|
86
106
|
} catch (err) {
|
|
@@ -133,9 +153,19 @@ async function watch ([cwd], {
|
|
|
133
153
|
}
|
|
134
154
|
log ()
|
|
135
155
|
log (`${t.bold}cds ${args.join(' ')}`)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
156
|
+
const escapedRegex = s => s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
157
|
+
const resolved = p => resolve(_cwd, p)
|
|
158
|
+
const excludedPaths = excluded.map(resolved).map(escapedRegex)
|
|
159
|
+
const ignore = excluded.length
|
|
160
|
+
? new RegExp(ignoreDefaults.map(d => d.source).concat(excludedPaths).join('|'))
|
|
161
|
+
: new RegExp(ignoreDefaults.map(d => d.source).join('|'))
|
|
162
|
+
const watched = [ _cwd, ...included.map(resolved) ]
|
|
163
|
+
if (DEBUG) {
|
|
164
|
+
console.log(`\nwatching (pid ${process.pid})`, {
|
|
165
|
+
extensions:ext, roots:watched, ignoring: [...excludedPaths.map(s => new RegExp(s)), ...ignoreDefaults]
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
if (liveReload) console.log (`live reload enabled for browsers`)
|
|
139
169
|
|
|
140
170
|
const BindingManager = require('../lib/bind/bindingManager')
|
|
141
171
|
const bindingManager = new BindingManager({cwd})
|
|
@@ -144,7 +174,7 @@ async function watch ([cwd], {
|
|
|
144
174
|
|
|
145
175
|
const nodemon = require('../lib/watch/node-watch')
|
|
146
176
|
const watcher = nodemon ({
|
|
147
|
-
script: resolve(__dirname,'../lib/watch/watched'), cwd, env, ext, ignore,
|
|
177
|
+
script: resolve(__dirname,'../lib/watch/watched'), cwd, env, ext, ignore, watched,
|
|
148
178
|
delay,
|
|
149
179
|
options
|
|
150
180
|
}).on('restart', (files)=>{
|
|
@@ -216,4 +246,4 @@ function paths (dir) {
|
|
|
216
246
|
function installed(id, ...paths) {
|
|
217
247
|
try { return require.resolve (id, { paths }) }
|
|
218
248
|
catch(e) { if (e.code !== 'MODULE_NOT_FOUND') throw e }
|
|
219
|
-
}
|
|
249
|
+
}
|
|
@@ -121,11 +121,14 @@ class BuildTaskProviderFactory {
|
|
|
121
121
|
// located under 'C:\SAPDevelop\git\...' using a sym-link from '%USERHOME%\git' to 'C:\SAPDevelop\git'.
|
|
122
122
|
// see cap/issues/#8694
|
|
123
123
|
resolvedTask.src = path.resolve(cds.root, task.src)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
// if --ws is passed, the db/ folder is not required, as the task will gather the model from the workspaces
|
|
125
|
+
if (!this.options.ws) {
|
|
126
|
+
try {
|
|
127
|
+
//validate source path
|
|
128
|
+
fs.realpathSync(resolvedTask.src)
|
|
129
|
+
} catch (e) {
|
|
130
|
+
throw new BuildError(`The 'src' folder '${path.resolve(cds.root, task.src)}' for build task '${resolvedTask.for}' does not exist`)
|
|
131
|
+
}
|
|
129
132
|
}
|
|
130
133
|
resolvedTask.dest = path.resolve(cds.root, cds.env.build.target, task.dest || task.src)
|
|
131
134
|
resolvedTask.options = task.options || {}
|
|
@@ -16,9 +16,8 @@ spec:
|
|
|
16
16
|
template:
|
|
17
17
|
metadata:
|
|
18
18
|
labels: {{- include "content-deployment.internal.labels" . | nindent 8 }}
|
|
19
|
-
annotations:
|
|
20
|
-
container.apparmor.security.beta.kubernetes.io/{{ include "content-deployment.internal.name" . }}: runtime/default
|
|
21
19
|
{{- if or .Values.annotations.job }}
|
|
20
|
+
annotations:
|
|
22
21
|
{{- tpl (toYaml .Values.annotations.job) $ | nindent 8 }}
|
|
23
22
|
{{- end }}
|
|
24
23
|
spec:
|
|
@@ -65,6 +64,8 @@ spec:
|
|
|
65
64
|
runAsUser: {{ .Values.runAsUser }}
|
|
66
65
|
{{- end }}
|
|
67
66
|
readOnlyRootFilesystem: false
|
|
67
|
+
appArmorProfile:
|
|
68
|
+
type: RuntimeDefault
|
|
68
69
|
volumeMounts:
|
|
69
70
|
- mountPath: /tmp
|
|
70
71
|
name: tmp
|
|
@@ -208,11 +208,11 @@ If release name contains chart name it will be used as service instance name.
|
|
|
208
208
|
{{ .checkName }}:
|
|
209
209
|
{{- if .checkValues.path }}
|
|
210
210
|
httpGet:
|
|
211
|
-
path: {{ .checkValues.path }}
|
|
212
|
-
port:
|
|
211
|
+
path: {{ tpl .checkValues.path .context }}
|
|
212
|
+
port: {{ .values.port | default .context.Values.port }}
|
|
213
213
|
{{- else }}
|
|
214
214
|
tcpSocket:
|
|
215
|
-
port: {{ .context.Values.port
|
|
215
|
+
port: {{ .values.port | default .context.Values.port}}
|
|
216
216
|
{{- end }}
|
|
217
217
|
{{- if eq .checkName "startupProbe" }}
|
|
218
218
|
periodSeconds: 2
|
|
@@ -20,7 +20,7 @@ spec:
|
|
|
20
20
|
name: {{ include "web-application.fullname" . }}
|
|
21
21
|
port: {{ .Values.port }}
|
|
22
22
|
rules:
|
|
23
|
-
{{- toYaml .Values.expose.rules | nindent 4 }}
|
|
23
|
+
{{- tpl (toYaml .Values.expose.rules) $ | nindent 4 }}
|
|
24
24
|
{{- if .Values.expose.corsPolicy }}
|
|
25
25
|
corsPolicy:
|
|
26
26
|
{{- toYaml .Values.expose.corsPolicy | nindent 4 }}
|