@sap/cds-dk 8.6.0 → 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.
Files changed (55) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/bin/cds.js +1 -1
  3. package/bin/debug.js +122 -26
  4. package/bin/deploy/index.js +7 -0
  5. package/bin/import.js +54 -29
  6. package/bin/repl.js +2 -2
  7. package/bin/util/fuzzySearch.js +10 -10
  8. package/bin/watch.js +46 -16
  9. package/lib/build/buildTaskProviderFactory.js +8 -5
  10. package/lib/build/plugins/helm/files/subcharts/content-deployment/Chart.yaml +1 -1
  11. package/lib/build/plugins/helm/files/subcharts/content-deployment/templates/job.yaml +3 -2
  12. package/lib/build/plugins/helm/files/subcharts/content-deployment/values.yaml +1 -1
  13. package/lib/build/plugins/helm/files/subcharts/web-application/Chart.yaml +1 -1
  14. package/lib/build/plugins/helm/files/subcharts/web-application/templates/_helpers.tpl +3 -3
  15. package/lib/build/plugins/helm/files/subcharts/web-application/templates/api-rule.yaml +1 -1
  16. package/lib/build/plugins/helm/files/subcharts/web-application/templates/deployment.yaml +13 -5
  17. package/lib/build/plugins/helm/files/subcharts/web-application/templates/service-binding.yaml +1 -0
  18. package/lib/build/plugins/helm/files/subcharts/web-application/values.schema.json +28 -15
  19. package/lib/build/plugins/helm/files/subcharts/web-application/values.yaml +22 -1
  20. package/lib/build/util.js +3 -1
  21. package/lib/import/common.js +174 -44
  22. package/lib/import/importapi.js +1 -1
  23. package/lib/import/message.js +1 -1
  24. package/lib/import/odata/ParserContext.js +46 -0
  25. package/lib/import/odata/index.js +20 -11
  26. package/lib/import/odata/v4parser.js +25 -51
  27. package/lib/init/add.js +0 -2
  28. package/lib/init/constants.js +3 -3
  29. package/lib/init/index.js +1 -1
  30. package/lib/init/merge.js +67 -66
  31. package/lib/init/mvn.js +16 -12
  32. package/lib/init/projectReader.js +2 -2
  33. package/lib/init/template/ams/files/package.json.hbs +1 -1
  34. package/lib/init/template/approuter/files/mta.yaml.hbs +2 -4
  35. package/lib/init/template/hana/index.js +12 -8
  36. package/lib/init/template/ias/files/mta.yaml.hbs +15 -0
  37. package/lib/init/template/ias/index.js +22 -5
  38. package/lib/init/template/mta/files/mta.yaml.hbs +3 -13
  39. package/lib/init/template/multitenancy/files/mta.yaml.hbs +1 -0
  40. package/lib/init/template/multitenancy/index.js +5 -0
  41. package/lib/init/template/nodejs/files/package.json.hbs +1 -1
  42. package/lib/init/template/portal/files/portal-site/i18n/catalog.properties +1 -1
  43. package/lib/init/template/portal/files/portal-site/i18n/catalog_de.properties +1 -1
  44. package/lib/init/template/portal/files/portal-site/i18n/group.properties +1 -1
  45. package/lib/init/template/portal/files/portal-site/i18n/group_de.properties +1 -1
  46. package/lib/init/template/sample/files/typescript/admin-service.ts.hbs +16 -0
  47. package/lib/init/template/sample/files/typescript/cat-service.ts.hbs +38 -0
  48. package/lib/init/template/sample/index.js +16 -12
  49. package/lib/init/template/typescript/files/package.json +1 -1
  50. package/lib/lint/io.js +6 -16
  51. package/lib/watch/node-watch.js +3 -3
  52. package/npm-shrinkwrap.json +49 -33
  53. package/package.json +1 -1
  54. /package/lib/init/template/sample/files/{nodejs → javascript}/admin-service.js.hbs +0 -0
  55. /package/lib/init/template/sample/files/{nodejs → javascript}/cat-service.js.hbs +0 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,37 @@ 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
+
35
+ ## Version 8.6.1 - 2024-12-18
36
+
37
+ ### Fixed
38
+
39
+ - `cds add ams` now creates correct dependencies for Java projects.
40
+
10
41
  ## Version 8.6.0 - 2024-12-17
11
42
 
12
43
  ### Added
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
- Debugs a CAP-based application in the Chrome Developer Tools.
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 Cloud Foundry space.
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 with 'cds watch --debug'.
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
- *--host* the debug host (default: '127.0.0.1')
23
+ *-h* | *--host*
19
24
 
20
- *--port* the debug port (default: 9229)
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 = 9229, host = '127.0.0.1', vscode } = cds.cli.options
35
- const ide = vscode ? 'vscode' : 'chrome'
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
- const script = process.argv[1] // `.../cds` or `.../cds-tsx`
39
- console.log(`Starting '${cds.utils.path.basename(script)} watch --debug'`)
40
- fork(script, ['watch', '--debug']).on('error', e => { throw 'Failed to start debug process:' + e.message })
41
- } else if (cds.cli.options.k8s) { // Kyma/Kubernetes
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
- const maxAttempts = 15
53
- let attempts = 0
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
- const openDevTools = async () => {
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
- openDevTools()
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
  }
@@ -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: ['--out', '--as', '--name', '--include-namespaces', '--from', '--config', '--destination', '--group'],
4
- shortcuts: ['-o', '-as', '-n', '-ns', undefined, '-c', undefined, undefined, '-', '-f'],
5
- flags: ['--dry', '--force', '--no-copy', '--no-save', '--keep-namespace', '--beta'],
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 Object>
48
- Adds the provided JSON Object as custom configuration data to the package.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
- *--beta*
51
- Enables beta mode in cds import.
52
- - Populates default value for optional action and function parameters in the CSN or CDS.
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
- let csn = '';
99
- let apiOptions = {};
100
- // preprocess
101
- let cwd = process.cwd();
102
- // process options
103
- await common.processOptions(options, apiOptions);
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
- let file
109
- let input
110
- if (!options.name) {
111
- file = Array.isArray(args) ? args[0] : args
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
- // process - csn generation
117
- // if --from option is given, call api directly accordingly
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 (!cdsImport.import.from[options.from]) {
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 cdsImport.import.from[options.from](input, apiOptions);
148
+ csn = await cds.import.from[options.from](input, apiOptions);
124
149
  } else {
125
- csn = await cdsImport.import(input, apiOptions);
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 await common.postProcess(apiOptions.file ?? file, options, csn, cwd);
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
  }
@@ -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
- * @returns array with best matches, is never null but might be empty in case no search was possible
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 > 50 || list.length > 50) {
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
- const ignore = RegExp(
69
- `(\\.git|node_modules|_out|@types|@cds-models)\\${sep}` +
70
- `|app(\\${sep}.+)?\\${sep}(` +
71
- `(webapp|dist|target)\\${sep}|` +
72
- `tsconfig\\.json$|` +
73
- `.*\\.tsbuildinfo$` +
74
- ')' +
75
- `|package-lock\\.json$` +
76
- `|\\${sep}gen\\${sep}`
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
- DEBUG && log (process.pid, 'watching:', ext, '...')
137
- DEBUG && log ('ignoring:', ignore.source)
138
- if (liveReload) log (`live reload enabled for browsers`)
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
- try {
125
- //validate source path
126
- fs.realpathSync(resolvedTask.src)
127
- } catch (e) {
128
- throw new BuildError(`The 'src' folder '${path.resolve(cds.root, task.src)}' for build task '${resolvedTask.for}' does not exist`)
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 || {}
@@ -4,4 +4,4 @@ name: content-deployment
4
4
  sources:
5
5
  - https://github.tools.sap/unified-runtime/content-deployment
6
6
  type: application
7
- version: 1.7.0
7
+ version: 1.7.1
@@ -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
@@ -14,7 +14,7 @@ global:
14
14
  _internal:
15
15
  content-deployment:
16
16
  versions:
17
- 1.7.0: true
17
+ 1.7.1: true
18
18
  # Will be used instead of the `.Chart.Name`, e.g. when generating the Deployment name.
19
19
  # nameOverride: name
20
20
 
@@ -5,4 +5,4 @@ name: web-application
5
5
  sources:
6
6
  - https://github.tools.sap/unified-runtime/web-application
7
7
  type: application
8
- version: 1.20.0
8
+ version: 1.22.0
@@ -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: http
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 }}