@sap/cds 6.5.0 → 6.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/CHANGELOG.md +53 -2
  2. package/README.md +5 -0
  3. package/apis/services.d.ts +5 -0
  4. package/bin/build/buildTaskEngine.js +0 -2
  5. package/bin/build/buildTaskFactory.js +1 -1
  6. package/bin/build/buildTaskHandler.js +1 -1
  7. package/bin/build/provider/buildTaskProviderInternal.js +10 -6
  8. package/bin/build/provider/fiori/index.js +5 -10
  9. package/bin/build/provider/hana/2migration.js +11 -2
  10. package/bin/build/provider/hana/index.js +17 -14
  11. package/bin/build/provider/hana/template/.hdiconfig-hanacloud +137 -0
  12. package/bin/build/provider/mtx-extension/index.js +18 -1
  13. package/bin/build/provider/mtx-sidecar/index.js +1 -1
  14. package/bin/build/util.js +1 -1
  15. package/bin/cds.js +1 -5
  16. package/bin/deploy/to-hana/hana.js +10 -3
  17. package/bin/deploy/to-hana/hdiDeployUtil.js +24 -12
  18. package/bin/serve.js +32 -20
  19. package/lib/auth/jwt-auth.js +4 -4
  20. package/lib/compile/for/lean_drafts.js +55 -6
  21. package/lib/dbs/cds-deploy.js +6 -8
  22. package/lib/env/schemas/cds-rc.json +4 -0
  23. package/lib/index.js +4 -2
  24. package/lib/req/cds-context.js +3 -3
  25. package/lib/srv/bindings.js +1 -2
  26. package/lib/srv/cds-serve.js +2 -1
  27. package/lib/srv/middlewares/trace.js +31 -15
  28. package/lib/srv/protocols/odata-v2-proxy.js +8 -8
  29. package/lib/srv/srv-handlers.js +26 -7
  30. package/lib/srv/srv-methods.js +2 -2
  31. package/lib/srv/srv-models.js +4 -3
  32. package/lib/utils/cds-test.js +7 -5
  33. package/libx/_runtime/auth/strategies/ias-auth.js +1 -1
  34. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -2
  35. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +26 -1
  36. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +1 -0
  37. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +1 -1
  38. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +11 -2
  39. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/PrimitiveValueDecoder.js +8 -8
  40. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +1 -1
  41. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/validator/ValueValidator.js +14 -14
  42. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +7 -8
  43. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ResourceJsonSerializer.js +3 -0
  44. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/UriHelper.js +2 -1
  45. package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +3 -2
  46. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +7 -0
  47. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +0 -3
  48. package/libx/_runtime/cds-services/services/Service.js +8 -19
  49. package/libx/_runtime/cds-services/services/utils/columns.js +7 -4
  50. package/libx/_runtime/cds-services/util/assert.js +7 -1
  51. package/libx/_runtime/common/code-ext/WorkerReq.js +3 -1
  52. package/libx/_runtime/common/code-ext/execute.js +9 -2
  53. package/libx/_runtime/common/code-ext/handlers.js +2 -2
  54. package/libx/_runtime/common/code-ext/worker.js +9 -5
  55. package/libx/_runtime/common/code-ext/workerQueryExecutor.js +5 -2
  56. package/libx/_runtime/common/composition/data.js +5 -2
  57. package/libx/_runtime/common/composition/tree.js +2 -0
  58. package/libx/_runtime/common/generic/auth/restrict.js +1 -1
  59. package/libx/_runtime/common/generic/etag.js +22 -10
  60. package/libx/_runtime/common/generic/input.js +12 -14
  61. package/libx/_runtime/common/utils/cqn2cqn4sql.js +31 -11
  62. package/libx/_runtime/common/utils/path.js +0 -1
  63. package/libx/_runtime/common/utils/search2cqn4sql.js +4 -1
  64. package/libx/_runtime/common/utils/structured.js +1 -0
  65. package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +19 -13
  66. package/libx/_runtime/db/data-conversion/post-processing.js +1 -1
  67. package/libx/_runtime/db/expand/expandCQNToJoin.js +5 -3
  68. package/libx/_runtime/db/expand/rawToExpanded.js +3 -2
  69. package/libx/_runtime/db/generic/input.js +2 -2
  70. package/libx/_runtime/db/generic/integrity.js +1 -0
  71. package/libx/_runtime/db/generic/virtual.js +1 -0
  72. package/libx/_runtime/db/query/read.js +3 -2
  73. package/libx/_runtime/fiori/generic/activate.js +3 -1
  74. package/libx/_runtime/fiori/generic/before.js +1 -0
  75. package/libx/_runtime/fiori/generic/edit.js +6 -1
  76. package/libx/_runtime/fiori/generic/new.js +2 -0
  77. package/libx/_runtime/fiori/generic/patch.js +2 -0
  78. package/libx/_runtime/fiori/generic/prepare.js +2 -0
  79. package/libx/_runtime/fiori/generic/read.js +8 -2
  80. package/libx/_runtime/fiori/generic/readOverDraft.js +2 -0
  81. package/libx/_runtime/fiori/lean-draft.js +498 -245
  82. package/libx/_runtime/fiori/utils/delete.js +2 -0
  83. package/libx/_runtime/messaging/Outbox.js +1 -1
  84. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +1 -0
  85. package/libx/_runtime/messaging/enterprise-messaging.js +2 -6
  86. package/libx/_runtime/messaging/file-based.js +1 -2
  87. package/libx/_runtime/messaging/outbox/OutboxRunner.js +1 -1
  88. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  89. package/libx/_runtime/messaging/service.js +0 -1
  90. package/libx/_runtime/remote/Service.js +1 -0
  91. package/libx/_runtime/sqlite/convertDraftAdminPathExpression.js +19 -3
  92. package/libx/_runtime/sqlite/customBuilder/CustomExpressionBuilder.js +0 -18
  93. package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +0 -18
  94. package/libx/_runtime/sqlite/customBuilder/CustomSelectBuilder.js +0 -24
  95. package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +2 -1
  96. package/libx/_runtime/sqlite/customBuilder/index.js +47 -32
  97. package/libx/odata/afterburner.js +17 -5
  98. package/libx/odata/grammar.pegjs +3 -4
  99. package/libx/odata/index.js +5 -1
  100. package/libx/odata/parseToCqn.js +3 -3
  101. package/libx/odata/parser.js +1 -1
  102. package/libx/odata/utils.js +58 -1
  103. package/package.json +1 -1
  104. package/server.js +1 -1
  105. package/libx/_runtime/sqlite/customBuilder/CustomDeleteBuilder.js +0 -17
  106. package/libx/_runtime/sqlite/customBuilder/CustomReferenceBuilder.js +0 -11
  107. package/libx/_runtime/sqlite/customBuilder/CustomUpdateBuilder.js +0 -17
  108. /package/bin/build/provider/hana/template/{.hdiconfig → .hdiconfig-haas} +0 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,56 @@
4
4
  - The format is based on [Keep a Changelog](http://keepachangelog.com/).
5
5
  - This project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## Version 6.6.1 2023-03-09
8
+
9
+ ### Added
10
+
11
+ - `cds.xt.TENANT_UPDATED` event is emitted once a tenant was extended
12
+
13
+ ### Fixed
14
+
15
+ - `TypeError` when using the query API with an unknown target in x4 flavor
16
+ - The setting for `cds.requires['cds.xt.DeploymentService'].lazyT0` is now recognized in the VS Code schema validation.
17
+ - The HDI deployment `stdout` logs are now only visible for `DEBUG` level if triggered via `cds-mtxs`. They are also streamed to `logs/<tenant>.log` in case you need the full deployment output, even without `DEBUG` enabled.
18
+ - `.forUpdate` when used for etags
19
+ - Prevent `TypeError` if an existing draft does not have admin data
20
+ - Outbound-streaming error handling
21
+
22
+ ## Version 6.6.0 - 2023-02-27
23
+
24
+ ### Added
25
+
26
+ - Improved error handling for `cds build` if the SaaS base model is missing in an extension project.
27
+ - Support for reliable paging using `$skiptoken`. Can be activated via `cds.query.limit.reliablePaging = true`
28
+
29
+ ### Changed
30
+
31
+ - `cds.serve(ServiceName)` (and `cds serve -s ServiceName`) now exactly serve services with the given names. Previously, all services that ended with the given name were served as well, e.g. `MyServiceName` and `ServiceName`, which might be problematic for applications that bootstrap services one by one.
32
+ - Optimize `@cds.persistence.journal` filtering for `last-dev` CSN file.
33
+ - `process.exit()` is no longer called during server shutdown, so that other/custom exit handlers get a chance to execute.
34
+
35
+ ### Fixed
36
+
37
+ - `cds deploy --to hana` no longer calls `cds bind` when `VCAP_SERVICES` is provided, e.g via `default-env.json`.
38
+ - `$search` on an entity without String elements
39
+ - Only elements from type `cds.String` are searchable when combining `$apply` and `$search`
40
+ - Error message for missing database connection in draft case
41
+ - Extensibility with in-memory Sqlite
42
+ - OData adapter error messages
43
+ - Columns in navigation path are now added to the SELECT.columns in new parser
44
+ - Application service calls on draft enabled entities using aliases
45
+ - Custom mtxs build tasks now use the correct default `src` folder value.
46
+ - `cds build` adds a `.hdiconfig` file when creating HANA migration tables if none is existing.
47
+ - UPSERTs using reserved keywords
48
+ - Fix outbound-streaming error handling
49
+ - Rollback transaction if inbound streaming fails
50
+ - Custom database initialization in `db/init.js` now skips the `t0` tenant for multitenant apps.
51
+ - Concurrent etag calculation for UPDATE and DELETE
52
+ - Typings for `cds.delete()`
53
+ - CQN for `not` operator with OData functions
54
+ - Expand on composition of aspect for draft enabled entities
55
+ - Better error messages are provided for errors with HTTP status code `400`, `500` and `501`
56
+
7
57
  ## Version 6.5.0 - 2023-01-27
8
58
 
9
59
  ### Added
@@ -15,13 +65,13 @@
15
65
 
16
66
  - Successive calls to `SELECT.where()` wraps existing clause in brackets if it contains `or`. E.g.
17
67
  ```js
18
- SELECT.from `X` .where `x` .or `y` .where `z`
68
+ SELECT.from `X` .where `x` .or `y` .where `z`
19
69
  //> SELECT from X where (x or y) and z`
20
70
  ```
21
71
  - `cds build` for HANA now adds an `engines.node` version to the generated `db/package.json`. This will help in the future when runtime environments change their default to some version higher than the one supported by `@sap/hdi-deploy`.
22
72
  - `cds build` checks the consistency of built-in models for java projects. An error is logged if some model files could not successfully be resolved indicating that a required npm module might be missing.
23
73
  - Status code of draft actions are set in respective handler instead of protocol adapter
24
- - `cds deploy --dry` no longer loads the `sqlite3` module by mistake. This fixes a regression when building Java projects. As a side effect a file with the name `undefined` was created in the project root folder.
74
+ - `cds deploy --dry` no longer loads the `sqlite3` module by mistake. This fixes a regression when building Java projects. As a side effect a file with the name `undefined` was created in the project root folder.
25
75
  - Internal representation of pseudo roles `internal-user` and `system-user`
26
76
 
27
77
  ### Fixed
@@ -57,6 +107,7 @@
57
107
  - fix view resolving and managed data for UPSERT
58
108
  - `cds.linked` supports polymorphic self links like in: `action foo( self: [many] $self, ...)`
59
109
  - Error with `@odata.draft.enabled` and `@restrict`
110
+ - Skip mandatory check on navigation properties for write requests
60
111
 
61
112
  ## Version 6.4.0 - 2022-12-15
62
113
 
package/README.md CHANGED
@@ -4,5 +4,10 @@ The API package for the [SAP Cloud Application Programming Model (CAP)](https://
4
4
 
5
5
  See the [API documentation](https://cap.cloud.sap/docs/node.js/api) for more details.
6
6
 
7
+ ## How to Obtain Support**
8
+
9
+ In case you find a bug, please report an [incident](https://cap.cloud.sap/docs/resources/#reporting-incidents) on SAP Support Portal.
10
+
7
11
  ## License
12
+
8
13
  This package is provided under the terms of the [SAP Developer License Agreement](https://tools.hana.ondemand.com/developer-license-3.1.txt).
@@ -54,6 +54,11 @@ export class QueryAPI {
54
54
  (query: Query): Promise<ResultSet | any>
55
55
  (query: string, args?: any[] | object): Promise<ResultSet | any>
56
56
  }
57
+
58
+ /**
59
+ * @see [docs](https://cap.cloud.sap/docs/node.js/cds-facade?q=cds.delete)
60
+ */
61
+ delete<T>(entity: Definition | string, key?: any): DELETE<T>
57
62
 
58
63
  /**
59
64
  * @see [docs](https://cap.cloud.sap/docs/node.js/services#srv-run)
@@ -257,8 +257,6 @@ class BuildTaskEngine {
257
257
  const files = BuildTaskEngine._getBuildOutput(handlers, buildOptions)
258
258
  if (files.length > 0) {
259
259
  this.logger.log(`done > wrote output to:\n ${files.join("\n ")}\n`)
260
- } else {
261
- this.logger.log('done >')
262
260
  }
263
261
  }
264
262
 
@@ -56,7 +56,7 @@ class BuildTaskFactory {
56
56
 
57
57
  async _createTasks(providerFactory) {
58
58
  const buildOptions = providerFactory.buildOptions
59
- this.logger.log(`determining build tasks for project [${buildOptions.root}].`)
59
+ this.logger.debug(`determining build tasks for project [${buildOptions.root}].`)
60
60
 
61
61
  // clearing model cache (details https://github.tools.sap/cap/cds/pull/181) is no longer required
62
62
  // because of changes https://github.tools.sap/cap/cds/pull/1121
@@ -184,7 +184,7 @@ class BuildTaskHandler {
184
184
  async model() {
185
185
  const files = this._resolveModel()
186
186
  if (!files || files.length === 0) {
187
- this._logger.log("no CDS model found")
187
+ this._logger.log(`no CDS model found for [${this.task.for}] build task [${this.task.src}] - nothing to be done`)
188
188
  return null
189
189
  }
190
190
  this._logger._debug && this._logger.debug(`model: ${relativePaths(this._buildOptions.root, files).join(", ")}`)
@@ -63,7 +63,11 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
63
63
  break
64
64
  case BUILD_TASK_MTX_EXTENSION:
65
65
  case BUILD_TASK_MTX:
66
- task.src = task.src || "."
66
+ if (isStreamlinedMtx()) {
67
+ task.src = task.src || BuildTaskProviderInternal._normalizePath(cds.env.folders.srv)
68
+ } else {
69
+ task.src = task.src || "."
70
+ }
67
71
  break
68
72
  default:
69
73
  throw new Error(`Unknown build task '${task.use || task.for}'`)
@@ -84,13 +88,13 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
84
88
  if (Array.isArray(db) && db.length > 0) {
85
89
  db = BuildTaskProviderInternal._getModuleFolder(projectPath, db) || null
86
90
  if (!db && !addRequiredTasks) { // log once
87
- this.logger.log("No database module found")
91
+ this.logger.debug("No database module found")
88
92
  }
89
93
  }
90
94
  if (Array.isArray(srv) && srv.length > 0) {
91
95
  srv = BuildTaskProviderInternal._getModuleFolder(projectPath, srv) || null
92
96
  if (!srv && !addRequiredTasks) { // log once
93
- this.logger.log("No service module found")
97
+ this.logger.debug("No service module found")
94
98
  }
95
99
  }
96
100
  // create required build tasks
@@ -205,7 +209,7 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
205
209
 
206
210
  const sidecarPath = path.join(projectPath, MTX_SIDECAR_FOLDER)
207
211
  if (!fs.existsSync(sidecarPath)) {
208
- throw new BuildError("CDS build failed", `MTX sidecar directory '${sidecarPath}' not existing. Custom build task configuration necessary if the folder is named differently.`)
212
+ throw new BuildError(`MTX sidecar directory '${sidecarPath}' not existing. Custom build task configuration necessary if the folder is named differently.`)
209
213
  }
210
214
  const sidecarEnv = cds.env.for("cds", sidecarPath)
211
215
  if (sidecarEnv.requires["cds.xt.ModelProviderService"]?.kind === "in-sidecar") {
@@ -213,12 +217,12 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
213
217
  for: BUILD_TASK_MTX_SIDECAR
214
218
  }
215
219
  }
216
- throw new BuildError("CDS build failed", 'Invalid MTX sidecar configuration. Make sure to add required service "cds.xt.ModelProviderService": "in-sidecar".')
220
+ throw new BuildError("Invalid MTX sidecar configuration - \"cds.xt.ModelProviderService\": \"in-sidecar\" missing.")
217
221
  }
218
222
 
219
223
  if (cds.env.requires["cds.xt.ModelProviderService"]?.kind === "in-sidecar") {
220
224
  // cds build is executed in sidecar folder
221
- throw new BuildError("CDS build failed", "Invalid working directory. Make sure to execute 'cds build' in CAP project root directory.")
225
+ throw new BuildError("Invalid working directory. Make sure to execute 'cds build' in CAP project root directory.")
222
226
  }
223
227
 
224
228
  this.logger.debug("Nodejs Streamlined MTX app without sidecar")
@@ -62,10 +62,9 @@ class FioriAppModuleBuilder extends BuildTaskHandlerEdmx {
62
62
  }
63
63
 
64
64
  for (let [appFolder, appModelGroup] of appModelGroups.entries()) {
65
- this.logger.log(`building module [${appFolder}] using [${this.constructor.name}]`)
65
+ this.logger.debug(`building module [${appFolder}] using [${this.constructor.name}]`)
66
66
  const modelPaths = cds.resolve(Array.from(appModelGroup.values()), this.buildOptions)
67
67
  if (!modelPaths || modelPaths.length === 0) {
68
- this.logger.log(`no model found`)
69
68
  continue
70
69
  }
71
70
  this.logger._debug && this.logger.debug(`model: ${relativePaths(this.buildOptions.root, modelPaths).join(", ")}`)
@@ -89,19 +88,15 @@ class FioriAppModuleBuilder extends BuildTaskHandlerEdmx {
89
88
  /**
90
89
  * This version only creates a odata representation for the 'mainService' data source
91
90
  * as defined by the fiori wizard - everything else is currently not supported.
92
- * Therefore errors are only logged, the build does not fail in case a the service
91
+ * Therefore errors are only logged, the build does not fail in case a service
93
92
  * cannot be resolved based on the defined service URI
94
93
  */
95
94
  async build() {
96
- const { src, dest } = this.task
97
- const modelPaths = this.resolveModel()
98
- if (!modelPaths || modelPaths.length === 0) {
99
- this.logger.log(`no model found`)
95
+ const model = await this.model()
96
+ if (!model) {
100
97
  return
101
98
  }
102
- this.logger._debug && this.logger.debug(`model: ${relativePaths(this.buildOptions.root, modelPaths).join(", ")}`)
103
-
104
- await this._writeEdmxToWebapp(src, dest)
99
+ await this._writeEdmxToWebapp(this.task.src, this.task.dest)
105
100
  }
106
101
 
107
102
  async _writeEdmxToWebapp(src, dest) {
@@ -1,6 +1,6 @@
1
1
  const path = require('path')
2
2
  const parser = require('./migrationtable')
3
- const { BuildError } = require('../../util')
3
+ const { BuildError, hasOptionValue } = require('../../util')
4
4
  const { LOG_MODULE_NAMES } = require('../../constants')
5
5
  const cds = require('../../cds'), { compiler: cdsc } = cds
6
6
  const cdscVersion = `-- generated by cds-compiler version ${cdsc.version()}`
@@ -160,7 +160,7 @@ function _filterJournalArtifacts(csn) {
160
160
  }
161
161
  const dict = csn.definitions
162
162
  for (const name in dict) {
163
- if (dict[name][ANNO_PERSISTENCE_JOURNAL] !== true) {
163
+ if (!_isPersistedAsJournalTable(dict[name])) {
164
164
  delete dict[name]
165
165
  }
166
166
  }
@@ -168,3 +168,12 @@ function _filterJournalArtifacts(csn) {
168
168
  csn.meta.build = `CDS Build v${cds.version}`
169
169
  return csn;
170
170
  }
171
+
172
+ // see cds-compiler/lib/model/csnUtils.js#isPersistedAsTable
173
+ function _isPersistedAsJournalTable(artifact) {
174
+ return artifact.kind === 'entity' && hasOptionValue(artifact['@cds.persistence.journal'], true) &&
175
+ !artifact.abstract &&
176
+ !hasOptionValue(artifact['@cds.persistence.skip'], true) &&
177
+ !hasOptionValue(artifact['@cds.persistence.exists'], true) &&
178
+ (!artifact.query && !artifact.projection || hasOptionValue(artifact['@cds.persistence.table'], true))
179
+ }
@@ -338,6 +338,12 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
338
338
  if (!HanaModuleBuilder._toEqualIgnoreMeta(lastDev, afterImage)) {
339
339
  await this.write(afterImage).to(lastDevCsnDir)
340
340
  }
341
+
342
+ // add src/.hdiconfig if not existing
343
+ if (!fs.existsSync(path.join(dbSrcDir, '.hdiconfig'))) {
344
+ const template = await HanaModuleBuilder._readTemplateAsJson('.hdiconfig-hanacloud')
345
+ await this.write(template).to(path.join(dbSrcDir, '.hdiconfig'))
346
+ }
341
347
  }
342
348
  } else {
343
349
  throw new BuildError(`Inconsistent CDS compilation results - file ${lastDevCsnFolder} missing`)
@@ -352,7 +358,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
352
358
  this.logger._debug && this.logger.debug(`skip create [${relativePaths(this.buildOptions.root, packageJson)}], already existing`)
353
359
  }
354
360
  if (this.isStagingBuild() && !exists) {
355
- const content = await this._readTemplateAsJson(FILE_NAME_PACKAGE_JSON)
361
+ const content = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_PACKAGE_JSON)
356
362
  await this.write(content).to(path.join(this.task.dest, FILE_NAME_PACKAGE_JSON))
357
363
  }
358
364
  }
@@ -362,7 +368,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
362
368
  */
363
369
  async _writeHdiConfig(plugins) {
364
370
  const hdiConfig = path.join(this.task.options.compileDest, FILE_NAME_HDICONFIG)
365
- const template = await this._readTemplateAsJson(FILE_NAME_HDICONFIG)
371
+ const template = await HanaModuleBuilder._readTemplateAsJson('.hdiconfig-haas')
366
372
  let content = {
367
373
  'file_suffixes': {}
368
374
  }
@@ -372,7 +378,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
372
378
  }
373
379
  }
374
380
  if (Object.keys(content['file_suffixes']).length !== plugins.size) {
375
- this.logger.error(`'HANA plugin not found for file suffix [${Array.from(plugins).join(',')}]`)
381
+ this.pushMessage(`'HANA plugin not found for file suffix [${Array.from(plugins).join(',')}]`)
376
382
  }
377
383
  // TODO - Be on the save side for now - go for the content use case later on if this works as expected.
378
384
  if (cds.env.hana['deploy-format'] === 'hdbtable') {
@@ -388,7 +394,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
388
394
  async _writeHdiNamespace() {
389
395
  // see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
390
396
  const hdiNamespace = path.join(this.task.options.compileDest, FILE_NAME_HDINAMESPACE)
391
- const content = await this._readTemplateAsJson(FILE_NAME_HDINAMESPACE)
397
+ const content = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_HDINAMESPACE)
392
398
  return await this.write(content).to(hdiNamespace)
393
399
  }
394
400
 
@@ -400,7 +406,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
400
406
  // see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
401
407
  const undeployJsonDest = path.join(this.task.dest, FILE_NAME_UNDEPLOY_JSON)
402
408
  const undeployJsonSrc = path.join(this.task.src, FILE_NAME_UNDEPLOY_JSON)
403
- const templateEntries = await this._readTemplateAsJson(FILE_NAME_UNDEPLOY_JSON)
409
+ const templateEntries = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_UNDEPLOY_JSON)
404
410
  let newEntries = []
405
411
  if (fs.existsSync(undeployJsonSrc)) {
406
412
  newEntries = await JSON.parse((await fs.promises.readFile(undeployJsonSrc, 'utf-8')).toString())
@@ -423,20 +429,12 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
423
429
  }
424
430
  }
425
431
 
426
- async _readTemplateAsJson(template) {
427
- const templatePath = path.join(__dirname, 'template', template)
428
- return fs.promises.readFile(templatePath, 'utf-8').then(f => JSON.parse(f.toString()))
429
- .catch((error) => {
430
- this.logger.error(`Failed to read template [${templatePath}]`)
431
- return Promise.reject(error)
432
- })
433
- }
434
432
 
435
433
  async _readTypesFromUndeployJson() {
436
434
  const result = new Set()
437
435
  const file = path.join(this.task.src, "undeploy.json")
438
436
  if (fs.existsSync(file)) {
439
- const undeployList = JSON.parse((await fs.promises.readFile(file)).toString())
437
+ const undeployList = JSON.parse((await fs.promises.readFile(file)).toString(), 'utf-8')
440
438
  if (Array.isArray(undeployList)) {
441
439
  undeployList.forEach(entry => result.add(path.extname(entry)))
442
440
  }
@@ -466,6 +464,11 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
466
464
  }
467
465
  }
468
466
 
467
+ static async _readTemplateAsJson(template) {
468
+ const content = await fs.promises.readFile(path.join(__dirname, 'template', template), 'utf-8')
469
+ return JSON.parse(content.toString())
470
+ }
471
+
469
472
  static _toEqualIgnoreMeta(csn1, csn2) {
470
473
  function toString(csn) {
471
474
  return JSON.stringify(csn, (k, v) => {
@@ -0,0 +1,137 @@
1
+
2
+ {
3
+ "file_suffixes": {
4
+ "csv": {
5
+ "plugin_name": "com.sap.hana.di.tabledata.source"
6
+ },
7
+ "hdbafllangprocedure": {
8
+ "plugin_name": "com.sap.hana.di.afllangprocedure"
9
+ },
10
+ "hdbanalyticprivilege": {
11
+ "plugin_name": "com.sap.hana.di.analyticprivilege"
12
+ },
13
+ "hdbcalculationview": {
14
+ "plugin_name": "com.sap.hana.di.calculationview"
15
+ },
16
+ "hdbcollection": {
17
+ "plugin_name": "com.sap.hana.di.collection"
18
+ },
19
+ "hdbconstraint": {
20
+ "plugin_name": "com.sap.hana.di.constraint"
21
+ },
22
+ "hdbdropcreatetable": {
23
+ "plugin_name": "com.sap.hana.di.dropcreatetable"
24
+ },
25
+ "hdbflowgraph": {
26
+ "plugin_name": "com.sap.hana.di.flowgraph"
27
+ },
28
+ "hdbfunction": {
29
+ "plugin_name": "com.sap.hana.di.function"
30
+ },
31
+ "hdbgraphworkspace": {
32
+ "plugin_name": "com.sap.hana.di.graphworkspace"
33
+ },
34
+ "hdbhadoopmrjob": {
35
+ "plugin_name": "com.sap.hana.di.virtualfunctionpackage.hadoop"
36
+ },
37
+ "hdbindex": {
38
+ "plugin_name": "com.sap.hana.di.index"
39
+ },
40
+ "hdblibrary": {
41
+ "plugin_name": "com.sap.hana.di.library"
42
+ },
43
+ "hdbmigrationtable": {
44
+ "plugin_name": "com.sap.hana.di.table.migration"
45
+ },
46
+ "hdbprocedure": {
47
+ "plugin_name": "com.sap.hana.di.procedure"
48
+ },
49
+ "hdbprojectionview": {
50
+ "plugin_name": "com.sap.hana.di.projectionview"
51
+ },
52
+ "hdbprojectionviewconfig": {
53
+ "plugin_name": "com.sap.hana.di.projectionview.config"
54
+ },
55
+ "hdbreptask": {
56
+ "plugin_name": "com.sap.hana.di.reptask"
57
+ },
58
+ "hdbresultcache": {
59
+ "plugin_name": "com.sap.hana.di.resultcache"
60
+ },
61
+ "hdbrole": {
62
+ "plugin_name": "com.sap.hana.di.role"
63
+ },
64
+ "hdbroleconfig": {
65
+ "plugin_name": "com.sap.hana.di.role.config"
66
+ },
67
+ "hdbsearchruleset": {
68
+ "plugin_name": "com.sap.hana.di.searchruleset"
69
+ },
70
+ "hdbsequence": {
71
+ "plugin_name": "com.sap.hana.di.sequence"
72
+ },
73
+ "hdbstatistics": {
74
+ "plugin_name": "com.sap.hana.di.statistics"
75
+ },
76
+ "hdbstructuredprivilege": {
77
+ "plugin_name": "com.sap.hana.di.structuredprivilege"
78
+ },
79
+ "hdbsynonym": {
80
+ "plugin_name": "com.sap.hana.di.synonym"
81
+ },
82
+ "hdbsynonymconfig": {
83
+ "plugin_name": "com.sap.hana.di.synonym.config"
84
+ },
85
+ "hdbsystemversioning": {
86
+ "plugin_name": "com.sap.hana.di.systemversioning"
87
+ },
88
+ "hdbtable": {
89
+ "plugin_name": "com.sap.hana.di.table"
90
+ },
91
+ "hdbtabledata": {
92
+ "plugin_name": "com.sap.hana.di.tabledata"
93
+ },
94
+ "hdbtabletype": {
95
+ "plugin_name": "com.sap.hana.di.tabletype"
96
+ },
97
+ "hdbtrigger": {
98
+ "plugin_name": "com.sap.hana.di.trigger"
99
+ },
100
+ "hdbview": {
101
+ "plugin_name": "com.sap.hana.di.view"
102
+ },
103
+ "hdbvirtualfunction": {
104
+ "plugin_name": "com.sap.hana.di.virtualfunction"
105
+ },
106
+ "hdbvirtualfunctionconfig": {
107
+ "plugin_name": "com.sap.hana.di.virtualfunction.config"
108
+ },
109
+ "hdbvirtualpackagehadoop": {
110
+ "plugin_name": "com.sap.hana.di.virtualpackage.hadoop"
111
+ },
112
+ "hdbvirtualpackagesparksql": {
113
+ "plugin_name": "com.sap.hana.di.virtualpackage.sparksql"
114
+ },
115
+ "hdbvirtualprocedure": {
116
+ "plugin_name": "com.sap.hana.di.virtualprocedure"
117
+ },
118
+ "hdbvirtualprocedureconfig": {
119
+ "plugin_name": "com.sap.hana.di.virtualprocedure.config"
120
+ },
121
+ "hdbvirtualtable": {
122
+ "plugin_name": "com.sap.hana.di.virtualtable"
123
+ },
124
+ "hdbvirtualtableconfig": {
125
+ "plugin_name": "com.sap.hana.di.virtualtable.config"
126
+ },
127
+ "properties": {
128
+ "plugin_name": "com.sap.hana.di.tabledata.properties"
129
+ },
130
+ "tags": {
131
+ "plugin_name": "com.sap.hana.di.tabledata.properties"
132
+ },
133
+ "txt": {
134
+ "plugin_name": "com.sap.hana.di.copyonly"
135
+ }
136
+ }
137
+ }
@@ -5,6 +5,7 @@ const cds = require('../../cds')
5
5
  const BuildTaskHandlerInternal = require('../buildTaskHandlerInternal')
6
6
  const { FOLDER_GEN } = require('../../constants')
7
7
  const ResourcesTarBuilder = require('../mtx/resourcesTarBuilder')
8
+ const { BuildError } = require('../../util')
8
9
 
9
10
  class MtxExtensionModuleBuilder extends BuildTaskHandlerInternal {
10
11
  init() {
@@ -18,7 +19,19 @@ class MtxExtensionModuleBuilder extends BuildTaskHandlerInternal {
18
19
  const { src, dest } = this.task
19
20
  const destExt = path.join(dest, 'ext')
20
21
 
21
- await this.copy(path.join(src, 'package.json')).to(path.join(destExt, 'package.json'))
22
+ const packageJson = path.join(src, 'package.json')
23
+ if (!fs.existsSync(packageJson)) {
24
+ throw new BuildError(`The package.json file is missing`)
25
+ }
26
+ await this.copy(packageJson).to(path.join(destExt, 'package.json'))
27
+
28
+ // validate existence of base model by simply checking existence of appPackage folder
29
+ // cds.resolve might fail for the extension migration use case as no index.csn file exists.
30
+ // A compilation error is thrown anyhow if any base model using statement cannot be resolved.
31
+ const appPackage = MtxExtensionModuleBuilder._getAppPackageName()
32
+ if (!fs.existsSync(path.join(src, 'node_modules', appPackage))) {
33
+ throw new BuildError(`The SaaS application base model '${appPackage}' is missing. Have you run the 'cds pull' command?`)
34
+ }
22
35
 
23
36
  // copy handlers
24
37
  const folders = [path.join(src, cds.env.folders.srv, 'handlers')]
@@ -58,5 +71,9 @@ class MtxExtensionModuleBuilder extends BuildTaskHandlerInternal {
58
71
  // add all resources contained in the 'ext' folder
59
72
  await new ResourcesTarBuilder(this).writeTarFile(path.join(this.task.dest, 'extension.tgz'), destExt)
60
73
  }
74
+
75
+ static _getAppPackageName() {
76
+ return cds.env.extends || '_base';
77
+ }
61
78
  }
62
79
  module.exports = MtxExtensionModuleBuilder
@@ -59,7 +59,7 @@ class MtxSidecarModuleBuilder extends NodeCfModuleBuilder {
59
59
  */
60
60
  async _buildMainApp(sidecarEnv) {
61
61
  if (sidecarEnv.requires['cds.xt.ModelProviderService']?.kind !== 'in-sidecar') {
62
- throw new BuildError("CDS build failed", "Invalid MTX sidecar configuration - \"cds.xt.ModelProviderService\": \"in-sidecar\" missing.")
62
+ throw new BuildError('Invalid MTX sidecar configuration - "cds.xt.ModelProviderService": "in-sidecar" missing.')
63
63
  }
64
64
  let main = sidecarEnv.requires['cds.xt.ModelProviderService']?.root
65
65
  const profiles = cds.env.profiles || []
package/bin/build/util.js CHANGED
@@ -228,7 +228,7 @@ class BuildError extends BuildMessage {
228
228
  }
229
229
 
230
230
  toString() {
231
- return this.message + '\n' + this.messages.map(m => m.toString()).join('\n')
231
+ return this.message + (this.messages.length > 0 ? '\n' + this.messages.map(m => m.toString()).join('\n') : '')
232
232
  }
233
233
  }
234
234
 
package/bin/cds.js CHANGED
@@ -9,7 +9,6 @@ const cli = { //NOSONAR
9
9
 
10
10
  exec (cmd = process.argv[2], ...argv) {
11
11
  if (!argv.length) argv = process.argv.slice(3)
12
- if (process.env.NODE_ENV !== 'test') this.errorHandlers()
13
12
  if (cmd in this.Shortcuts) cmd = process.argv[2] = this.Shortcuts[cmd]
14
13
  let task = this.load ('./'+cmd)
15
14
  if (task && cmd !== 'build') return task.apply (this, this.args(task,argv))
@@ -59,10 +58,7 @@ const cli = { //NOSONAR
59
58
  },
60
59
 
61
60
  errorHandlers () {
62
- const _error = (e) => { cli.log(e.errors || e, { 'log-level': cds.env.log.levels.cli }); _exit(1) }
63
- const _exit = (c) => { console.log(); process.exit(c) }
64
- cds.repl || process.on ('unhandledRejection', _error)
65
- cds.repl || process.on ('uncaughtException', _error)
61
+ // for compatibility with lkg -> remove after next release of cds-dk
66
62
  },
67
63
 
68
64
  get log() { return this.log = require('./utils/log') }
@@ -71,8 +71,8 @@ class HanaDeployer {
71
71
  await fs.write(path.join(currentModelFolder, 'undeploy.json'), JSON.stringify(undeployWhitelist, null, 2));
72
72
  }
73
73
 
74
- const isEmpty = !Object.keys(vcapEnv).length;
75
- if (!isEmpty) {
74
+ const hasVCAPEnv = Object.keys(vcapEnv).length > 0;
75
+ if (hasVCAPEnv) {
76
76
  await fs.mkdir(currentModelFolder, { recursive: true });
77
77
  } else {
78
78
  const { cfServiceInstanceName, cfServiceInstanceKeyName, serviceKey } =
@@ -106,7 +106,14 @@ class HanaDeployer {
106
106
 
107
107
  await hdiDeployUtil.deploy(currentModelFolder, vcapEnv, hdiOptions);
108
108
 
109
- if (bindCallback) {
109
+ // let isLoggedInToCF;
110
+ // try {
111
+ // isLoggedInToCF = !!(await cfUtil.getCfTarget());
112
+ // } catch (err) {
113
+ // // valid state: not logged in
114
+ // }
115
+ // if (bindCallback && isLoggedInToCF) {
116
+ if (!hasVCAPEnv && bindCallback) {
110
117
  const args = [path.relative(projectPath, buildResult.task.src)];
111
118
  const options = { to: `${serviceName}:${serviceKeyName}`, kind: buildResult.task.for }
112
119
  await bindCallback(args, options);