@sap/cds-dk 7.8.1 → 7.9.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 (90) hide show
  1. package/bin/add.js +28 -7
  2. package/bin/bind.js +64 -21
  3. package/bin/build.js +35 -3
  4. package/bin/cds.js +32 -13
  5. package/bin/compile/index.js +44 -3
  6. package/bin/completion/completionFs.js +61 -0
  7. package/bin/completion/index.js +212 -0
  8. package/bin/completion/scripts/cds-bash.sh +17 -0
  9. package/bin/completion/scripts/cds-ps.ps1 +18 -0
  10. package/bin/completion/scripts/cds-zsh.sh +12 -0
  11. package/bin/help.js +8 -2
  12. package/bin/init.js +34 -4
  13. package/bin/subscribe.js +5 -1
  14. package/bin/watch.js +4 -2
  15. package/lib/bind/KubernetesApiAccessor.js +3 -2
  16. package/lib/bind/bindingResolver.js +3 -2
  17. package/lib/bind/bindingUtil.js +10 -8
  18. package/lib/bind/cfKeyProvider.js +58 -153
  19. package/lib/bind/index.js +46 -36
  20. package/lib/bind/kubernetesCredentialsProvider.js +6 -5
  21. package/lib/bind/userCdsrcJsonStorageProvider.js +25 -3
  22. package/lib/build/buildTaskEngine.js +1 -1
  23. package/lib/build/provider/hana/index.js +1 -1
  24. package/lib/build/provider/hana/template/undeploy.json +3 -1
  25. package/lib/build/provider/nodejs/index.js +1 -1
  26. package/lib/compile/openapi/csdl2openapi.js +4 -0
  27. package/lib/compile/openapi/index.js +5 -0
  28. package/lib/deploy/to-hana/hana.js +25 -7
  29. package/lib/env/schemas/cds-rc.js +29 -2
  30. package/lib/import/odata/v4parser.js +78 -25
  31. package/lib/init/constants.js +2 -1
  32. package/lib/init/index.js +18 -13
  33. package/lib/init/merge.js +1 -0
  34. package/lib/init/mvn.js +8 -47
  35. package/lib/init/plugin.js +0 -4
  36. package/lib/init/projectReader.js +17 -10
  37. package/lib/init/template/approuter/files/values.yaml.hbs +6 -12
  38. package/lib/init/template/approuter/index.js +1 -7
  39. package/lib/init/template/completion/completionSetup.js +184 -0
  40. package/lib/init/template/completion/index.js +22 -0
  41. package/lib/init/template/data/as-csv.js +25 -17
  42. package/lib/init/template/data/as-json.js +115 -30
  43. package/lib/init/template/data/index.js +28 -15
  44. package/lib/init/template/hana/files/undeploy.json +2 -1
  45. package/lib/init/template/helm/files/chart/values.schema.json +1 -1
  46. package/lib/init/template/helm/files/content-deployment/Chart.yaml +0 -2
  47. package/lib/init/template/helm/files/content-deployment/values.schema.json +0 -1
  48. package/lib/init/template/helm/files/service-instance/Chart.yaml +0 -2
  49. package/lib/init/template/helm/files/service-instance/values.schema.json +0 -1
  50. package/lib/init/template/helm/files/web-application/Chart.yaml +1 -3
  51. package/lib/init/template/helm/files/web-application/templates/_helpers.tpl +23 -0
  52. package/lib/init/template/helm/files/web-application/templates/deployment.yaml +3 -29
  53. package/lib/init/template/helm/files/web-application/values.schema.json +17 -2
  54. package/lib/init/template/helm/files/web-application/values.yaml +10 -2
  55. package/lib/init/template/helm-unified-runtime/files/templates/NOTES.txt +2 -0
  56. package/lib/init/template/helm-unified-runtime/files/templates/_deployment_helpers.tpl +10 -2
  57. package/lib/init/template/helm-unified-runtime/files/values.schema.json +1 -1
  58. package/lib/init/template/http/index.js +150 -104
  59. package/lib/init/template/kafka/index.js +6 -0
  60. package/lib/init/template/lint/index.js +12 -13
  61. package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
  62. package/lib/init/template/multitenancy/files/mtxs-configmap-java.yaml +1 -1
  63. package/lib/init/template/multitenancy/files/values.yaml.hbs +0 -5
  64. package/lib/init/template/multitenancy/index.js +13 -5
  65. package/lib/init/template/nodejs/files/.vscode/settings.json +11 -0
  66. package/lib/init/template/nodejs/files/eslint.config.js +13 -0
  67. package/lib/init/template/nodejs/files/package.json.hbs +3 -1
  68. package/lib/init/template/sample/index.js +18 -20
  69. package/lib/init/template/tiny-sample/index.js +1 -2
  70. package/lib/init/template/typer/index.js +2 -2
  71. package/lib/lint/Linter.js +133 -55
  72. package/lib/lint/checks.js +5 -6
  73. package/lib/lint/io.js +119 -10
  74. package/lib/mtx/auth_manager.js +5 -5
  75. package/lib/mtx/params.js +4 -2
  76. package/lib/mtx/settings_manager.js +1 -1
  77. package/lib/mtx/tenant_action.js +12 -2
  78. package/lib/mtx/util/logging.js +10 -4
  79. package/lib/util/axios.js +2 -1
  80. package/lib/util/cf.js +32 -37
  81. package/lib/util/fs.js +1 -1
  82. package/lib/util/git.js +1 -1
  83. package/lib/util/term.js +1 -1
  84. package/{bin → lib/watch}/watched.js +2 -2
  85. package/npm-shrinkwrap.json +317 -293
  86. package/package.json +2 -2
  87. package/lib/init/template/approuter/files/approuter-mtxs-configmap.yaml +0 -19
  88. package/lib/init/template/nodejs/files/.eslintrc +0 -26
  89. /package/lib/init/template/{approuter/files/mtxs-configmap-java.yaml → multitenancy/files/mtxs-configmap-java-approuter.yaml} +0 -0
  90. /package/lib/init/template/{approuter/files/mtxs-configmap-nodejs.yaml → multitenancy/files/mtxs-configmap-nodejs-approuter.yaml} +0 -0
@@ -1,6 +1,6 @@
1
1
  module.exports = {
2
2
  title: "JSON schema for CDS-DK configuration",
3
- $schema: "https://json-schema.org/draft/2020-12/schema",
3
+ $schema: "https://json-schema.org/draft-07/schema",
4
4
  description: "Build overlay",
5
5
  $defs: {
6
6
  cdsRoot: {
@@ -8,22 +8,25 @@ module.exports = {
8
8
  // declaration for schema node for cds plugins contributing cds configuration
9
9
  schema: {
10
10
  type: "object",
11
+ default: {},
11
12
  description: "Schema declaration for cds plugins contributing cds configuration",
12
13
  additionalProperties: false,
13
14
  properties: {
14
15
  cds: {
15
16
  type: "object",
17
+ default: {},
16
18
  description: "Containing json schema declarations for root level entries under cds node.",
17
19
  patternProperties: {
18
20
  // new keyword must start with word character or opening brackets
19
21
  "^[\\[\\(\\w].*": {
20
- $ref: "https://json-schema.org/draft/2020-12/schema"
22
+ $ref: "https://json-schema.org/draft-07/schema"
21
23
  }
22
24
  }
23
25
  },
24
26
 
25
27
  buildTaskType: {
26
28
  type: "object",
29
+ default: {},
27
30
  additionalProperties: false,
28
31
  required: ["name"],
29
32
  properties: {
@@ -41,6 +44,7 @@ module.exports = {
41
44
 
42
45
  databaseType: {
43
46
  type: "object",
47
+ default: {},
44
48
  additionalProperties: false,
45
49
  required: ["name"],
46
50
  properties: {
@@ -61,8 +65,16 @@ module.exports = {
61
65
  // build specific schema
62
66
  build: {
63
67
  type: "object",
68
+ default: {},
64
69
  description: "Customize CDS build settings.",
65
70
  additionalProperties: true,
71
+ patternProperties: {
72
+ '\\[.+\\]': {
73
+ default: {},
74
+ description: 'Generic build profile',
75
+ $ref: '#/$defs/cdsRoot/properties/build'
76
+ }
77
+ },
66
78
  properties: {
67
79
  target: {
68
80
  type: "string",
@@ -79,6 +91,13 @@ module.exports = {
79
91
  items: {
80
92
  type: "object",
81
93
  additionalProperties: true,
94
+ patternProperties: {
95
+ '\\[.+\\]': {
96
+ default: {},
97
+ description: 'Generic tasks profile',
98
+ $ref: '#/$defs/cdsRoot/properties/build/properties/tasks/items'
99
+ }
100
+ },
82
101
  properties: {
83
102
  dest: {
84
103
  type: "string",
@@ -115,8 +134,16 @@ module.exports = {
115
134
  // deploy specific schema
116
135
  deploy: {
117
136
  type: "object",
137
+ default: {},
118
138
  description: "Customize 'cds deploy' settings.",
119
139
  additionalProperties: true,
140
+ patternProperties: {
141
+ '\\[.+\\]': {
142
+ default: {},
143
+ description: 'Generic deploy profile',
144
+ $ref: '#/$defs/cdsRoot/properties/deploy'
145
+ }
146
+ },
120
147
  properties: {
121
148
  no_save: {
122
149
  type: "boolean",
@@ -99,7 +99,7 @@ function _initialize(parserContext) {
99
99
  parserContext.primarySchema = "";
100
100
  parserContext.schemaAliasToNamespace = {};
101
101
  parserContext.schemaToSchemaDataIndex = {};
102
- parserContext.vocabAliasToNamespace = {};
102
+ parserContext.vocabNamespaceToAlias = {};
103
103
  parserContext.entityToBoundedActions = {};
104
104
  parserContext.entityToBoundedFunctions = {};
105
105
  parserContext.entityContainerAnnotations = {};
@@ -425,23 +425,62 @@ function _parseAnnotationTerms(annotationTerm, annotationTermObject, csnDefsTarg
425
425
  }
426
426
  }
427
427
 
428
- function _resolveAnotationTerm(schemaDataAnnotation, parserContext) {
429
- // Case 1: We have the Namespace and Alias for the vocabulary
430
- for (const [alias, namespace] of Object.entries(parserContext.vocabAliasToNamespace)) {
431
- if (schemaDataAnnotation.includes('@' + alias + '.')) {
432
- schemaDataAnnotation = schemaDataAnnotation.split('@' + alias + '.').join('@' + known_vocabularies[namespace] + '.');
428
+ function _validateAnnotationNamespace(annotationTerm, vocabNamespaceToAlias) {
429
+ let aliasOrNamespace = annotationTerm.substring(1, annotationTerm.lastIndexOf('.'));
430
+
431
+ for (let alias of Object.values(known_vocabularies)) {
432
+ if (alias === aliasOrNamespace) {
433
+ return;
434
+ }
435
+ }
436
+
437
+ for (let [namespace, alias] of Object.entries(vocabNamespaceToAlias)) {
438
+ if (alias === aliasOrNamespace || namespace === aliasOrNamespace) {
439
+ console.log(warn(annotationTerm + " AnnotationTerm belongs to an unknown namespace: " + namespace));
440
+ return;
441
+ }
442
+ }
443
+
444
+ console.log(warn(annotationTerm + ": Reference of this AnnotationTerm is not present in the edmx file."));
445
+ }
446
+
447
+ function _resolveAnnotationTerm(schemaDataAnnotation, parserContext) {
448
+
449
+ for (const [namespace, alias] of Object.entries(parserContext.vocabNamespaceToAlias)) {
450
+ if (known_vocabularies[namespace]) {
451
+ // Case 1: Namespace belongs to known vocabularies. Replacing the namespace/alias of the doc with standard alias
452
+ if (schemaDataAnnotation.includes('@' + alias + '.')) {
453
+ schemaDataAnnotation = schemaDataAnnotation.split('@' + alias + '.').join('@' + known_vocabularies[namespace] + '.');
454
+ }
455
+ if (schemaDataAnnotation.includes('@' + namespace + '.')) {
456
+ schemaDataAnnotation = schemaDataAnnotation.split('@' + namespace + '.').join('@' + known_vocabularies[namespace] + '.');
457
+ }
458
+ } else {
459
+ // Case 2: Namespace doesn't belong to known vocabularies. Replacing the namespace with alias(if provided) in the doc.
460
+ if (schemaDataAnnotation.includes('@' + namespace + '.') && alias) {
461
+ schemaDataAnnotation = schemaDataAnnotation.split('@' + namespace + '.').join('@' + alias + '.');
462
+ }
433
463
  }
434
464
  }
435
465
  /**
436
- * Case 2: We only have the Namespace for the vocabulary
437
- * Case 3: We don't have the edmx:Reference at all
466
+ * Case 3: Namespace doesn't have edmx:Reference. But it is present in known_vocabularies.
467
+ * Replacing it with standard alias.
438
468
  */
439
- for (const [vocabulary, alias] of Object.entries(known_vocabularies)) {
440
- if (schemaDataAnnotation.includes(vocabulary)) {
441
- schemaDataAnnotation = schemaDataAnnotation.split(vocabulary).join(alias);
469
+ for (const [namespace, alias] of Object.entries(known_vocabularies)) {
470
+ if (schemaDataAnnotation.includes(namespace)) {
471
+ schemaDataAnnotation = schemaDataAnnotation.split(namespace).join(alias);
442
472
  }
443
473
  }
444
474
 
475
+ let index = 0;
476
+ while (schemaDataAnnotation.indexOf('@', index) != -1) {
477
+
478
+ let i = schemaDataAnnotation.indexOf('@', index);
479
+ let annotationTerm = schemaDataAnnotation.substring(i, schemaDataAnnotation.indexOf('"', i));
480
+ _validateAnnotationNamespace(annotationTerm, parserContext.vocabNamespaceToAlias);
481
+ index = i+1;
482
+ }
483
+
445
484
  return JSON.parse(schemaDataAnnotation);
446
485
  }
447
486
 
@@ -459,7 +498,7 @@ function _captureAnnotationWithinElement(sourceObject, targetObject, parserConte
459
498
 
460
499
  Object.keys(sourceObject).forEach(key => {
461
500
  if (key.startsWith('@')) {
462
- element = _resolveAnotationTerm(JSON.stringify(key), parserContext);
501
+ element = _resolveAnnotationTerm(JSON.stringify(key), parserContext);
463
502
  _parseAnnotationTerms(element, sourceObject[key], targetObject, parserContext);
464
503
  }
465
504
  });
@@ -1309,7 +1348,7 @@ function _parseEntityContainer(csnDefs, entityContainerElements, parserContext)
1309
1348
  if (Object.keys(possibleAnnotations).length > 0) {
1310
1349
  let entityContainerAnnotations = {};
1311
1350
  let annotationTarget = parserContext.primarySchema + '.' + parserContext.entityContainerName;
1312
- possibleAnnotations = _resolveAnotationTerm(
1351
+ possibleAnnotations = _resolveAnnotationTerm(
1313
1352
  JSON.stringify(possibleAnnotations), parserContext
1314
1353
  );
1315
1354
  /**
@@ -1447,16 +1486,28 @@ function _collectBoundedActionFunction(isAction, currNamespace, elementName, ele
1447
1486
  for (let i = 0; i < elementDataList.length; i++) {
1448
1487
  let dataObj = elementDataList[i];
1449
1488
  let boundedEntityName = dataObj.$Parameter[0].$Type;
1489
+ let entityTypeNamespace = currNamespace;
1450
1490
  let [schemaName, entityName] = _extractSchemaNameAndElementName(boundedEntityName);
1451
1491
 
1452
- // binding parameter type should be within the current schema only
1453
- if (currNamespace !== schemaName && currNamespace !== parserContext.schemaAliasToNamespace[schemaName]) {
1454
- throw new Error(messages.INVALID_BOUNDED_PARAM_TYPE + ` Check the Element: ${elementName} of Schema: ${currNamespace} `);
1492
+ // binding parameter type should be within the available namespaces in the scope of a document.
1493
+ if (entityTypeNamespace !== schemaName && entityTypeNamespace !== parserContext.schemaAliasToNamespace[schemaName]) {
1494
+
1495
+ // checking if the namespace is available in other schema of the document
1496
+ if (parserContext.schemaToSchemaDataIndex.hasOwnProperty(schemaName)) {
1497
+ entityTypeNamespace = schemaName;
1498
+ }
1499
+ // checking if the alias is present for the schema name and assigning the actual namespace
1500
+ else if (parserContext.schemaAliasToNamespace[schemaName]) {
1501
+ entityTypeNamespace = parserContext.schemaAliasToNamespace[schemaName];
1502
+ } else {
1503
+ throw new Error(messages.INVALID_BOUNDED_PARAM_TYPE + ` Check the Element: ${elementName} of Schema: ${currNamespace} `);
1504
+ }
1455
1505
  }
1456
- if (!parserContext.entityTypes.includes(currNamespace + '.' + entityName)) {
1506
+
1507
+ if (!parserContext.entityTypes.includes(entityTypeNamespace + '.' + entityName)) {
1457
1508
  throw new Error(messages.UNRESOLVED_TYPE + boundedEntityName);
1458
1509
  }
1459
- boundedEntityName = currNamespace + '.' + entityName;
1510
+ boundedEntityName = entityTypeNamespace + '.' + entityName;
1460
1511
 
1461
1512
  if (isAction) {
1462
1513
  if (!parserContext.entityToBoundedActions[boundedEntityName]?.[elementName]) {
@@ -1501,17 +1552,15 @@ function _collectBoundedActionFunction(isAction, currNamespace, elementName, ele
1501
1552
  * @param {Object} parserContext, contains parser level context informations
1502
1553
  */
1503
1554
  function _collectSchemaElements(edmxAsJson, schemaDataList, parserContext) {
1555
+ // This array is used to store the parameter values which will be used later to call _collectBoundedActionFunction.
1556
+ let boundActionFunctionDetails = [];
1504
1557
 
1505
1558
  _collectUnboundedActionFunction(schemaDataList, parserContext);
1506
1559
 
1507
1560
  // capture all the references
1508
1561
  if (edmxAsJson.$Reference) {
1509
1562
  Object.entries(edmxAsJson.$Reference).forEach(ref => {
1510
- if (ref[1].$Include[0].$Alias &&
1511
- known_vocabularies.hasOwnProperty(ref[1].$Include[0].$Namespace)
1512
- ) {
1513
- parserContext.vocabAliasToNamespace[ref[1].$Include[0].$Alias] = ref[1].$Include[0].$Namespace;
1514
- }
1563
+ parserContext.vocabNamespaceToAlias[ref[1].$Include[0].$Namespace] = ref[1].$Include[0].$Alias;
1515
1564
  });
1516
1565
  }
1517
1566
 
@@ -1532,12 +1581,12 @@ function _collectSchemaElements(edmxAsJson, schemaDataList, parserContext) {
1532
1581
  else if (elementData instanceof Array) {
1533
1582
  let isAction = elementData[0].$Kind === 'Action' ? true : false;
1534
1583
  if (elementData[0].$IsBound) {
1535
- _collectBoundedActionFunction(isAction, currNamespace, elementName, elementData, parserContext);
1584
+ boundActionFunctionDetails.push([isAction, currNamespace, elementName, elementData]);
1536
1585
  }
1537
1586
  }
1538
1587
  // annotations
1539
1588
  else if (elementName === '$Annotations') {
1540
- schemaData.$Annotations = _resolveAnotationTerm(JSON.stringify(schemaData.$Annotations), parserContext);
1589
+ schemaData.$Annotations = _resolveAnnotationTerm(JSON.stringify(schemaData.$Annotations), parserContext);
1541
1590
  /**
1542
1591
  * collect entity container annotations with the assumption that
1543
1592
  * we only have a single entity container
@@ -1558,6 +1607,10 @@ function _collectSchemaElements(edmxAsJson, schemaDataList, parserContext) {
1558
1607
  }
1559
1608
  });
1560
1609
  }
1610
+ // This will delay the execution of _collectBoundedActionFunction, as we need to collect all the entityTypes first.
1611
+ boundActionFunctionDetails.forEach(paramValues => {
1612
+ _collectBoundedActionFunction(...paramValues, parserContext);
1613
+ });
1561
1614
  }
1562
1615
 
1563
1616
  function _preProcess(edmxAsJson, parserContext, importerContext) {
@@ -4,7 +4,8 @@ module.exports = {
4
4
  COMMAND_INIT: 'init',
5
5
  COMMAND_ADD: 'add',
6
6
 
7
- MAVEN_ARCHETYPE_VERSION: '2.8.1',
7
+ JAVA_LTS_VERSIONS: [17, 21],
8
+ MAVEN_ARCHETYPE_VERSION: '2.9.0',
8
9
 
9
10
  OPTIONS: Object.freeze({
10
11
  JAVA: 'java',
package/lib/init/index.js CHANGED
@@ -109,7 +109,11 @@ module.exports = class CDSGenerator {
109
109
  this._initialize(null);
110
110
  this._greetings();
111
111
 
112
- if (!PROJECT_FILES.find(exists)) {
112
+ // `add completion` configures global shell completion and not project settings
113
+ // `add data` can live without project metadata
114
+ const nonProjectFacets = { completion:1, data:1 }
115
+ const needsProject = facets.some(facet => !nonProjectFacets[facet])
116
+ if (needsProject && !PROJECT_FILES.find(exists)) {
113
117
  throw `The current folder doesn't seem to contain a project. None of the following files found: ${PROJECT_FILES.join(', ')}.`
114
118
  }
115
119
 
@@ -165,7 +169,7 @@ module.exports = class CDSGenerator {
165
169
  if (cds.cli.options.for && typeof cds.cli.options.for !== 'string') {
166
170
  throw 'The --for argument must not be empty.'
167
171
  }
168
- if (cds.cli.options.force) {
172
+ if (cds.cli.options.force && !cds.cli.options.dry) {
169
173
  console.log(`Using '--force' ... existing files will be overwritten`)
170
174
  }
171
175
  }
@@ -174,10 +178,14 @@ module.exports = class CDSGenerator {
174
178
  DEBUG?.(`Project path: ${cds.root}`);
175
179
 
176
180
  await this._validateOptions();
177
- await this._fillTemplateList(facets);
178
181
 
179
- for (const template of this.templateList) {
180
- console.log(`Adding feature '${template.name}'...`);
182
+ const { command, options } = cds.cli
183
+ const plugins = command === COMMAND_INIT ? options.add : new Set(facets)
184
+ await this._fillTemplateList(plugins)
185
+
186
+ for (const [i, facet] of Object.entries(Array.from(plugins))) {
187
+ if (!cds.cli.options.dry) console.log(`Adding feature '${facet}'...`);
188
+ const template = this.templateList[i]
181
189
  await template.run();
182
190
  await template.combine();
183
191
  await template.combineSupported();
@@ -190,7 +198,7 @@ module.exports = class CDSGenerator {
190
198
  message = message + ` Continue with '${term.bold('cd ' + relativeProjectPath)}'.`
191
199
  }
192
200
  console.log('\n' + message)
193
- } else {
201
+ } else if (!cds.cli.options.dry) {
194
202
  console.log(`\nSuccessfully added features to your project.`)
195
203
  }
196
204
  }
@@ -216,11 +224,8 @@ module.exports = class CDSGenerator {
216
224
  }
217
225
  }
218
226
 
219
- async _fillTemplateList(facets) {
227
+ async _fillTemplateList(plugins) {
220
228
  const templates = new Map
221
- const { command, options } = cds.cli
222
-
223
- const plugins = command === COMMAND_INIT ? options.add : new Set(facets)
224
229
 
225
230
  for (let plugin of plugins) {
226
231
  // Compat
@@ -230,13 +235,13 @@ module.exports = class CDSGenerator {
230
235
  cds.cli.options.add.add('helm-unified-runtime')
231
236
  }
232
237
  if (plugin === 'sample-tiny') plugin = 'tiny-sample'
233
- if (plugin in { 'kibana-logging':1, 'kibana':1 }) plugin = 'application-logging'
238
+ if (plugin in { 'kibana-logging': 1, 'kibana': 1 }) plugin = 'application-logging'
234
239
  if (plugin === 'postgresql') plugin = 'postgres'
235
240
 
236
241
  if (!templates.has(plugin)) {
237
242
  const template = await this._createTemplate(plugin)
238
243
  if (await template.canRun()) {
239
- DEBUG?.(`Adding feature '${template.name}'`)
244
+ DEBUG?.(`Adding feature '${plugin}'`)
240
245
  templates.set(plugin, template)
241
246
  const dependencies = await template.requires()
242
247
  dependencies?.forEach(d => plugins.add(d))
@@ -256,7 +261,7 @@ module.exports = class CDSGenerator {
256
261
  .map((entry) => entry[1])
257
262
 
258
263
  // check debug to avoid lengthy computation when not in debug mode
259
- DEBUG?.(`Features: ${this.templateList.map(({name}) => name).join(', ')}`);
264
+ DEBUG?.(`Features: ${this.templateList.map(({ name }) => name).join(', ')}`);
260
265
  }
261
266
 
262
267
  // CAP Generator API
package/lib/init/merge.js CHANGED
@@ -182,6 +182,7 @@ async function _mergeYAML(into, from, project, semantics = {}) {
182
182
  if (additions) _addToMap(additions)
183
183
  if (deletions) _addToMap(deletions.map(deletion => deletion.item))
184
184
  if (relationships) _addToMap(relationships?.map(({into: [entry]}) => entry).filter(e => e))
185
+ if (overwrites) _addToMap(overwrites.map(overwrite => overwrite.item[0]))
185
186
  }
186
187
 
187
188
  function _traverseYAMLNode(node, index, actions, templateNode) {
package/lib/init/mvn.js CHANGED
@@ -72,40 +72,6 @@ class MvnArchetypeUtil {
72
72
  return this._finalize(params);
73
73
  }
74
74
 
75
- getAddSamplesCmdArgs() {
76
- const params = new Map();
77
-
78
- params.set(`com.sap.cds:cds-maven-plugin:${MAVEN_ARCHETYPE_VERSION}:addSample`);
79
-
80
- const { options } = cds.cli
81
- if (options[JAVA_MVN]) {
82
- this._scanMvnParams(options[JAVA_MVN], params);
83
- }
84
-
85
- if (options.force) {
86
- params.set(`-Doverwrite`, true);
87
- }
88
-
89
- return this._finalize(params);
90
- }
91
-
92
- getAddTestsCmdArgs() {
93
- const params = new Map();
94
-
95
- params.set(`com.sap.cds:cds-maven-plugin:${MAVEN_ARCHETYPE_VERSION}:addIntegrationTest`);
96
-
97
- const { options } = cds.cli
98
- if (options[JAVA_MVN]) {
99
- this._scanMvnParams(options[JAVA_MVN], params);
100
- }
101
-
102
- if (options.force) {
103
- params.set(`-Doverwrite`, true);
104
- }
105
-
106
- return this._finalize(params);
107
- }
108
-
109
75
  getAddHanaCmdArgs() {
110
76
  const params = new Map();
111
77
 
@@ -155,19 +121,14 @@ class MvnArchetypeUtil {
155
121
  } catch (err) {
156
122
  DEBUG?.(err);
157
123
  }
158
- const match = javaVersion?.stderr?.match(/version\s*"?(\d+\.\d+\.\d+)"?/);
159
- if (match?.[1]) {
160
- const segments = match[1]?.split('.');
161
- const version = new Number(segments?.[0]);
162
- switch (true) {
163
- case (version < 17):
164
- if (process.env.WS_BASE_URL) {
165
- throw `Java version ${match[1]} is not supported. Use Java 17 or higher. You can use command 'Java: Set Default JDK' to switch to Java 17.`
166
- }
167
- throw `Java version ${match[1]} is not supported. Use Java 17 or higher.`
168
- case (version < 20): params.set(`-DjdkVersion`, 17); break;
169
- case (version >= 20): params.set(`-DjdkVersion`, 20); break;
170
- default:
124
+ const [,version] = javaVersion?.stderr?.match(/version\s*"?(\d+\.\d+\.\d+)"?/) ?? [];
125
+ if (version) {
126
+ const [major] = version.split('.').map(Number);
127
+ if (major < 17) {
128
+ if (process.env.WS_BASE_URL) {
129
+ throw `Java version ${version} is not supported. Use Java 17 or higher. You can use command 'Java: Set Default JDK' to switch to Java 17.`
130
+ }
131
+ throw `Java version ${version} is not supported. Use Java 17 or higher.`
171
132
  }
172
133
  }
173
134
  }
@@ -6,10 +6,6 @@ const { env4 } = require('./projectReader')
6
6
 
7
7
  module.exports = class Plugin {
8
8
 
9
- constructor() {
10
- this.name = this.constructor.name.replace(/template/i, '').replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
11
- }
12
-
13
9
  /**
14
10
  * Provides command-line options for the plugin.
15
11
  * @returns {Array.<{option: string, flag: string, shortcut?: string, help: string}>}
@@ -2,7 +2,7 @@ const cds = require('../cds')
2
2
  const { join, resolve, basename } = require('path')
3
3
  const { fs, exists, isdir, path } = cds.utils
4
4
  const { parseXml } = require('./xml')
5
- const { REGEX_JAVA_VERSION } = require('./constants')
5
+ const { REGEX_JAVA_VERSION, JAVA_LTS_VERSIONS } = require('./constants')
6
6
  const DEBUG = cds.debug('cli')
7
7
 
8
8
  module.exports = new class ProjectReader {
@@ -15,18 +15,24 @@ module.exports = new class ProjectReader {
15
15
  this.appName = this.appId = basename(cds.root)
16
16
  this.appDescription = 'A simple CAP project.'
17
17
 
18
- // 2. Use either pom.xml or package.json
19
- if (exists('pom.xml')) {
20
- const { artifactId = [], description = [], version = [], properties = [] } = parseXml(resolve(cds.root, 'pom.xml')) ?? {}
21
- const v = version[0] === '${revision}' ? properties[0]?.revision[0] : version[0]
18
+ const isJava = exists('pom.xml') || cds.cli.options?.add?.has('java')
19
+ if (isJava) {
20
+ let artifactId, description, version, properties
21
+ try {
22
+ ({ artifactId, description, version, properties } = parseXml(resolve(cds.root, 'pom.xml')) ?? {})
23
+ } catch (e) {
24
+ if (e.code !== 'ENOENT') throw e
25
+ }
26
+ const v = version?.[0] === '${revision}' ? properties?.[0]?.revision[0] : version?.[0] ?? '1.0.0-SNAPSHOT'
22
27
  if (v && REGEX_JAVA_VERSION.test(v)) this.appVersion = v
23
- if (artifactId[0]) this.appName = this.appId = artifactId[0].split(/-parent/)[0]
24
- if (description[0]) this.appDescription = description[0]
28
+ this.jdkVersion = properties?.[0]?.['jdk.version']?.[0]?._text?.[0] ?? JAVA_LTS_VERSIONS[JAVA_LTS_VERSIONS.length - 1]
29
+ if (artifactId?.[0]) this.appName = this.appId = artifactId?.[0]?.split(/-parent/)[0]
30
+ if (description?.[0]) this.appDescription = description[0]
25
31
  }
26
32
  else if (exists('package.json')) {
27
33
  const { name, version, description } = JSON.parse(fs.readFileSync(join(cds.root, 'package.json')))
28
- this.appVersion = version
29
- const segments = name.trim().replace(/@/g, '').split('/').map(encodeURIComponent)
34
+ this.appVersion = version ?? this.appVersion
35
+ const segments = (name ?? this.appName).trim().replace(/@/g, '').split('/').map(encodeURIComponent)
30
36
  this.appName = segments[segments.length - 1]
31
37
  this.appId = segments.join('.')
32
38
  this.appDescription = description ?? this.appDescription
@@ -90,7 +96,7 @@ module.exports = new class ProjectReader {
90
96
  */
91
97
  readProject() {
92
98
  const env = this.env4('production')
93
- const { appVersion, appName, appId, appDescription } = this
99
+ const { appVersion, appName, appId, appDescription, jdkVersion } = this
94
100
  DEBUG?.({ env })
95
101
 
96
102
  const _inProd = plugin => require(`./template/${plugin}`).hasInProduction(env)
@@ -121,6 +127,7 @@ module.exports = new class ProjectReader {
121
127
  ),
122
128
  appPath: () => env.folders.app,
123
129
  appVersion: () => appVersion,
130
+ jdkVersion: () => jdkVersion,
124
131
  approuterPath: () => join(env.folders.app, 'router'),
125
132
  appName: () => appName,
126
133
  cleanedAppName: () => appName.replaceAll('_', '-'),
@@ -1,20 +1,14 @@
1
1
  ---
2
- {{#hasXsuaa}}
3
- xsuaa:
4
- parameters:
5
- oauth2-configuration:
6
- redirect-uris:
7
- - https://*.<your-cluster-domain>/**
8
- {{/hasXsuaa}}
9
2
  approuter:
10
- {{#hasXsuaa}}
11
- bindings:
12
- auth:
13
- serviceInstanceName: xsuaa
14
- {{/hasXsuaa}}
15
3
  image:
16
4
  repository: <your-container-registry>/{{appName}}-approuter
17
5
  tag: latest
6
+ {{#hasMultitenancy}}
7
+ {{=<% %>=}}
8
+ env:
9
+ TENANT_HOST_PATTERN: ^(.*)-{{ .Release.Name }}-approuter-{{ .Release.Namespace }}.{{ .Values.global.domain }} # change if expose.host is set
10
+ <%={{ }}=%>
11
+ {{/hasMultitenancy}}
18
12
  resources:
19
13
  limits:
20
14
  ephemeral-storage: 1G
@@ -63,13 +63,7 @@ module.exports = class ApprouterTemplate extends require('../../plugin') {
63
63
  }
64
64
  }]}}).into('chart/values.yaml', { with: project })
65
65
 
66
- const fileName = hasMultitenancy ? 'approuter-mtxs-configmap.yaml' : 'approuter-configmap.yaml'
67
- await copy(join(__dirname, 'files', fileName)).to('chart', 'templates', 'approuter-configmap.yaml')
68
-
69
- if (hasMultitenancy) {
70
- const mtxsConfigMapFileName = isNodejs ? 'mtxs-configmap-nodejs.yaml' : 'mtxs-configmap-java.yaml'
71
- await copy(join(__dirname, 'files', mtxsConfigMapFileName)).to('chart', 'templates', 'mtxs-configmap.yaml')
72
- }
66
+ await copy(join(__dirname, 'files/approuter-configmap.yaml')).to('chart', 'templates', 'approuter-configmap.yaml')
73
67
  }
74
68
 
75
69
  const xsAppPath = join(approuterPath, 'xs-app.json')