@sap/cds-dk 8.2.2 → 8.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/bin/cds.js +10 -9
  3. package/bin/compile/index.js +6 -2
  4. package/bin/deploy/index.js +22 -3
  5. package/bin/import.js +24 -14
  6. package/bin/repl.js +21 -8
  7. package/bin/util/fuzzySearch.js +8 -5
  8. package/bin/watch.js +1 -1
  9. package/lib/build/plugins/helm/files/subcharts/content-deployment/Chart.yaml +1 -1
  10. package/lib/build/plugins/helm/files/subcharts/content-deployment/values.schema.json +1 -1
  11. package/lib/build/plugins/helm/files/subcharts/content-deployment/values.yaml +1 -1
  12. package/lib/build/plugins/helm/files/subcharts/web-application/Chart.yaml +1 -1
  13. package/lib/build/plugins/helm/files/subcharts/web-application/templates/virtual-service.yaml +23 -12
  14. package/lib/build/plugins/helm/files/subcharts/web-application/values.schema.json +1 -1
  15. package/lib/build/plugins/helm/files/subcharts/web-application/values.yaml +2 -2
  16. package/lib/compile/to-mermaid.js +87 -0
  17. package/lib/import/common.js +40 -17
  18. package/lib/import/importapi.js +3 -3
  19. package/lib/import/openapi/importOpenAPI.js +42 -4
  20. package/lib/init/merge.js +2 -2
  21. package/lib/init/mvn.js +2 -2
  22. package/lib/init/projectReader.js +3 -1
  23. package/lib/init/registries/xs-app.js +10 -0
  24. package/lib/init/template/cf-manifest/index.js +2 -0
  25. package/lib/init/template/cloud-logging/files/mta.yaml.hbs +13 -2
  26. package/lib/init/template/cloud-logging/files/{package.json → package.json.hbs} +5 -1
  27. package/lib/init/template/cloud-logging/index.js +4 -3
  28. package/lib/init/template/data/as-csv.js +6 -0
  29. package/lib/init/template/data/as-json.js +8 -1
  30. package/lib/init/template/data/index.js +1 -1
  31. package/lib/init/template/destination/files/mta.yaml.hbs +5 -5
  32. package/lib/init/template/dynatrace/files/mta.yaml.hbs +22 -6
  33. package/lib/init/template/dynatrace/files/package.json.hbs +5 -2
  34. package/lib/init/template/dynatrace/files/values.yaml +15 -0
  35. package/lib/init/template/dynatrace/index.js +10 -5
  36. package/lib/init/template/handler/index.js +16 -1
  37. package/lib/init/template/helm/files/values.yaml.hbs +2 -2
  38. package/lib/init/template/helm/index.js +6 -1
  39. package/lib/init/template/html5-repo/files/app-package.json.hbs +3 -1
  40. package/lib/init/template/html5-repo/files/ui5-deploy.yaml.hbs +7 -0
  41. package/lib/init/template/html5-repo/index.js +3 -1
  42. package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
  43. package/lib/init/template/mta/index.js +2 -0
  44. package/lib/init/template/typer/index.js +2 -1
  45. package/lib/init/template/workzone-standard/files/manifest.json.hbs +15 -1
  46. package/lib/init/template/workzone-standard/files/mta.yaml.hbs +11 -2
  47. package/lib/init/template/workzone-standard/files/xs-app.json.hbs +18 -0
  48. package/lib/init/template/workzone-standard/index.js +25 -7
  49. package/lib/mtx/auth_manager.js +7 -5
  50. package/lib/mtx/util/errors.js +4 -4
  51. package/npm-shrinkwrap.json +53 -44
  52. package/package.json +1 -1
@@ -17,7 +17,7 @@ let optionsMapping = {
17
17
  };
18
18
 
19
19
  let apiOptions = ['includeNamespaces', 'keepNamespace', 'beta'];
20
- let commonOptions = ['no_copy', 'no_save', 'out', 'dry', 'as', 'from', 'force', 'config', 'destination'];
20
+ let commonOptions = ['no_copy', 'no_save', 'out', 'dry', 'as', 'from', 'force', 'config', 'destination', 'name'];
21
21
 
22
22
  async function generateEDMX2JSON(edmx) {
23
23
  let cjson = convert.xml2json(edmx, {
@@ -176,7 +176,7 @@ async function processOptions(cliOptions, options) {
176
176
  options[item] = cliOptions[item];
177
177
  }
178
178
  });
179
-
179
+
180
180
  // reads cli options from environment
181
181
  readEnvVariables(cliOptions, true);
182
182
  }
@@ -312,10 +312,10 @@ async function _write(result, service, cwd) {
312
312
  extension = dest.substring(dest.lastIndexOf('.'));
313
313
  dest = dest.replace(extension, '');
314
314
  if (service.length > 1){
315
- using = `using { ${service.join(', ')}} from './${path.relative('srv', dest).replace(/\\/g, '/')}'`;
315
+ using = `using { ${service.join(', ')}} from './${path.relative(cds.env.folders.srv, dest).replace(/\\/g, '/')}'`;
316
316
  }
317
317
  else{
318
- using = `using { ${service} as external } from './${path.relative('srv', dest).replace(/\\/g, '/')}'`;
318
+ using = `using { ${service} as external } from './${path.relative(cds.env.folders.srv, dest).replace(/\\/g, '/')}'`;
319
319
  }
320
320
  using = require('../util/term').info(using);
321
321
  message = `[cds] - imported API to ${path.relative(cwd, dest)}
@@ -327,21 +327,36 @@ ${using}
327
327
  console.log(message);
328
328
  }
329
329
 
330
- async function _updatePackageJson(dest, services, kind, cwd, config) {
331
- const package_json = path.resolve(cwd, 'package.json');
332
- const conf = await exists(package_json) ? require(package_json) : {};
330
+ async function _updatePackageJson(dest, services, kind, cwd, config, destination) {
331
+ // try to find package.json in the srv folder
332
+ let package_json = _findPackageJson(path.resolve(cwd, dest), cwd);
333
+ let conf = {};
334
+ if (package_json) {
335
+ conf = JSON.parse(await read(package_json, "utf-8"));
336
+ } else {
337
+ package_json = path.resolve(cwd, 'package.json');
338
+ }
333
339
  const requires = ['cds', 'requires'].reduce((p, n) => p[n] || (p[n] = {}), conf);
334
340
  if (kind !== 'rest' && kind !== 'rfc') {
335
341
  kind = (kind === "V2") ? 'odata-v2' : 'odata';
336
342
  }
343
+ // add destination configuration
344
+ if (!config && destination) {
345
+ config = { "[production]": { credentials: { destination } } };
346
+ }
347
+
337
348
  let package_json_updated = false;
338
349
  for (let service of services) {
339
350
  // existing service configuration data can be updated, e.g. in case of delta imports
340
351
  const model = path.relative(cwd, dest).replace(/\\/g, '/'); // cds env must not be platform specific
341
352
  const serviceConfig = { kind, model, ...config }
342
- if (!requires[service] || JSON.stringify(serviceConfig) !== JSON.stringify(requires[service])) {
353
+ if (!requires[service]) {
343
354
  cds.env.requires[service] = requires[service] = serviceConfig;
344
355
  package_json_updated = true;
356
+ } else {
357
+ if (JSON.stringify(serviceConfig) !== JSON.stringify(requires[service])) {
358
+ console.warn(`Service '${service}' already exists in ./package.json with a different configuration, skipping update.\n`);
359
+ }
345
360
  }
346
361
  }
347
362
  if (package_json_updated) {
@@ -350,6 +365,21 @@ async function _updatePackageJson(dest, services, kind, cwd, config) {
350
365
  }
351
366
  }
352
367
 
368
+ function _findPackageJson(dir, cwd) {
369
+ const packageJsonPath = path.join(dir, 'package.json');
370
+ if (fs.existsSync(packageJsonPath)) {
371
+ return packageJsonPath;
372
+ }
373
+ if (dir === cwd) {
374
+ return null;
375
+ }
376
+ const parentDir = path.dirname(dir);
377
+ if (parentDir === dir) {
378
+ return null;
379
+ }
380
+ return _findPackageJson(parentDir, cwd);
381
+ }
382
+
353
383
  function _parseValidJsonConfig(config) {
354
384
  try {
355
385
  if (config) {
@@ -363,19 +393,12 @@ function _parseValidJsonConfig(config) {
363
393
  async function postProcess(filePath, options, csn, cwd) {
364
394
  const services = _getServiceNames(csn);
365
395
  let config = _parseValidJsonConfig(options.config);
366
-
367
- // add destination configuration
368
- if (options.destination) {
369
- config ??= {};
370
- config.credentials = { destination: options.destination };
371
- }
372
-
373
- const destFilePath = path.resolve(cwd, options.out ? path.join(options.out, path.basename(filePath)) : path.join('srv/external/', path.basename(filePath)));
396
+ const destFilePath = path.resolve(cwd, options.out ? path.join(options.out, path.basename(filePath)) : path.join(cds.env.folders.srv, 'external', path.basename(filePath)));
374
397
  if (options.out) options.out = _validateAndComputeOutputFilePath(options.out, options.as, destFilePath);
375
398
  const kind = options.inputFileKind;
376
399
  const result = await _getResult(csn, options.as, options.out || destFilePath.replace(/\.[^.]+$/, ''), options.force, kind);
377
400
  const written = options.dry || await _write(result, services, cwd);
378
- const registered = options.dry || options.no_save || await _updatePackageJson(result[1].replace(/\.[^.]+$/, ''), services, kind, cwd, config);
401
+ const registered = options.dry || options.no_save || await _updatePackageJson(result[1].replace(/\.[^.]+$/, ''), services, kind, cwd, config, options.destination);
379
402
  if (!options.dry && !options.no_copy)
380
403
  await _copyToSrvExternal(filePath, destFilePath, cwd);
381
404
  if (options.dry) return console.log(result[0]);
@@ -7,11 +7,11 @@ let asyncapi = require('./asyncapi');
7
7
  let messages = require('./message').getMessages();
8
8
 
9
9
  module.exports = Object.assign(cds_import, {
10
- from: cds.lazified({
10
+ from: {
11
11
  edmx: cds_import_from_edmx,
12
12
  openapi: cds_import_from_openapi,
13
13
  asyncapi: cds_import_from_asyncapi
14
- })
14
+ }
15
15
  });
16
16
 
17
17
  /**
@@ -95,7 +95,7 @@ async function cds_import_from_openapi(filepath, options = {}) {
95
95
  return csn;
96
96
  }
97
97
 
98
- /**
98
+ /**
99
99
  * This is the import API function to generate CSN from asyncapi files.
100
100
  * @param {string} filepath
101
101
  * - a single valid filepath
@@ -552,14 +552,13 @@ function indirectlyReferencedType(context, subSchema) {
552
552
  }
553
553
 
554
554
  function referencedType(context, ref) {
555
- const expectedPrefix = context.v3
556
- ? "#/components/schemas/"
557
- : "#/definitions/";
555
+ const expectedPrefix = context.v3 ? "#/components/schemas/" : "#/definitions/";
558
556
  if (!ref.startsWith(expectedPrefix)) {
559
557
  throw new Error(`TODO: unexpected reference ${ref} in schema.`);
560
558
  }
561
559
  const schemaName = ref.substring(expectedPrefix.length);
562
560
  const schema = context.schemas[schemaName];
561
+
563
562
  return {
564
563
  name: `${context.serviceName}_types.${cdsName(schemaName)}`,
565
564
  schema,
@@ -633,11 +632,50 @@ function betterType(currentType, schema) {
633
632
  // }
634
633
 
635
634
  function structElements(context, type, schema) {
635
+ checkCircularReference(schema);
636
+ const schemaName = Object.keys(context.schemas).find(key => context.schemas[key] === schema);
637
+ const refPath = `#/components/schemas/${schemaName}`;
636
638
  //TODO: interpret "required"
637
639
  for (const [prop, propSchema] of Object.entries(schema.properties || {})) {
638
640
  const name = cdsName(prop);
641
+ //to detect recursive data types
642
+ if ((propSchema?.$ref === refPath) || (propSchema?.items?.$ref === refPath)) {
643
+ console.warn(`Recursive data type detected: ${schemaName} for the property ${name}`);
644
+ }
639
645
  //TODO: check if property "name" already exists and has identical cdsType, warn otherwise
640
646
  type.elements[name] = cdsType(context, propSchema);
641
647
  if (name !== prop) type.elements[name]["@openapi.name"] = prop;
642
648
  }
643
- }
649
+ }
650
+
651
+ // function to check circular references and throw error if found
652
+ function checkCircularReference(schema, visited = new Set()) {
653
+ if (schema.$ref) {
654
+ const ref = schema.$ref;
655
+ if (visited.has(ref)) {
656
+ console.warn(`Circular reference detected: ${ref}`);
657
+ }
658
+ visited.add(ref);
659
+ }
660
+
661
+ if (schema.allOf) {
662
+ schema.allOf.forEach(subSchema => checkCircularReference(subSchema, visited));
663
+ }
664
+
665
+ if (schema.anyOf) {
666
+ schema.anyOf.forEach(subSchema => checkCircularReference(subSchema, visited));
667
+ }
668
+
669
+ if (schema.oneOf) {
670
+ schema.oneOf.forEach(subSchema => checkCircularReference(subSchema, visited));
671
+ }
672
+
673
+ if (schema.properties) {
674
+ Object.values(schema.properties).forEach(subSchema => checkCircularReference(subSchema, visited));
675
+ }
676
+
677
+ if (schema.items) {
678
+ checkCircularReference(schema.items, visited);
679
+ }
680
+ }
681
+
package/lib/init/merge.js CHANGED
@@ -162,8 +162,8 @@ async function _mergeYAML(into, from, project, semantics = {}) {
162
162
 
163
163
  let collectionStack = [target.contents]
164
164
 
165
- const _getProperty = (object, keyPath) => keyPath.split('.').reduce((p, k) => p && p[k], object)
166
- const _getYAMLProperty = (object, keyPath) => keyPath.split('.').reduce((p, k) => p && p.get(k), object)
165
+ const _getProperty = (object, keyPath) => keyPath.split('.').filter(k => k).reduce((p, k) => p && p[k], object)
166
+ const _getYAMLProperty = (object, keyPath) => keyPath.split('.').filter(k => k).reduce((p, k) => p && p.get(k), object)
167
167
 
168
168
  const _validateWhere = (node, dict, index) => {
169
169
  const _addToMap = entries => entries?.filter(entry => {
package/lib/init/mvn.js CHANGED
@@ -17,8 +17,8 @@ module.exports.add = async function (feature) {
17
17
  if (javaMvn) _scan(javaMvn).forEach(([k,v]) => params.set(k,v))
18
18
  const archetypeVersion = params.get('-DarchetypeVersion') ?? MAVEN_ARCHETYPE_VERSION
19
19
  if (feature === HANA) { // REVISIT: compat for HANA until -Dfeature HANA is provided by Java
20
- params.set(`com.sap.cds:cds-maven-plugin:${archetypeVersion}:addTargetPlatform`)
21
- params.set(`-DtargetPlatform`, `cloudfoundry`) // REVISIT: Should get rid of CF dependency for Kyma scenarios
20
+ params.set(`com.sap.cds:cds-maven-plugin:${archetypeVersion}:add`)
21
+ params.set(`-Dfeature`, `CF`) // REVISIT: Should get rid of CF dependency for Kyma scenarios
22
22
  } else {
23
23
  params.set(`com.sap.cds:cds-maven-plugin:${archetypeVersion}:add`)
24
24
  params.set(`-Dfeature`, feature)
@@ -13,7 +13,7 @@ module.exports = new class ProjectReader {
13
13
 
14
14
  #setPackageInfo() {
15
15
  // 1. Use project name and static default values
16
- this.appVersion = cds.cli.options.add?.has('java') ? '1.0.0-SNAPSHOT' : '1.0.0'
16
+ this.appVersion = cds.cli.options?.add?.has('java') ? '1.0.0-SNAPSHOT' : '1.0.0'
17
17
  this.appName = this.appId = basename(cds.root)
18
18
  this.appDescription = 'A simple CAP project.'
19
19
 
@@ -89,10 +89,12 @@ module.exports = new class ProjectReader {
89
89
  * @property {boolean} hasApprouter Indicates if the project uses the SAP Application Router.
90
90
  * @property {boolean} hasHtml5Repo Indicates if the project uses the SAP BTP HTML5 Application Repository.
91
91
  * @property {boolean} hasPortal Indicates if the project uses the SAP Cloud Portal service.
92
+ * @property {boolean} hasWorkzone Indicates if the project uses the SAP Build Work Zone service.
92
93
  * @property {boolean} hasDestination Indicates if the project uses the SAP BTP Destination service.
93
94
  * @property {boolean} hasMTXRoute Indicates if the approuter should have a multitenant route.
94
95
  * @property {boolean} hasMTXRouteJava Indicates if the approuter should have a multitenant subscription route (java).
95
96
  * @property {boolean} hasMalwareScanner Indicates if the project uses the SAP Malware Scanning service.
97
+ * @property {boolean} hasDynatrace Indicates if the project uses Dynatrace.
96
98
  *
97
99
  */
98
100
 
@@ -0,0 +1,10 @@
1
+
2
+
3
+ const odataApi = {
4
+ in: 'routes',
5
+ where: { target: '/odata/$1' }
6
+ }
7
+
8
+ module.exports = {
9
+ odataApi
10
+ }
@@ -3,6 +3,7 @@ const cds = require('../../../cds')
3
3
  const { exists } = require('../../../cds').utils
4
4
  const { readProject } = require('../../projectReader')
5
5
  const { renderAndCopy } = require('../../template')
6
+ const mvn = require('../../mvn')
6
7
  const MANIFEST_FILE = 'manifest.yml'
7
8
  const SERVICES_MANIFEST_FILE = 'services-manifest.yml'
8
9
 
@@ -29,5 +30,6 @@ module.exports = class CfManifestTemplate extends require('../../plugin') {
29
30
  async run() {
30
31
  const project = readProject()
31
32
  await renderAndCopy(join(__dirname, 'files'), cds.root, project)
33
+ if (project.isJava) await mvn.add('CF')
32
34
  }
33
35
  }
@@ -3,6 +3,17 @@ modules:
3
3
  - name: {{appName}}-srv
4
4
  type: {{language}}
5
5
  path: {{& srvPath}}
6
+ {{#isJava}}
7
+ properties:
8
+ JBP_CONFIG_JAVA_OPTS:
9
+ from_environment: false
10
+ java_opts: >
11
+ -javaagent:META-INF/.sap_java_buildpack/otel_agent/opentelemetry-javaagent.jar
12
+ -Dotel.javaagent.extensions=META-INF/.sap_java_buildpack/otel_agent_extension/otel-agent-ext-java.jar
13
+ OTEL_METRICS_EXPORTER: cloud-logging
14
+ OTEL_TRACES_EXPORTER: cloud-logging
15
+ OTEL_LOGS_EXPORTER: none
16
+ {{/isJava}}
6
17
  requires:
7
18
  - name: {{appName}}-cloud-logging
8
19
  - name: {{appName}}-mtx
@@ -21,5 +32,5 @@ resources:
21
32
  service: cloud-logging
22
33
  service-plan: {{cloudLoggingServicePlan}}
23
34
  config:
24
- ingest_otlp:
25
- enabled: true
35
+ ingest_otlp:
36
+ enabled: true
@@ -8,7 +8,11 @@
8
8
  },
9
9
  "cds": {
10
10
  "requires": {
11
- "telemetry": "to-cloud-logging"
11
+ "[{{profile}}]": {
12
+ "telemetry": {
13
+ "kind": "to-cloud-logging"
14
+ }
15
+ }
12
16
  }
13
17
  }
14
18
  }
@@ -30,9 +30,10 @@ module.exports = class extends require('../../plugin') {
30
30
  }
31
31
 
32
32
  async run() {
33
- const { hasTelemetry } = readProject()
34
- if (cds.cli.options['with-telemetry'] || hasTelemetry) {
35
- await merge(__dirname, 'files/package.json').into('package.json')
33
+ const project = readProject(), { hasTelemetry, isNodejs } = project
34
+ if (isNodejs && (cds.cli.options['with-telemetry'] || hasTelemetry)) {
35
+ project.profile ??= 'production'
36
+ await merge(__dirname, 'files/package.json.hbs').into('package.json', { with: project })
36
37
  await sort('package.json', 'dependencies')
37
38
  }
38
39
  }
@@ -39,6 +39,12 @@ module.exports = async (data={}, csn, { headerOnly=false, separator=',' }={}) =>
39
39
  }
40
40
  record.push(...Object.values(value))
41
41
  }
42
+ else if (element.is_struct) {
43
+ if (i === 0) {
44
+ header.push(...Object.keys(value).map(structField => name + '_' + structField))
45
+ }
46
+ record.push(...Object.values(value))
47
+ }
42
48
  else {
43
49
  if (i === 0) header.push(name)
44
50
  if (Array.isArray(value)) { // `array of` / `many`
@@ -121,9 +121,16 @@ function dataForField(element, entity, csn, record, data, parentEntity, depth, r
121
121
  else if (element.items?.type) // `array of` / `many` with simple type
122
122
  return [ dataForField(element.items, entity, csn, record, data, null, depth+1, referenceData) ]
123
123
 
124
+ if (element.is_struct) {
125
+ let struct = {}
126
+ for (const el of element.elements) {
127
+ struct[el.name] = dataForField(el, entity, csn, record, data, null, depth+1, referenceData)
128
+ }
129
+ return struct
130
+ }
131
+
124
132
  const type = element._type || element.type
125
133
  switch (type) {
126
- case undefined: return
127
134
  case 'cds.Time':
128
135
  return '22:59:53'
129
136
 
@@ -67,7 +67,7 @@ module.exports = class DataTemplate extends require('../../plugin') {
67
67
  : getDefaultTargetFolder(env)
68
68
  dest = resolve(cds.root, dest)
69
69
 
70
- let csn = await cds.load(cds.env.roots) // normal CSN
70
+ let csn = await cds.load([cds.env.roots, join(`${cds.env.folders.srv}`, `external`) ]) // normal CSN. Default paths and models imported with `cds import`
71
71
  // Skip of unused reuse entities like Language, Country, Currency
72
72
  csn = cds.minify(csn)
73
73
  csn = cds.reflect(csn) // reflected model (adds additional helper functions)
@@ -31,14 +31,14 @@ resources:
31
31
  destinations:
32
32
  - Name: {{appName}}-srv-api
33
33
  URL: ~{srv-api/srv-url}
34
- Authentication: OAuth2UserTokenExchange
34
+ Authentication: NoAuthentication
35
35
  Type: HTTP
36
36
  ProxyType: Internet
37
37
  HTML5.ForwardAuthToken: true
38
38
  HTML5.DynamicDestination: true
39
- - Authentication: NoAuthentication
40
- Name: ui5
41
- ProxyType: Internet
42
- Type: HTTP
39
+ - Name: ui5
43
40
  URL: https://ui5.sap.com
41
+ Authentication: NoAuthentication
42
+ Type: HTTP
43
+ ProxyType: Internet
44
44
  {{/hasHtml5Repo}}
@@ -3,8 +3,28 @@ modules:
3
3
  - name: {{appName}}-srv
4
4
  type: {{language}}
5
5
  path: {{& srvPath}}
6
+ {{#isJava}}
7
+ properties:
8
+ JBP_CONFIG_JAVA_OPTS:
9
+ from_environment: false
10
+ java_opts: >
11
+ -javaagent:META-INF/.sap_java_buildpack/otel_agent/opentelemetry-javaagent.jar
12
+ -Dotel.javaagent.extensions=META-INF/.sap_java_buildpack/otel_agent_extension/otel-agent-ext-java.jar
13
+ -Dotel.javaagent.extension.sap.cf.binding.dynatrace.metrics.token-name=ingest_apitoken
14
+ OTEL_METRICS_EXPORTER: dynatrace
15
+ OTEL_TRACES_EXPORTER: none
16
+ OTEL_LOGS_EXPORTER: none
17
+ {{/isJava}}
6
18
  requires:
7
19
  - name: {{appName}}-dynatrace
20
+ parameters:
21
+ config:
22
+ tokens:
23
+ - name: ingest_apitoken
24
+ scopes:
25
+ - openTelemetryTrace.ingest
26
+ - metrics.ingest
27
+
8
28
  - name: {{appName}}-mtx
9
29
  type: nodejs
10
30
  path: {{#isNodejs}}gen/{{/isNodejs}}mtx/sidecar
@@ -15,10 +35,6 @@ resources:
15
35
  type: org.cloudfoundry.managed-service
16
36
  parameters:
17
37
  service: dynatrace
18
- service-plan: standard
38
+ service-plan: environment
19
39
  config:
20
- tokens:
21
- - name: ingest_apitoken
22
- scopes:
23
- - openTelemetryTrace.ingest
24
- - metrics.ingest
40
+ environment_name: {{appName}}
@@ -2,13 +2,16 @@
2
2
  "dependencies": {
3
3
  "@cap-js/telemetry": ">=0",
4
4
  "@opentelemetry/exporter-metrics-otlp-proto": "^0"{{#hasHelm}},
5
- "@opentelemetry/exporter-trace-otlp-proto": "^0",
6
5
  "@opentelemetry/host-metrics": "^0"
7
6
  {{/hasHelm}}
8
7
  },
9
8
  "cds": {
10
9
  "requires": {
11
- "telemetry": "to-dynatrace"
10
+ "[{{profile}}]": {
11
+ "telemetry": {
12
+ "kind": "to-dynatrace"
13
+ }
14
+ }
12
15
  }
13
16
  }
14
17
  }
@@ -0,0 +1,15 @@
1
+ srv:
2
+ bindings:
3
+ dynatrace:
4
+ serviceInstanceName: dynatrace
5
+ parameters:
6
+ tokens:
7
+ - name: ingest_apitoken
8
+ scopes:
9
+ - openTelemetryTrace.ingest
10
+ - metrics.ingest
11
+ dynatrace:
12
+ serviceOfferingName: dynatrace
13
+ servicePlanName: environment
14
+ parameters:
15
+ environment_name: DYNATRACE # (Mandatory) maximum of 16 characters and can only comprise of uppercase letters and digits.
@@ -10,20 +10,21 @@ module.exports = class extends require('../../plugin') {
10
10
  }
11
11
 
12
12
  async canRun() {
13
- const { hasMta, hasHelm, hasHelmUnifiedRuntime } = readProject()
14
- if ((hasHelmUnifiedRuntime || hasHelm) && !hasMta) throw `'cds add dynatrace' is not available for Kyma yet`
15
13
  return true
16
14
  }
17
15
 
18
16
  async run() {
19
17
  const project = readProject()
20
- await merge(__dirname, 'files/package.json.hbs').into('package.json', { with: project })
21
- await sort('package.json', 'dependencies')
18
+ if (project.isNodejs) {
19
+ project.profile ??= 'production'
20
+ await merge(__dirname, 'files/package.json.hbs').into('package.json', { with: project })
21
+ await sort('package.json', 'dependencies')
22
+ }
22
23
  }
23
24
 
24
25
  async combine() {
25
26
  const project = readProject()
26
- const { hasMta, isJava, hasMultitenancy, srvPath } = project
27
+ const { hasMta, hasHelm, hasHelmUnifiedRuntime, isJava, hasMultitenancy, srvPath } = project
27
28
 
28
29
  if (hasMta) {
29
30
  const dynatrace = {
@@ -51,5 +52,9 @@ module.exports = class extends require('../../plugin') {
51
52
  with: project, additions, relationships
52
53
  })
53
54
  }
55
+
56
+ if (hasHelm || hasHelmUnifiedRuntime) {
57
+ await merge(__dirname, 'files', 'values.yaml').into('chart/values.yaml')
58
+ }
54
59
  }
55
60
  }
@@ -5,7 +5,22 @@ const mvn = require('../../mvn')
5
5
  module.exports = class Handler extends require('../../plugin') {
6
6
 
7
7
  static help() {
8
- return 'add handler stubs'
8
+ return 'add handler stubs for actions and functions (Java)'
9
+ }
10
+
11
+ options() {
12
+ return {
13
+ 'filter': {
14
+ type: 'string',
15
+ short: 'f',
16
+ help: `Filter actions or functions by name prefix. Regular expressions are not supported.`
17
+ },
18
+ 'out': {
19
+ type: 'string',
20
+ short: 'o',
21
+ help: 'Specify a custom output directory inside the `handlers` directory. The default is `handlers`.'
22
+ }
23
+ }
9
24
  }
10
25
 
11
26
  canRun() {
@@ -26,6 +26,6 @@ srv:
26
26
  memory: {{#isJava}}1G{{/isJava}}{{^isJava}}500M{{/isJava}}
27
27
  health:
28
28
  liveness:
29
- path: {{#isJava}}/actuator/health{{/isJava}}{{^isJava}}/health{{/isJava}}
29
+ path: {{#isJava}}/actuator/health/liveness{{/isJava}}{{^isJava}}/health{{/isJava}}
30
30
  readiness:
31
- path: {{#isJava}}/actuator/health{{/isJava}}{{^isJava}}/health{{/isJava}}
31
+ path: {{#isJava}}/actuator/health/readiness{{/isJava}}{{^isJava}}/health{{/isJava}}
@@ -5,6 +5,7 @@ const { readProject } = require('../../projectReader')
5
5
  const { merge } = require('../../merge')
6
6
  const { ask4 } = require('../../../util/question')
7
7
  const { execSync } = require('child_process')
8
+ const { mvn } = require('../../add')
8
9
 
9
10
  module.exports = class HelmTemplate extends require('../../plugin') {
10
11
 
@@ -90,10 +91,11 @@ module.exports = class HelmTemplate extends require('../../plugin') {
90
91
  await merge(__dirname, 'files/Chart.yaml.hbs').into('chart/Chart.yaml', { with: project })
91
92
  await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml', { with: project })
92
93
  await this._mergeDependency('web-application', 'srv')
94
+ if (project.isJava) await mvn.add('k8s')
93
95
  }
94
96
 
95
97
  async combine() {
96
- const { hasDestination, hasEnterpriseMessaging, hasEnterpriseMessagingShared, hasHana, hasMultitenancy, hasXsuaa, hasHtml5Repo, hasApprouter, hasKafka, hasAttachments, hasPortal, hasMalwareScanner } = readProject()
98
+ const { hasDestination, hasEnterpriseMessaging, hasEnterpriseMessagingShared, hasHana, hasMultitenancy, hasXsuaa, hasHtml5Repo, hasApprouter, hasKafka, hasAttachments, hasPortal, hasMalwareScanner, hasDynatrace } = readProject()
97
99
 
98
100
  if (hasApprouter) {
99
101
  await this._mergeDependency('web-application', 'approuter')
@@ -140,6 +142,9 @@ module.exports = class HelmTemplate extends require('../../plugin') {
140
142
  if (hasMalwareScanner) {
141
143
  await this._mergeDependency('service-instance', 'malware-scanner')
142
144
  }
145
+ if (hasDynatrace) {
146
+ await this._mergeDependency('service-instance', 'dynatrace')
147
+ }
143
148
  }
144
149
 
145
150
  async _mergeDependency(name, alias) {
@@ -8,11 +8,13 @@
8
8
  "start": "ui5 serve"
9
9
  },
10
10
  "devDependencies": {
11
- "@ui5/cli": "^3",
11
+ {{#hasWorkzone}}"@sap/ui5-builder-webide-extension": "^1.1.9",{{/hasWorkzone}}
12
+ "@ui5/cli": "^4",
12
13
  "ui5-task-zipper": "^3"
13
14
  },
14
15
  "ui5": {
15
16
  "dependencies": [
17
+ {{#hasWorkzone}}"@sap/ui5-builder-webide-extension",{{/hasWorkzone}}
16
18
  "ui5-task-zipper"
17
19
  ]
18
20
  }
@@ -13,6 +13,13 @@ builder:
13
13
  - "/test/**"
14
14
  - "/localService/**"
15
15
  customTasks:
16
+ {{#hasWorkzone}}
17
+ - name: webide-extension-task-updateManifestJson
18
+ afterTask: replaceVersion
19
+ configuration:
20
+ appFolder: webapp
21
+ destDir: dist
22
+ {{/hasWorkzone}}
16
23
  - name: ui5-task-zipper
17
24
  afterTask: generateVersionInfo
18
25
  configuration:
@@ -2,6 +2,7 @@ const { join } = require('path')
2
2
  const { readProject } = require('../../projectReader')
3
3
  const { merge } = require('../../merge')
4
4
  const { srv4, html5RepoHost, html5Runtime, appDeployer, approuter, mtxSidecar4 } = require('../../registries/mta')
5
+ const { odataApi } = require('../../registries/xs-app')
5
6
 
6
7
  module.exports = class Html5RepoTemplate extends require('../../plugin') {
7
8
 
@@ -52,7 +53,8 @@ module.exports = class Html5RepoTemplate extends require('../../plugin') {
52
53
 
53
54
  await Promise.all(apps.map(async ({app}) => {
54
55
  project.app = app
55
- await merge(__dirname, 'files/xs-app.json.hbs').into(join(appPath, app, 'xs-app.json'), { project })
56
+ const additions = [odataApi]
57
+ await merge(__dirname, 'files/xs-app.json.hbs').into(join(appPath, app, 'xs-app.json'), { with: project, additions })
56
58
  }))
57
59
 
58
60
  if (hasMultitenancy) {
@@ -29,7 +29,7 @@ modules:
29
29
  parameters:
30
30
  buildpack: sap_java_buildpack_jakarta
31
31
  readiness-health-check-type: http
32
- readiness-health-check-http-endpoint: /actuator/health
32
+ readiness-health-check-http-endpoint: /actuator/health/readiness
33
33
  properties:
34
34
  SPRING_PROFILES_ACTIVE: cloud,sandbox
35
35
  JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']"