@sap/cds-dk 8.9.4 → 9.0.4

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 (100) hide show
  1. package/CHANGELOG.md +89 -2012
  2. package/LICENSE +15 -21
  3. package/bin/bind.js +1 -1
  4. package/bin/build.js +35 -37
  5. package/bin/cds.js +12 -29
  6. package/bin/compile/index.js +2 -2
  7. package/bin/debug.js +27 -7
  8. package/bin/deploy/index.js +6 -23
  9. package/bin/deploy/to-hana.js +4 -2
  10. package/bin/help.js +3 -1
  11. package/bin/init.js +1 -1
  12. package/bin/up.js +45 -12
  13. package/bin/watch.js +45 -63
  14. package/lib/bind/cf.js +2 -1
  15. package/lib/bind/k8s.js +2 -2
  16. package/lib/bind/plugin.js +1 -1
  17. package/lib/bind/shared.js +16 -25
  18. package/lib/build/buildTaskEngine.js +26 -10
  19. package/lib/build/buildTaskFactory.js +3 -2
  20. package/lib/build/buildTaskProvider.js +18 -7
  21. package/lib/build/buildTaskProviderFactory.js +35 -13
  22. package/lib/build/constants.js +4 -0
  23. package/lib/build/index.js +1 -1
  24. package/lib/build/plugin.js +89 -54
  25. package/lib/build/plugins/helm/files/subcharts/web-application/Chart.yaml +3 -1
  26. package/lib/build/plugins/helm/files/subcharts/web-application/templates/_helpers.tpl +4 -2
  27. package/lib/build/plugins/helm/files/subcharts/web-application/templates/api-rule.yaml +4 -2
  28. package/lib/build/plugins/helm/files/subcharts/web-application/templates/deployment.yaml +18 -1
  29. package/lib/build/plugins/helm/files/subcharts/web-application/templates/service-binding.yaml +0 -1
  30. package/lib/build/plugins/helm/files/subcharts/web-application/values.schema.json +34 -2
  31. package/lib/build/plugins/helm/files/subcharts/web-application/values.yaml +9 -2
  32. package/lib/build/plugins/helm/index.js +2 -1
  33. package/lib/build/plugins.js +24 -10
  34. package/lib/build/provider/edmxBuildPlugin.js +1 -11
  35. package/lib/build/provider/hana/index.js +12 -5
  36. package/lib/build/provider/hana/template/package.json +1 -1
  37. package/lib/build/provider/internalBuildPlugin.js +1 -1
  38. package/lib/build/provider/internalBuildTaskProvider.js +3 -24
  39. package/lib/build/provider/java/index.js +1 -1
  40. package/lib/build/provider/mtx-extension/index.js +3 -8
  41. package/lib/build/provider/nodejs/index.js +28 -6
  42. package/lib/build/util.js +186 -125
  43. package/lib/deploy/index.js +5 -0
  44. package/lib/deploy/to-hana/hana.js +27 -33
  45. package/lib/deploy/to-hana/hdiDeployUtil.js +2 -2
  46. package/lib/import/odata/v2parser.js +34 -3
  47. package/lib/import/openapi/importOpenAPI.js +4 -0
  48. package/lib/index.js +2 -11
  49. package/lib/init/constants.js +0 -1
  50. package/lib/init/merge.js +101 -77
  51. package/lib/init/mvn.js +3 -3
  52. package/lib/init/projectReader.js +1 -1
  53. package/lib/init/template/ams/files/mta.yaml.hbs +6 -1
  54. package/lib/init/template/ams/files/package.json.hbs +1 -1
  55. package/lib/init/template/approuter/files/mta.yaml.hbs +5 -0
  56. package/lib/init/template/cf-manifest/files/manifest.yml.hbs +1 -1
  57. package/lib/init/template/cloud-logging/files/package.json.hbs +3 -3
  58. package/lib/init/template/dynatrace/files/mta.yaml.hbs +1 -1
  59. package/lib/init/template/dynatrace/files/package.json.hbs +2 -2
  60. package/lib/init/template/dynatrace/index.js +2 -1
  61. package/lib/init/template/enterprise-messaging/files/mta.yaml.hbs +6 -0
  62. package/lib/init/template/enterprise-messaging/index.js +5 -1
  63. package/lib/init/template/extensibility/files/package.json.hbs +1 -1
  64. package/lib/init/template/hana/files/db/package.json +1 -1
  65. package/lib/init/template/hana/files/package.json.hbs +2 -4
  66. package/lib/init/template/helm/index.js +13 -22
  67. package/lib/init/template/helm-unified-runtime/index.js +2 -1
  68. package/lib/init/template/html5-repo/files/values.yaml.hbs +12 -1
  69. package/lib/init/template/html5-repo/index.js +10 -5
  70. package/lib/init/template/http/index.js +1 -1
  71. package/lib/init/template/ias/files/mta.yaml.hbs +1 -1
  72. package/lib/init/template/ias/files/sidecar.package.json.hbs +0 -7
  73. package/lib/init/template/ias/index.js +5 -4
  74. package/lib/init/template/lint/files/package.json +6 -0
  75. package/lib/init/template/lint/index.js +61 -204
  76. package/lib/init/template/mta/files/package.json +1 -1
  77. package/lib/init/template/multitenancy/files/mta.yaml.hbs +2 -2
  78. package/lib/init/template/multitenancy/files/package.json.hbs +1 -1
  79. package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +7 -4
  80. package/lib/init/template/multitenancy/index.js +3 -0
  81. package/lib/init/template/nodejs/files/package.json.hbs +5 -2
  82. package/lib/init/template/redis/files/package.json.hbs +1 -1
  83. package/lib/init/template/sqlite/files/package.json +1 -1
  84. package/lib/init/template/toggles/files/package.json.hbs +1 -1
  85. package/lib/init/template/typescript/files/package.json +1 -3
  86. package/lib/init/template/workzone-standard/index.js +2 -0
  87. package/lib/init/template/xsuaa/index.js +2 -6
  88. package/lib/lint/Linter.js +203 -331
  89. package/lib/lint/generators.js +52 -46
  90. package/lib/lint/io.js +77 -289
  91. package/lib/util/fs.js +2 -1
  92. package/lib/util/git.js +1 -1
  93. package/lib/util/glob.js +77 -0
  94. package/lib/watch/livereload-server.js +3 -4
  95. package/lib/watch/node-watch.js +3 -4
  96. package/lib/watch/watched.js +1 -1
  97. package/npm-shrinkwrap.json +59 -1232
  98. package/package.json +6 -8
  99. package/readme.md +1 -1
  100. package/lib/lint/checks.js +0 -135
@@ -709,11 +709,42 @@ function _getServiceComplexTypes(parserContext) {
709
709
  complexTypeKey = complexTypesKeys[i];
710
710
  complexType = parserContext.allComplexTypes[complexTypeKey].Property;
711
711
  isOpenType = parserContext.allComplexTypes[complexTypeKey].open;
712
- complexTypeCSN = complexTypeCSN + _getServiceComplexType(complexTypeKey, complexType, parserContext, isOpenType);
712
+
713
+ //S4 might have actions or functions which return a complex type named like the action or function. In this case the complex type must be renamed as else a compile error happens as the result type cannot be found / is a function.
714
+ if (parserContext.allFunctionImports.some(fi => fi[0] === complexTypeKey)) {
715
+ const originalName = complexTypeKey;
716
+ const functionImport = parserContext.allFunctionImports.find(fi => fi[0] === complexTypeKey);
717
+ complexTypeKey = functionImport[0] + 'ReturnType';
718
+ let i = 1;
719
+ while (
720
+ parserContext.allFunctionImports.some(fi => fi[0] === complexTypeKey) ||
721
+ parserContext.allEntitySetMapMC[complexTypeKey] ||
722
+ parserContext.allEntitySetMap[_extractEntityFromNamespace(complexTypeKey)] ||
723
+ parserContext.allEntities.includes(_extractEntityFromNamespace(complexTypeKey))
724
+ ) {
725
+ if (i > 1) {
726
+ complexTypeKey = complexTypeKey.slice(0, complexTypeKey.length-1)
727
+ }
728
+ complexTypeKey += i;
729
+ i++;
730
+ }
731
+
732
+ //Rename complexType in parserContext for downstream FunctionImport logic
733
+ parserContext.allComplexTypes[complexTypeKey] = parserContext.allComplexTypes[originalName];
734
+ parserContext.allComplexTypes[complexTypeKey]['_attributes'].Name = complexTypeKey
735
+ delete parserContext.allComplexTypes[originalName]
736
+ //Correct Return Type of affected FunctionImports
737
+ const functionImportsWithWrongReturnType = parserContext.allFunctionImports.filter(fi => fi[2] === originalName || fi[2] === `Collection(${originalName})`);
738
+ for (const functionImport of functionImportsWithWrongReturnType) {
739
+ functionImport[2] = functionImport[2].replace(originalName, complexTypeKey);
740
+ }
741
+ }
742
+
743
+ complexTypeCSN += _getServiceComplexType(complexTypeKey, complexType, parserContext, isOpenType);
713
744
  if (i !== complexTypesKeys.length - 1) {
714
- complexTypeCSN = complexTypeCSN + ",\n";
745
+ complexTypeCSN += ",\n";
715
746
  } else {
716
- complexTypeCSN = complexTypeCSN + "\n";
747
+ complexTypeCSN += "\n";
717
748
  }
718
749
  }
719
750
  return complexTypeCSN;
@@ -685,6 +685,10 @@ function structElements(context, type, schema) {
685
685
  //TODO: check if property "name" already exists and has identical cdsType, warn otherwise
686
686
  type.elements[name] = cdsType(context, propSchema);
687
687
  if (name !== prop) type.elements[name]["@openapi.name"] = prop;
688
+ // Add @mandatory if the property is in the required array
689
+ if (schema.required && schema.required.includes(prop)) {
690
+ type.elements[name]["@mandatory"] = true;
691
+ }
688
692
  }
689
693
  }
690
694
 
package/lib/index.js CHANGED
@@ -35,10 +35,11 @@ class CdsDk {
35
35
  }
36
36
  }
37
37
 
38
- const REQUIRED_CDS_MAJOR = 7, REQUIRED_CDS_MINOR = 2
38
+ const REQUIRED_CDS_MAJOR = 8, REQUIRED_CDS_MINOR = 3
39
39
  const [major, minor] = cds.version.split('.').map(Number)
40
40
  if (major < REQUIRED_CDS_MAJOR || major === REQUIRED_CDS_MAJOR && minor < REQUIRED_CDS_MINOR) {
41
41
  const [dkVersion] = require('../package.json').version.split('.')
42
+
42
43
  console.error(`
43
44
  This application uses '@sap/cds' version ${major}.${minor}, which is not compatible with the installed '@sap/cds-dk' version ${dkVersion}.
44
45
  You can either:
@@ -48,16 +49,6 @@ if (major < REQUIRED_CDS_MAJOR || major === REQUIRED_CDS_MAJOR && minor < REQUIR
48
49
  process.exit(1)
49
50
  }
50
51
 
51
- const EXCLUDED_CDS_MAJOR = 9
52
- if (major >= EXCLUDED_CDS_MAJOR) {
53
- const [dkVersion] = require('../package.json').version.split('.')
54
- console.error(`
55
- This application uses '@sap/cds' version ${major}, which is not compatible with the installed '@sap/cds-dk' version ${dkVersion}.
56
- Update '@sap/cds-dk' to the latest version.
57
- `)
58
- process.exit(1)
59
- }
60
-
61
52
  cds.extend (cds.constructor) .with (CdsDk)
62
53
 
63
54
  class CdsDkAdd {
@@ -61,7 +61,6 @@ module.exports = {
61
61
  DATA: 'data',
62
62
  HTTP: 'http',
63
63
  LINT: 'lint',
64
- LINT_GLOBAL: 'lint:global',
65
64
  LINT_DEV: 'lint:dev',
66
65
  PIPELINE: 'pipeline',
67
66
  }),
package/lib/init/merge.js CHANGED
@@ -1,7 +1,8 @@
1
1
  const { EOL } = require('node:os')
2
2
  const { inspect } = require('node:util')
3
3
  const cds = require('../cds')
4
- const { copy, read, write, exists, path: {resolve, join}, yaml: YAML } = cds.utils
4
+ const YAML = require('yaml')
5
+ const { copy, read, write, exists, path: {resolve, join} } = cds.utils
5
6
  const { readYAML, writeYAML, readJSON } = require('../util/fs')
6
7
  const { detectIndent } = require('./indent')
7
8
  const { colors } = require('../util/term')
@@ -50,43 +51,7 @@ module.exports.mergeGitignore = async function(into, from) {
50
51
  const enhanced = target.concat(source.filter(line => !target.includes(line)))
51
52
  await write(into, enhanced.join(EOL))
52
53
  return enhanced
53
- }
54
-
55
- /**
56
- * @typedef {Object} MatchedNode
57
- * @property {string | MatchedNode} in - key path or matched node to start search from
58
- * @property {Object} where - list of constraints
59
- */
60
-
61
- /**
62
- * @typedef {Object} Overwrites
63
- * @property {(string | MatchedNode)[]} item - path to item to be overwritten
64
- * @property {string} withValue - replacement string
65
- */
66
-
67
- /**
68
- * @typedef {Object} Deletion
69
- * @property {MatchedNode} item - matched node to delete
70
- * @property {MatchedNode} [key] - key path to property to delete in node (optional)
71
- * @property {Object[]} [relationships] - list of relationships to delete
72
- * @property {string} relationships[].removeProperty - key path to to-be-removed property
73
- * @property {string[]} relationships[].allWithin - key path to relationship
74
- */
75
-
76
- /**
77
- * @typedef {Object} Relationship
78
- * @property {(string | MatchedNode)[]} insert - source path to matched node
79
- * @property {(string | MatchedNode)[]} into - target path for inserted relationship
80
- */
81
-
82
- /**
83
- * @typedef {Object} MergingSemantics
84
- * @property {boolean} [forceOverwrite] - overwrite values for existing keys
85
- * @property {MatchedNode[]} [additions] - matched nodes to be added from source template
86
- * @property {Overwrites[]} [overwrites] - matched keys to be overwritten with given string
87
- * @property {Deletion[]} [deletions] - matched nodes to be deleted
88
- * @property {Relationship[]} [relationships] - relationships to be inserted
89
- */
54
+ }
90
55
 
91
56
  /**
92
57
  * @param {string | JSON} into - file path or JSON to merge into
@@ -121,8 +86,8 @@ async function _mergeJSON(into, from, project, semantics) {
121
86
  }
122
87
 
123
88
  /**
124
- * @param {string | YAML.Document} into - file path or YAML to merge into
125
- * @param {string | YAML.Document} from - file path or YAML to merge from
89
+ * @param {string | YAML.Document | object} into - file path or YAML to merge into
90
+ * @param {string | YAML.Document | object} from - file path or YAML to merge from
126
91
  * @param {Object} [project] - project descriptor used for Mustache replacements
127
92
  * @param {MergingSemantics} [semantics] - merging algorithm semantics
128
93
  * @returns {Promise<YAML.Document>} - merged YAML
@@ -169,11 +134,14 @@ async function _mergeYAML(into, from, project, semantics = {}) {
169
134
 
170
135
  const _validateWhere = (node, dict, index) => {
171
136
  const _addToMap = entries => entries?.filter(entry => {
172
- if (typeof entry.in === 'string') return true // just a key path on the document root
173
- const neededParent = dict.get(entry.in[0])?.node
174
- return collectionStack.includes(neededParent) // lookbehind in parent collection stack
175
- // REVISIT: Only look behind until sequence is reached?
137
+ if (typeof entry.in === 'string') return true
138
+ if (typeof entry === 'string' && !entry.where) return false // no random access caching needed for pure key paths
139
+ if (Array.isArray(entry)) entry = entry[0]
140
+ const neededParent = dict.get(entry.in[0])?.node
141
+ return collectionStack.includes(neededParent) // lookbehind in parent collection stack
142
+ // REVISIT: Only look behind until sequence is reached?
176
143
  }).forEach(item => {
144
+ if (Array.isArray(item)) item = item[0]
177
145
  const json = JSON.parse(String(node))
178
146
  const whereFulfilled = Object.entries(item.where).every(([key, value]) =>
179
147
  _getProperty(json, key) === value
@@ -186,7 +154,7 @@ async function _mergeYAML(into, from, project, semantics = {}) {
186
154
  if (additions) _addToMap(additions)
187
155
  if (deletions) _addToMap(deletions.map(deletion => deletion.item))
188
156
  if (relationships) _addToMap(relationships?.map(({into: [entry]}) => entry).filter(e => e))
189
- if (overwrites) _addToMap(overwrites.map(overwrite => overwrite.item[0]))
157
+ if (overwrites) _addToMap(overwrites.map(overwrite => overwrite.item))
190
158
  }
191
159
 
192
160
  function _traverseYAMLNode(node, index, actions, templateNode) {
@@ -284,11 +252,23 @@ async function _mergeYAML(into, from, project, semantics = {}) {
284
252
  overwrites?.forEach(({ item, withValue }) => {
285
253
  const keyPath = Array.isArray(item) && typeof item[0] === 'string' ? item[0] : typeof item === 'string' ? item : item[1]
286
254
  const inEntry = Array.isArray(item) && typeof item[0] === 'object' ? item[0] : typeof item === 'object' ? item : item[1]
287
- const node = inEntry && entryMap.get(inEntry) ? entryMap.get(inEntry).node : collectionStack[collectionStack.length - 1]
255
+ let node
256
+ if (inEntry && entryMap.get(inEntry)) {
257
+ node = entryMap.get(inEntry).node // starting from item found in nested array cache
258
+ } else {
259
+ node = collectionStack[collectionStack.length - 1] // starting from root
260
+ }
288
261
  const keys = keyPath.split('.')
289
- if (!node.getIn(keys)) return
290
- _getYAMLProperty(node, keys.slice(0, keys.length - 1).join('.'))
291
- .set(keys[keys.length - 1], withValue)
262
+ for (const key of keys.slice(0, -1)) {
263
+ if (!node?.get(key) && typeof inEntry === 'string') return // node doesn't exist, will be added by template
264
+ node = node?.get(key) ?? node
265
+ }
266
+ const tail = keys.pop()
267
+ if (!node.get(tail)) {
268
+ node.add({ key: tail, value: withValue })
269
+ } else {
270
+ node.set(tail, withValue)
271
+ }
292
272
  })
293
273
 
294
274
  // 4. Delete entries from the project (e.g. separate deployer module when adding mtx)
@@ -335,7 +315,7 @@ async function _mergeYAML(into, from, project, semantics = {}) {
335
315
  })
336
316
  .filter(item => !entryMap.get(item))
337
317
  .forEach(item => {
338
- if (!templateEntryMap.get(item)) throw 'Error: did not find entry in template for ' + inspect(item, { colors, depth:11 }) + ' in ' + from
318
+ if (!templateEntryMap.get(item)) throw 'Error: did not find entry in template for ' + inspect(item, { colors, depth:11 }) + ' in \n' + from
339
319
  const templateNode = templateEntryMap.get(item).node
340
320
  item.at !== undefined ? targetNode.items.splice(item.at, 0, templateNode) : targetNode.add(templateNode)
341
321
  })
@@ -352,36 +332,42 @@ async function _mergeYAML(into, from, project, semantics = {}) {
352
332
  // 7. Create missing relationships
353
333
  _traverseYAMLNode(target.contents, null, {
354
334
  mergeCollection: (targetNode, templateNode) => {
355
- if (YAML.isSeq(templateNode)) {
335
+ if (!YAML.isSeq(templateNode)) return
356
336
  const targetJSON = YAML.parse(String(targetNode))
357
- const relationships = semantics.relationships?.filter(relationship => {
358
- const [entry, keyPath] = relationship.into
359
- if (!entryMap.get(entry)) return false
360
- const existingNode = _getYAMLProperty(entryMap.get(entry).node, keyPath)
361
- return targetNode === existingNode
362
- }) ?? []
363
-
364
- for (const { into, insert } of relationships) {
365
- const intoKey = into[into.length - 1]
366
- const [insEntry, entryKeyPath] = insert
367
- const missingPairs = [insEntry]
368
- .filter(item => {
369
- if (!entryMap.get(item)) {
370
- const spec = inspect(item, { colors, depth:11 })
371
- throw new Error(`Did not find entry in template for ${spec} in ${from}:\n${source}`)
372
- }
373
- return !targetJSON.some(targetItem =>
374
- _getProperty(entryMap.get(item).json, entryKeyPath) === targetItem[intoKey]
375
- )
376
- })
377
- .map(item => entryMap.get(item).node.get(intoKey))
378
- for (const pair of missingPairs) {
379
- targetNode.add({ [intoKey]: pair })
380
- }
337
+ for (const { insert, into } of semantics.relationships ?? []) {
338
+ const [first, ...rest] = into
339
+ const seqPath = rest.find(x => typeof x === 'string') || ''
340
+ const keyPath = rest.length > 1 ? rest.at(-1) : null
341
+ const base = entryMap.get(first)
342
+ if (!base) continue
343
+ const seqNode = seqPath ? _getYAMLProperty(base.node, seqPath) : base.node
344
+ if (seqNode !== targetNode) continue
345
+ const inserts = Array.isArray(insert) ? insert : [insert]
346
+ for (const ins of inserts) {
347
+ const insEntry = entryMap.get(ins)
348
+ if (!insEntry) continue
349
+ const srcNode = insEntry.node, srcJson = insEntry.json
350
+ let key = keyPath
351
+ if (!key && srcNode.get && srcNode.get('name')) key = 'name'
352
+ let cand, duplicate
353
+ if (key) {
354
+ const val = _getProperty(srcJson, key)
355
+ cand = templateNode.items.find(i => YAML.isMap(i) && i.get(key) === val) || { [key]: val }
356
+ duplicate = targetJSON.some(t => t?.[key] === val)
357
+ } else {
358
+ cand = templateNode.items.find(i => JSON.stringify(YAML.parse(String(i))) === JSON.stringify(YAML.parse(String(srcNode)))) || srcNode
359
+ const srcObj = YAML.parse(String(cand))
360
+ duplicate = targetJSON.some(t => JSON.stringify(t) === JSON.stringify(srcObj))
361
+ }
362
+ if (!duplicate) {
363
+ const clone = YAML.parse(YAML.stringify(cand))
364
+ targetNode.add(clone)
365
+ targetJSON.push(clone)
366
+ }
367
+ }
381
368
  }
382
- }
383
369
  }
384
- }, source.contents)
370
+ }, source.contents)
385
371
 
386
372
  typeof into === 'string' && await writeYAML(into, target)
387
373
  return target
@@ -456,3 +442,41 @@ module.exports.merge = (...src) => {
456
442
  }
457
443
  }
458
444
  }
445
+
446
+
447
+ /**
448
+ * @typedef {Object} MatchedNode
449
+ * @property {string | MatchedNode} in - key path or matched node to start search from
450
+ * @property {Object} where - list of constraints
451
+ */
452
+
453
+ /**
454
+ * @typedef {Object} Overwrites
455
+ * @property {(string | MatchedNode)[]} item - path to item to be overwritten
456
+ * @property {string} withValue - replacement string
457
+ */
458
+
459
+ /**
460
+ * @typedef {Object} Deletion
461
+ * @property {MatchedNode} item - matched node to delete
462
+ * @property {MatchedNode} [key] - key path to property to delete in node (optional)
463
+ * @property {Object[]} [relationships] - list of relationships to delete
464
+ * @property {string} relationships[].removeProperty - key path to to-be-removed property
465
+ * @property {string[]} relationships[].allWithin - key path to relationship
466
+ */
467
+
468
+ /**
469
+ * @typedef {Object} Relationship
470
+ * @property {(string | MatchedNode)[]} insert - source path to matched node
471
+ * @property {(string | MatchedNode)[]} into - target path for inserted relationship
472
+ */
473
+
474
+ /**
475
+ * @typedef {Object} MergingSemantics
476
+ * @property {boolean} [forceOverwrite] - overwrite values for existing keys
477
+ * @property {MatchedNode[]} [additions] - matched nodes to be added from source template
478
+ * @property {Overwrites[]} [overwrites] - matched keys to be overwritten with given string
479
+ * @property {Deletion[]} [deletions] - matched nodes to be deleted
480
+ * @property {Relationship[]} [relationships] - relationships to be inserted
481
+ */
482
+
package/lib/init/mvn.js CHANGED
@@ -156,15 +156,15 @@ function _scan(mvnParams) {
156
156
  // a=[x,y,z] => a:x,y,z
157
157
  const quoteRegex = /([\w\-.]+)=([\w\-.]+|\[([\w.\-,]+)\])/g
158
158
  return [...mvnParams.matchAll(quoteRegex)].map(([,key,value,listValues]) => {
159
- key = key.startsWith('-D') ? key : `-D${key}`
159
+ key = key.startsWith('-') ? key : `-${key}`
160
160
  return [key, listValues || value]
161
161
  })
162
162
  }
163
163
 
164
164
  function _finalize(params) {
165
165
  params.set(`-Dstyle.color`, `always`)
166
- if (LOG._debug) params.set('-X')
167
- if (LOG._debug) params.set('-e')
166
+ if (LOG._debug && !params.has('-X')) params.set('-X')
167
+ if (LOG._debug && !params.has('-e')) params.set('-e')
168
168
  if (process.env.CI) params.set('--batch-mode')
169
169
  const final = Array.from(params, ([arg, val]) => val !== null && val !== undefined ? `${arg}=${val}` : arg)
170
170
  DEBUG?.(term.highlight('mvn ' + final.join(' ')))
@@ -194,7 +194,7 @@ module.exports = new class ProjectReader {
194
194
  hasUI5: _ui5,
195
195
  hasMTXRoute: () => _inProd('extensibility') || (_inProd('multitenancy') && !_isJava()),
196
196
  hasMTXRouteJava: () => (_inProd('helm-unified-runtime') || _inProd('helm')) && _isJava() && _inProd('multitenancy'),
197
- imageRegistry: () => exists('chart/values.yaml') ? cds.load.yaml(join(cds.root, 'chart/values.yaml')).global?.image?.registry ?? '<your-container-registry>' : '<your-container-registry>',
197
+ imageRegistry: () => exists('chart/values.yaml') ? cds.load.yaml(join(cds.root, 'chart/values.yaml')).global?.image?.registry ?? '<your-container-registry-server>' : '<your-container-registry-server>',
198
198
  extendsApp: _extends,
199
199
  }
200
200
 
@@ -10,7 +10,12 @@ modules:
10
10
  - name: {{appName}}-ams-policies-deployer
11
11
  type: javascript.nodejs
12
12
  {{#isJava}}
13
- path: srv/src/gen/policies
13
+ path: .
14
+ build-parameters:
15
+ builder: custom
16
+ commands:
17
+ - npx cds build --for ams
18
+ build-result: srv/src/gen/policies
14
19
  {{/isJava}}
15
20
  {{^isJava}}
16
21
  path: gen/policies
@@ -1,7 +1,7 @@
1
1
  {
2
2
  {{#isNodejs}}
3
3
  "dependencies": {
4
- "@sap/ams": "^2"
4
+ "@sap/ams": "^3"
5
5
  },
6
6
  "devDependencies": {
7
7
  "@sap/ams-dev": "^2"
@@ -72,6 +72,8 @@ modules:
72
72
  resources:
73
73
  - name: {{appName}}-auth
74
74
  type: org.cloudfoundry.managed-service
75
+ requires:
76
+ - name: app-api
75
77
  parameters:
76
78
  service: xsuaa
77
79
  service-plan: application
@@ -79,3 +81,6 @@ resources:
79
81
  config:
80
82
  xsappname: {{appName}}-${org}-${space}
81
83
  tenant-mode: {{#hasMultitenancy}}shared{{/hasMultitenancy}}{{^hasMultitenancy}}dedicated{{/hasMultitenancy}}
84
+ oauth2-configuration:
85
+ redirect-uris:
86
+ - https://~{app-api/app-uri}/**
@@ -17,7 +17,7 @@ applications:
17
17
  {{#isJava}}
18
18
  path: {{& srvPath}}/target/{{archiveName}}
19
19
  memory: 1G
20
- disk_quota: 512M
20
+ disk_quota: 1G
21
21
  env:
22
22
  SPRING_PROFILES_ACTIVE: cloud
23
23
  JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jdk.SAPMachineJDK']"
@@ -2,9 +2,9 @@
2
2
  "dependencies": {
3
3
  "@cap-js/telemetry": ">=0",
4
4
  "@grpc/grpc-js": "^1",
5
- "@opentelemetry/exporter-trace-otlp-grpc": "^0",
6
- "@opentelemetry/exporter-metrics-otlp-grpc": "^0",
7
- "@opentelemetry/host-metrics": "^0"
5
+ "@opentelemetry/exporter-trace-otlp-grpc": "<0.200",
6
+ "@opentelemetry/exporter-metrics-otlp-grpc": "<0.200",
7
+ "@opentelemetry/host-metrics": "<0.200"
8
8
  },
9
9
  "cds": {
10
10
  "requires": {
@@ -37,4 +37,4 @@ resources:
37
37
  service: dynatrace
38
38
  service-plan: environment
39
39
  config:
40
- environment_name: {{appName}}
40
+ environment_name: {{uppercaseStrippedAppName}}
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "dependencies": {
3
3
  "@cap-js/telemetry": ">=0",
4
- "@opentelemetry/exporter-metrics-otlp-proto": "^0"{{#hasHelm}},
5
- "@opentelemetry/host-metrics": "^0"
4
+ "@opentelemetry/exporter-metrics-otlp-proto": "<0.200"{{#hasHelm}},
5
+ "@opentelemetry/host-metrics": "<0.200"
6
6
  {{/hasHelm}}
7
7
  },
8
8
  "cds": {
@@ -24,7 +24,7 @@ module.exports = class extends require('../../plugin') {
24
24
 
25
25
  async combine() {
26
26
  const project = readProject()
27
- const { hasMta, hasHelm, hasHelmUnifiedRuntime, isJava, hasMultitenancy, srvPath } = project
27
+ const { appName, hasMta, hasHelm, hasHelmUnifiedRuntime, isJava, hasMultitenancy, srvPath } = project
28
28
 
29
29
  if (hasMta) {
30
30
  const dynatrace = {
@@ -48,6 +48,7 @@ module.exports = class extends require('../../plugin') {
48
48
  into: [mtxSidecar, 'requires', 'name']
49
49
  })
50
50
  }
51
+ project.uppercaseStrippedAppName = appName.replace(/-/g, '').toUpperCase().slice(0, 16),
51
52
  await merge(__dirname, 'files/mta.yaml.hbs').into('mta.yaml', {
52
53
  with: project, additions, relationships
53
54
  })
@@ -13,3 +13,9 @@ resources:
13
13
  service: enterprise-messaging
14
14
  service-plan: default
15
15
  path: ./event-mesh.json
16
+ - type: org.cloudfoundry.managed-service
17
+ parameters:
18
+ service: xsuaa
19
+ service-plan: application
20
+ processed-after:
21
+ - {{appName}}-messaging
@@ -2,7 +2,7 @@ const cds = require('../../../cds')
2
2
  const { read, yaml: YAML } = cds.utils
3
3
  const { readProject } = require('../../projectReader')
4
4
  const { merge } = require('../../merge')
5
- const { srv4, enterpriseMessaging } = require('../../registries/mta')
5
+ const { srv4, enterpriseMessaging, xsuaa } = require('../../registries/mta')
6
6
 
7
7
  module.exports = class EnterpriseMessagingTemplate extends require('../../plugin') {
8
8
 
@@ -58,6 +58,10 @@ module.exports = class EnterpriseMessagingTemplate extends require('../../plugin
58
58
 
59
59
  if (hasXsuaa) {
60
60
  if (hasMta) {
61
+ await merge(__dirname, 'files/mta.yaml.hbs').into('mta.yaml', {
62
+ project,
63
+ additions: [xsuaa]
64
+ })
61
65
  project['em-service-name'] = YAML.parse(await read('mta.yaml'))?.resources?.find(r => r?.parameters?.service === 'enterprise-messaging')?.name
62
66
  } else {
63
67
  project['em-service-name'] = `${appName}-messaging`
@@ -1,7 +1,7 @@
1
1
  {
2
2
  {{#isNodejs}}
3
3
  "dependencies": {
4
- "@sap/cds-mtxs": "^2"
4
+ "@sap/cds-mtxs": "^3"
5
5
  },
6
6
  "cds": {
7
7
  {{/isNodejs}}
@@ -8,7 +8,7 @@
8
8
  "node": "^22.0.0"
9
9
  },
10
10
  "scripts": {
11
- "start": "node node_modules/@sap/hdi-deploy/deploy.js --use-hdb",
11
+ "start": "node node_modules/@sap/hdi-deploy/deploy.js --use-hdb --parameter com.sap.hana.di.table/try_fast_table_migration=true",
12
12
  "build": "npm i && npx cds build .. --for hana --production"
13
13
  }
14
14
  }
@@ -1,12 +1,10 @@
1
1
  {
2
2
  {{#isNodejs}}
3
3
  "dependencies": {
4
- "@cap-js/hana": "^1"
4
+ "@cap-js/hana": "^2"
5
5
  },
6
6
  "cds": {
7
- "sql": {
8
- "native_hana_associations": false
9
- }{{#profile}},
7
+ {{#profile}}
10
8
  "requires": {
11
9
  "[{{profile}}]": {
12
10
  {{#shortcut}}
@@ -1,6 +1,7 @@
1
1
  const { join } = require('path')
2
+ const yaml = require('yaml')
2
3
  const cds = require('../../../cds')
3
- const { exists, rimraf, copy, readFileSync, yaml } = cds.utils
4
+ const { exists, rimraf, copy, readFileSync } = cds.utils
4
5
  const { readProject } = require('../../projectReader')
5
6
  const { merge } = require('../../merge')
6
7
  const { ask4 } = require('../../../util/question')
@@ -46,43 +47,33 @@ module.exports = class HelmTemplate extends require('../../plugin') {
46
47
  async run() {
47
48
  const project = readProject()
48
49
  project.domain = 'abc.com'
49
- project.registry = 'registry-name'
50
+ project.registry = 'registry-server'
50
51
  project.imagePullSecret = 'docker-registry'
51
52
  project.tag = 'latest'
52
53
 
53
- if (cds.cli.command == 'add' && !HelmTemplate.hasInProduction()) {
54
- let registry = 'registry-name', tag = 'latest', domain = 'abc.com'
54
+ if (cds.cli.command === 'add' && !HelmTemplate.hasInProduction()) {
55
+ let registry = 'registry-server', tag = 'latest', domain = 'abc.com'
55
56
 
56
- // read domain using kubectl
57
57
  try {
58
- const domainCmd = execSync(`kubectl config view --minify --output jsonpath="{.clusters[*].cluster.server}"`, { stdio: "pipe" }).toString()
59
- const domainStartIndex = domainCmd.indexOf('api.')
60
- if (domainStartIndex !== -1) {
61
- domain = domainCmd.substring(domainStartIndex + 4)
62
- }
63
- } catch (error) {
64
- // ignore
65
- }
58
+ const domainGuess = execSync(`kubectl config view --minify --output jsonpath="{.clusters[*].cluster.server}"`, { stdio: "pipe" }).toString()
59
+ const domainStartIndex = domainGuess.indexOf('api.')
60
+ if (domainStartIndex !== -1) domain = domainGuess.substring(domainStartIndex + 4)
61
+ } catch (error) { /* ignore */ }
66
62
 
67
63
  // read project.registry
68
64
  if (exists('containerize.yaml')) {
69
65
  const containerizeYamlFile = readFileSync(join(cds.root, 'containerize.yaml'), 'utf8')
70
- const containerizYaml = yaml.parseDocument(containerizeYamlFile).toJS()
71
- registry = containerizYaml.repository
72
- tag = containerizYaml.tag
66
+ const containerizeYaml = yaml.parseDocument(containerizeYamlFile).toJS()
67
+ registry = containerizeYaml.repository
68
+ tag = containerizeYaml.tag
73
69
  }
74
70
 
75
- let imagePullSecretInput = 'docker-registry'
76
71
  if (!cds.cli.options['y']) {
77
- const [domainAns, imagePullSecretAns, registryAns] = await ask4(`domain: (${domain}) `, 'imagePullSecret: (docker-registry) ', `registry: (${registry}) `)
78
-
79
- domain = domainAns || domain
80
- imagePullSecretInput = imagePullSecretAns || imagePullSecretInput
72
+ const [registryAns] = await ask4(`registry server (${registry}): `)
81
73
  registry = registryAns || registry
82
74
  }
83
75
 
84
76
  project.domain = domain
85
- project.imagePullSecret = imagePullSecretInput
86
77
  project.registry = registry
87
78
  project.tag = tag
88
79
  }
@@ -1,5 +1,6 @@
1
1
  const cds = require('../../..')
2
- const { rimraf, exists, readFileSync, yaml } = cds.utils
2
+ const yaml = require('yaml')
3
+ const { rimraf, exists, readFileSync } = cds.utils
3
4
  const { join } = require('path')
4
5
 
5
6
  const { readProject } = require('../../projectReader')
@@ -5,11 +5,22 @@ html5-apps-repo-host:
5
5
  html5-apps-deployer:
6
6
  env:
7
7
  SAP_CLOUD_SERVICE: {{strippedAppName}}.service
8
+ {{#hasIas}}
9
+ IAS_DEPENDENCY_NAME: {{appName}}-ias-dependency
10
+ {{/hasIas}}
8
11
  image:
9
12
  repository: {{appName}}-html5-deployer
10
13
  bindings:
14
+ {{#hasXsuaa}}
11
15
  xsuaa:
12
16
  serviceInstanceName: xsuaa
17
+ {{/hasXsuaa}}
18
+ {{#hasIas}}
19
+ ias:
20
+ serviceInstanceName: identity
21
+ parameters:
22
+ credential-type: X509_GENERATED
23
+ {{/hasIas}}
13
24
  destination:
14
25
  serviceInstanceName: destination
15
26
  html5-apps-repo:
@@ -26,7 +37,7 @@ html5-apps-deployer:
26
37
  - configMapRef:
27
38
  name: "{{ .Release.Name }}-html5-apps-deployer-configmap"
28
39
  <%={{ }}=%>
29
- backendDestinations:
40
+ backendDestinations:
30
41
  srv-api:
31
42
  service: srv
32
43
  destination: