@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.
- package/CHANGELOG.md +38 -0
- package/bin/cds.js +10 -9
- package/bin/compile/index.js +6 -2
- package/bin/deploy/index.js +22 -3
- package/bin/import.js +24 -14
- package/bin/repl.js +21 -8
- package/bin/util/fuzzySearch.js +8 -5
- package/bin/watch.js +1 -1
- package/lib/build/plugins/helm/files/subcharts/content-deployment/Chart.yaml +1 -1
- package/lib/build/plugins/helm/files/subcharts/content-deployment/values.schema.json +1 -1
- package/lib/build/plugins/helm/files/subcharts/content-deployment/values.yaml +1 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/Chart.yaml +1 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/templates/virtual-service.yaml +23 -12
- package/lib/build/plugins/helm/files/subcharts/web-application/values.schema.json +1 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/values.yaml +2 -2
- package/lib/compile/to-mermaid.js +87 -0
- package/lib/import/common.js +40 -17
- package/lib/import/importapi.js +3 -3
- package/lib/import/openapi/importOpenAPI.js +42 -4
- package/lib/init/merge.js +2 -2
- package/lib/init/mvn.js +2 -2
- package/lib/init/projectReader.js +3 -1
- package/lib/init/registries/xs-app.js +10 -0
- package/lib/init/template/cf-manifest/index.js +2 -0
- package/lib/init/template/cloud-logging/files/mta.yaml.hbs +13 -2
- package/lib/init/template/cloud-logging/files/{package.json → package.json.hbs} +5 -1
- package/lib/init/template/cloud-logging/index.js +4 -3
- package/lib/init/template/data/as-csv.js +6 -0
- package/lib/init/template/data/as-json.js +8 -1
- package/lib/init/template/data/index.js +1 -1
- package/lib/init/template/destination/files/mta.yaml.hbs +5 -5
- package/lib/init/template/dynatrace/files/mta.yaml.hbs +22 -6
- package/lib/init/template/dynatrace/files/package.json.hbs +5 -2
- package/lib/init/template/dynatrace/files/values.yaml +15 -0
- package/lib/init/template/dynatrace/index.js +10 -5
- package/lib/init/template/handler/index.js +16 -1
- package/lib/init/template/helm/files/values.yaml.hbs +2 -2
- package/lib/init/template/helm/index.js +6 -1
- package/lib/init/template/html5-repo/files/app-package.json.hbs +3 -1
- package/lib/init/template/html5-repo/files/ui5-deploy.yaml.hbs +7 -0
- package/lib/init/template/html5-repo/index.js +3 -1
- package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
- package/lib/init/template/mta/index.js +2 -0
- package/lib/init/template/typer/index.js +2 -1
- package/lib/init/template/workzone-standard/files/manifest.json.hbs +15 -1
- package/lib/init/template/workzone-standard/files/mta.yaml.hbs +11 -2
- package/lib/init/template/workzone-standard/files/xs-app.json.hbs +18 -0
- package/lib/init/template/workzone-standard/index.js +25 -7
- package/lib/mtx/auth_manager.js +7 -5
- package/lib/mtx/util/errors.js +4 -4
- package/npm-shrinkwrap.json +53 -44
- package/package.json +1 -1
package/lib/import/common.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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
|
-
|
|
332
|
-
|
|
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]
|
|
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]);
|
package/lib/import/importapi.js
CHANGED
|
@@ -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:
|
|
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}:
|
|
21
|
-
params.set(`-
|
|
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
|
|
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
|
|
|
@@ -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
|
-
|
|
25
|
-
|
|
35
|
+
ingest_otlp:
|
|
36
|
+
enabled: true
|
|
@@ -30,9 +30,10 @@ module.exports = class extends require('../../plugin') {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
async run() {
|
|
33
|
-
const { hasTelemetry } =
|
|
34
|
-
if (cds.cli.options['with-telemetry'] || hasTelemetry) {
|
|
35
|
-
|
|
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:
|
|
34
|
+
Authentication: NoAuthentication
|
|
35
35
|
Type: HTTP
|
|
36
36
|
ProxyType: Internet
|
|
37
37
|
HTML5.ForwardAuthToken: true
|
|
38
38
|
HTML5.DynamicDestination: true
|
|
39
|
-
-
|
|
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:
|
|
38
|
+
service-plan: environment
|
|
19
39
|
config:
|
|
20
|
-
|
|
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
|
-
"
|
|
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
|
-
|
|
21
|
-
|
|
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
|
|
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
|
-
|
|
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']"
|