@sap/cds-dk 9.3.0 → 9.3.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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,21 @@ This project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  The format is based on [Keep a Changelog](https://keepachangelog.com/).
8
8
 
9
+ ## Version 9.3.1 - 2025-09-08
10
+
11
+ ### Fixed
12
+
13
+ - `cds add ias` correctly sets the `subscription-manager` dependencies endpoint for Node.js.
14
+ - `cds add data --records` respects the max length of a string field when it is annotated with `@Communication.IsEmailAddress`
15
+ - `cds add data --records --format csv` correctly escaping complex properties nested within structs.
16
+ - `cds add data --records` correctly generates values for structs in cases when the entity and the struct, used by the entity, have both a property with the same name.
17
+ - `cds add html5-repo` also binds the `html5-repo-host` service to the approuter.
18
+ - `cds up` has improved support for setups with multiple microservices.
19
+ - `cds add mta` will add no `role-collections` parameters if there are some specified in `xs-security.json`.
20
+ - `cds add github-actions` correctly generates a release workflow.
21
+ - `cds add github-actions` uses a simplified and more resilient Kyma setup script.
22
+ - `cds import` now correctly imports EDMX files with empty NavigationPropertyPath tags.
23
+
9
24
  ## Version 9.3.0 - 2025-09-01
10
25
 
11
26
  ### Added
@@ -23,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
23
38
 
24
39
  ### Fixed
25
40
 
41
+ - `cds add workzone` with missing `sap.app` config in `manifest.json` does not throw a `TypeError`.
26
42
  - `cds add ias` adds a subdomain-less application URL in `redirect_uris`.
27
43
 
28
44
  ## Version 9.2.1 - 2025-08-22
package/bin/up.js CHANGED
@@ -67,7 +67,8 @@ const runDetectingError = async (cmd, errorRegex) => {
67
67
  }
68
68
 
69
69
  async function up() {
70
- const { apps, appName, hasApprouter, hasXsuaa } = readProject()
70
+ const project = readProject()
71
+ const { apps, appName, hasApprouter, hasXsuaa, isMonorepoMicroservice } = project
71
72
 
72
73
  for (const { app } of apps) {
73
74
  const appPath = path.join(cds.root, cds.env.folders.app, app)
@@ -104,11 +105,12 @@ async function up() {
104
105
  run('npm i --package-lock-only')
105
106
  }
106
107
  }
107
- const prefix = execSync('npm prefix', { encoding: 'utf8' }).trim()
108
- if (prefix !== cds.root) {
109
- const source = path.join(prefix, 'package-lock.json')
108
+
109
+ if (isMonorepoMicroservice) {
110
+ const { npmWorkspaceRoot } = project
111
+ const source = path.join(npmWorkspaceRoot, 'package-lock.json')
110
112
  const target = path.join(process.cwd(), 'package-lock.json')
111
- if (exists(target) || fs.lstatSync(target).isSymbolicLink()) fs.unlinkSync(target)
113
+ if (exists(target) && fs.lstatSync(target).isSymbolicLink()) fs.unlinkSync(target)
112
114
  const relative = path.relative(process.cwd(), source)
113
115
  fs.symlinkSync(relative, target, 'junction')
114
116
  }
@@ -1620,6 +1620,11 @@ class PropertyPathExpression extends Expression {
1620
1620
  const targetOption = this.getContext().getConverterOptions().target;
1621
1621
  if (targetOption === MetadataConverter.TARGETS.LIBRARY) {
1622
1622
  target = { [this._targetName]: this.getElement().elements[0].text };
1623
+ } else if (!this.getElement().elements && this._targetName === '$NavigationPropertyPath') {
1624
+ //elements are not given, when <NavigationPropertyPath/> is in EDMX, which is used to refresh the current context
1625
+ return {
1626
+ "=": "($self)"
1627
+ };
1623
1628
  } else {
1624
1629
  target = this.getElement().elements[0].text;
1625
1630
  }
@@ -5,7 +5,7 @@ module.exports = {
5
5
  COMMAND_ADD: 'add',
6
6
 
7
7
  JAVA_LTS_VERSIONS: [17, 21],
8
- MAVEN_ARCHETYPE_VERSION: '4.2.0',
8
+ MAVEN_ARCHETYPE_VERSION: '4.3.0',
9
9
 
10
10
  OPTIONS: Object.freeze({
11
11
  COMPLETION: 'completion',
@@ -1,5 +1,6 @@
1
1
  const cds = require('../cds')
2
- const { join, resolve, basename } = require('path')
2
+ const { join, resolve, basename } = require('node:path')
3
+ const { execSync } = require('node:child_process')
3
4
  const { fs, exists, isfile, isdir, path } = cds.utils
4
5
  const { parseXml } = require('./xml')
5
6
  const { REGEX_JAVA_VERSION, JAVA_LTS_VERSIONS } = require('./constants')
@@ -9,6 +10,7 @@ module.exports = new class ProjectReader {
9
10
 
10
11
  constructor() {
11
12
  this.readProject = this.readProject.bind(this)
13
+ this.cachedWorkspaceRoot = null
12
14
  }
13
15
 
14
16
  #setPackageInfo() {
@@ -105,6 +107,9 @@ module.exports = new class ProjectReader {
105
107
  * @property {boolean} hasDynatrace Indicates if the project uses Dynatrace.
106
108
  * @property {boolean} hasCloudLogging Indicates if the project uses Cloud Logging.
107
109
  * @property {String} extendsApp Indicates which project is extended if any.
110
+ * @property {String} githubSlug GitHub org/repo.
111
+ * @property {boolean} isMonorepoMicroservice Indicates if the project is a monorepo microservice.
112
+ * @property {String} npmWorkspaceRoot The root path of the monorepo workspace.
108
113
  */
109
114
 
110
115
  /**
@@ -198,7 +203,16 @@ module.exports = new class ProjectReader {
198
203
  sap: () => cds.cli.options.sap,
199
204
  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>',
200
205
  extendsApp: _extends,
206
+ npmWorkspaceRoot: () => {
207
+ if (this.cachedWorkspaceRoot) return this.cachedWorkspaceRoot
208
+ this.cachedWorkspaceRoot = execSync('npm prefix', { encoding: 'utf8', cwd: cds.root, stdio: 'pipe' }).trim()
209
+ return this.cachedWorkspaceRoot
210
+ },
211
+ isMonorepoMicroservice: function () {
212
+ return this.npmWorkspaceRoot() !== cds.root
213
+ },
201
214
  hasRoles: () => {}, roles: () => {}, // for xs-security generation
215
+ hasCustomRoleCollections: () => exists('xs-security.json') && !!JSON.parse(fs.readFileSync(path.join(cds.root, 'xs-security.json')))['role-collections']
202
216
  }
203
217
 
204
218
  // Automatically creates availability checks for `cds add` commands.
@@ -48,11 +48,7 @@ module.exports = async (data={}, csn, { headerOnly=false, separator=',' }={}) =>
48
48
  }
49
49
  else {
50
50
  if (i === 0) header.push(name)
51
- if (Array.isArray(value) || typeof value === 'object') { // `array of`/`many` and `cds.Map`
52
- value = JSON.stringify(value)
53
- }
54
- value = escape(value)
55
- record.push(value)
51
+ record.push(processValue(value))
56
52
  }
57
53
  }
58
54
  records.push(record.join(separator))
@@ -71,16 +67,23 @@ module.exports = async (data={}, csn, { headerOnly=false, separator=',' }={}) =>
71
67
  return value
72
68
  }
73
69
 
70
+ function processValue(v) {
71
+ if (Array.isArray(v) || typeof v === 'object') { // `array of`/`many` and `cds.Map`
72
+ return escape(JSON.stringify(v))
73
+ }
74
+ return escape(v)
75
+ }
76
+
74
77
  function resolveStruct(v, prefix) {
75
78
  return Object.entries(v).reduce((acc, [key, val]) => {
76
79
  //structs can be within structs
77
- if (typeof val === 'object') {
80
+ if (typeof val === 'object' && !Array.isArray(val)) {
78
81
  const {headers, records} = resolveStruct(val, prefix + '_' + key);
79
82
  acc.headers = acc.headers.concat(headers);
80
83
  acc.records = acc.records.concat(records);
81
84
  } else {
82
85
  acc.headers.push(prefix + '_' + key);
83
- acc.records.push(val);
86
+ acc.records.push(processValue(val));
84
87
  }
85
88
  return acc;
86
89
  }, {headers: [], records: []});
@@ -125,8 +125,9 @@ function dataForField(element, artifact, csn, record, data, parent, depth, refer
125
125
 
126
126
  if (element.is_struct) {
127
127
  let struct = {}
128
+ Object.defineProperty(struct, '$id', {value: record['$id'], enumerable: false})
128
129
  for (const el of element.elements) {
129
- struct[el.name] = dataForField(el, artifact, csn, record, data, null, depth+1, referenceData)
130
+ struct[el.name] = dataForField(el, artifact, csn, struct, data, null, depth+1, referenceData)
130
131
  }
131
132
  return struct
132
133
  }
@@ -176,7 +177,7 @@ function dataForField(element, artifact, csn, record, data, parent, depth, refer
176
177
  || element['@Communication.IsEmailAddress']
177
178
  || element['@cds.on.insert']?.['='] === '$user'
178
179
  || element['@cds.on.update']?.['='] === '$user') {
179
- return randomEmailAddress(element.name, record['$id'], csn)
180
+ return randomEmailAddress(element, record['$id'], csn)
180
181
  }
181
182
 
182
183
  let str = `${element.name}-${record['$id']}`
@@ -450,11 +451,13 @@ function randomFromList(list) {
450
451
  return list[randomNumber() % list.length]
451
452
  }
452
453
 
453
- function randomEmailAddress(firstName, num, csn) {
454
+ function randomEmailAddress(element, num, csn) {
454
455
  let addr = fakerValue('faker.internet.email', csn, false)
455
456
  if (addr) return addr
456
457
  const provider = randomFromList(['example.com', 'example.org', 'example.net'])
457
- return `${firstName}.${num.toString(36)}@${provider}`
458
+ let localPart = `${element.name}.${num.toString(36)}`
459
+ // -1 in substring for @
460
+ return (element.length ? localPart.substring(0, element.length - 1 - provider.length) : localPart) + `@${provider}`
458
461
  }
459
462
 
460
463
  function randomStrForRegex(regexStr, csn) {
@@ -1,5 +1,5 @@
1
1
  const cds = require('../../../cds')
2
- const { read, yaml: YAML } = cds.utils
2
+ const { read, exists, yaml: YAML } = cds.utils
3
3
  const { readProject } = require('../../projectReader')
4
4
  const { merge } = require('../../merge')
5
5
  const { srv4, enterpriseMessaging, xsuaa } = require('../../registries/mta')
@@ -37,7 +37,6 @@ module.exports = class EnterpriseMessagingTemplate extends require('../../plugin
37
37
  project.cloudevents = cds.cli.options.cloudevents
38
38
  await merge(__dirname, 'files/package.json.hbs').into(configFile, { with: project })
39
39
  }
40
- await merge(__dirname, 'files/event-mesh.json.hbs').into('event-mesh.json', { project })
41
40
  }
42
41
 
43
42
  async combine() {
@@ -76,5 +75,7 @@ module.exports = class EnterpriseMessagingTemplate extends require('../../plugin
76
75
  if (hasHelm || hasHelmUnifiedRuntime) {
77
76
  await merge(__dirname, 'files', 'values.yaml').into('chart/values.yaml')
78
77
  }
78
+
79
+ if (!exists('event-mesh.json')) await merge(__dirname, 'files/event-mesh.json.hbs').into('event-mesh.json', { project })
79
80
  }
80
81
  }
@@ -1,5 +1,5 @@
1
1
  const cds = require('../../../cds')
2
- const { read } = cds.utils
2
+ const { read, exists } = cds.utils
3
3
  const { readProject } = require('../../projectReader')
4
4
  const { merge } = require('../../merge')
5
5
  const { srv4, enterpriseMessaging } = require('../../registries/mta')
@@ -38,7 +38,6 @@ module.exports = class EnterpriseMessagingSharedTemplate extends require('../../
38
38
  project.cloudevents = cds.cli.options.cloudevents
39
39
  await merge(__dirname, 'files/package.json.hbs').into(configFile, { with: project })
40
40
  }
41
- await merge(__dirname, 'files/event-mesh.json.hbs').into('event-mesh.json', { project })
42
41
  }
43
42
 
44
43
  async combine() {
@@ -60,5 +59,7 @@ module.exports = class EnterpriseMessagingSharedTemplate extends require('../../
60
59
  if (hasHelm || hasHelmUnifiedRuntime) {
61
60
  await merge(__dirname, 'files/values.yaml').into('chart/values.yaml')
62
61
  }
62
+
63
+ if (!exists('event-mesh.json')) await merge(__dirname, 'files/event-mesh.json.hbs').into('event-mesh.json', { project })
63
64
  }
64
65
  }
@@ -43,15 +43,7 @@ runs:
43
43
  shell: bash
44
44
  - run: apt-get install kubectl -y
45
45
  shell: bash
46
- - run: curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
47
- shell: bash
48
- - run: sudo apt-get install apt-transport-https --yes
49
- shell: bash
50
- - run: echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
51
- shell: bash
52
- - run: sudo apt-get update
53
- shell: bash
54
- - run: sudo apt-get install helm
46
+ - run: curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
55
47
  shell: bash
56
48
  - run: npm install -g ctz
57
49
  shell: bash
@@ -2,6 +2,10 @@ name: Cloud Foundry
2
2
 
3
3
  on:
4
4
  workflow_call:
5
+ inputs:
6
+ environment:
7
+ default: Staging
8
+ type: string
5
9
  workflow_dispatch:
6
10
  push:
7
11
  branches:
@@ -22,10 +26,10 @@ jobs:
22
26
  runs-on: {{#sap}}[self-hosted, solinas]{{/sap}}{{^sap}}ubuntu-latest{{/sap}}
23
27
  steps:
24
28
  - uses: actions/checkout@v5
25
- - uses: actions/setup-node@v4
29
+ - uses: actions/setup-node@v5
26
30
  with:
27
31
  node-version: 22
28
- - uses: ./.github/actions/cf-setup # cap-js/cf-setup@v1
32
+ - uses: ./.github/actions/cf-setup
29
33
  with:
30
34
  cf-api: {{#literal}}${{ vars.CF_API }}{{/literal}}
31
35
  cf-org: {{#literal}}${{ vars.CF_ORG }}{{/literal}}
@@ -35,10 +39,6 @@ jobs:
35
39
  - run: npm install
36
40
  - run: npx cds up
37
41
 
38
- - uses: ./.github/actions/github-deployment
39
- with:
40
- app-name: {{#literal}}${{ env.APP_NAME }}{{/literal}}
41
-
42
42
  {{#hasApprouter}}
43
43
  - run: cf logs {{#literal}}"${{ env.APP_NAME }}"{{/literal}} --recent
44
44
  if: always()
@@ -53,3 +53,13 @@ jobs:
53
53
  - run: cf logs {{#literal}}"${{ env.APP_NAME }}-mtx"{{/literal}} --recent
54
54
  if: always()
55
55
  {{/hasMultitenancy}}
56
+
57
+ - name: Get application URL
58
+ id: route
59
+ shell: bash
60
+ run: |
61
+ {{#literal}}host=$(cf app "${APP_NAME}" | awk '/routes:/ {print $2}' | sed -E 's#^https?://##; s/,.*$//')
62
+ echo "url=https://$host" >> "$GITHUB_OUTPUT"{{/literal}}
63
+ environment:
64
+ name: {{#literal}}${{ inputs.environment || 'Staging' }}{{/literal}}
65
+ url: {{#literal}}${{ steps.route.outputs.url }}{{/literal}}
@@ -12,7 +12,7 @@ permissions:
12
12
  deployments: write
13
13
 
14
14
  concurrency:
15
- group: {{#literal}}deploy-${{ github.workflow }}-${{ github.head_ref || github.run_id }}{{/literal}}
15
+ group: {{#literal}}kyma-${{ github.workflow }}-${{ github.head_ref || github.run_id }}{{/literal}}
16
16
  cancel-in-progress: true
17
17
 
18
18
  env:
@@ -24,7 +24,7 @@ jobs:
24
24
  image: public.int.repositories.cloud.sap/ubuntu:24.04
25
25
  steps:
26
26
  - uses: actions/checkout@v5
27
- - uses: actions/setup-node@v4
27
+ - uses: actions/setup-node@v5
28
28
  with:
29
29
  node-version: 22
30
30
  - uses: ./.github/actions/kyma-setup
@@ -0,0 +1,30 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ release:
6
+ types: [published]
7
+
8
+ permissions:
9
+ contents: read
10
+ deployments: write
11
+
12
+ jobs:
13
+ tests:
14
+ uses: {{& githubSlug}}/.github/workflows/test.yaml@main
15
+ secrets: inherit
16
+ {{#hasMta}}
17
+ deploy-cf:
18
+ needs: [tests]
19
+ uses: {{& githubSlug}}/.github/workflows/cf.yaml@main
20
+ secrets: inherit
21
+ with:
22
+ environment: Production
23
+ {{/hasMta}}{{^hasMta}}{{#hasHelm}}
24
+ deploy-kyma:
25
+ needs: [tests]
26
+ uses: {{& githubSlug}}/.github/workflows/kyma.yaml@main
27
+ secrets: inherit
28
+ with:
29
+ environment: Production
30
+ {{/hasHelm}}{{/hasMta}}
@@ -16,7 +16,7 @@ jobs:
16
16
  tests:
17
17
  runs-on: {{#sap}}[self-hosted, solinas]{{/sap}}{{^sap}}ubuntu-latest{{/sap}}
18
18
  steps:
19
- - uses: actions/setup-node@v4
19
+ - uses: actions/setup-node@v5
20
20
  with:
21
21
  node-version: 22
22
22
  - uses: actions/checkout@v5
@@ -1,7 +1,10 @@
1
1
  const path = require('node:path')
2
+ const { execSync } = require('node:child_process')
3
+ const term = require('../../../util/term')
2
4
  const { readProject } = require('../../projectReader')
3
5
  const { renderAndCopy } = require('../../template')
4
6
  const cds = require('../../../cds')
7
+ const DEBUG = cds.log('add')._debug
5
8
  const { exists, copy } = cds.utils
6
9
 
7
10
  module.exports = class GitHubActionTemplate extends require('../../plugin') {
@@ -23,11 +26,27 @@ module.exports = class GitHubActionTemplate extends require('../../plugin') {
23
26
  }
24
27
 
25
28
  async run() {
26
- const out = '.github/workflows/test.yaml'
27
- if (!exists(out) || cds.cli.options.force) {
28
- await renderAndCopy(path.join(__dirname, 'files/workflows/test.yaml.hbs'), out, { sap: cds.cli.options.sap })
29
+ const test = `.github/workflows/test.yaml`
30
+ if (!exists(test) || cds.cli.options.force) {
31
+ await renderAndCopy(path.join(__dirname, 'files/workflows/test.yaml.hbs'), test, { sap: cds.cli.options.sap })
29
32
  } else {
30
- console.log('> skipping ' + out)
33
+ console.log('> skipping ' + test)
34
+ }
35
+
36
+ const release = `.github/workflows/release.yaml`
37
+ if (!exists(release) || cds.cli.options.force) {
38
+
39
+ let githubSlug
40
+ try {
41
+ githubSlug = execSync('git remote get-url origin', { stdio: 'pipe' }).toString().split('/').slice(-2).join('/').trim().replace(/\.git$/, '')
42
+ } catch (error) {
43
+ githubSlug = '<org/repo>'
44
+ // console.log(`\ncould not determine GitHub URL for the project – replace '<org/repo>' in ${release}`, DEBUG ? error : '')
45
+ }
46
+ const { hasMta, hasHelm } = readProject()
47
+ await renderAndCopy(path.join(__dirname, 'files/workflows/release.yaml.hbs'), release, { sap: cds.cli.options.sap, githubSlug, hasMta, hasHelm })
48
+ } else {
49
+ console.log('> skipping ' + release)
31
50
  }
32
51
  }
33
52
 
@@ -44,10 +63,6 @@ module.exports = class GitHubActionTemplate extends require('../../plugin') {
44
63
  if (force || !exists(cfSetup)) {
45
64
  await copy(path.join(__dirname, 'files/cf-setup'), cfSetup)
46
65
  }
47
- const cfGithub = '.github/actions/github-deployment'
48
- if (force || !exists(cfGithub)) {
49
- await copy(path.join(__dirname, 'files/github-deployment'), cfGithub)
50
- }
51
66
  }
52
67
  if (hasHelm) {
53
68
  const kyma = '.github/workflows/kyma.yaml'
@@ -94,6 +94,9 @@ module.exports = class Html5RepoTemplate extends require('../../plugin') {
94
94
  relationships.push({
95
95
  insert: [html5Runtime, 'name'],
96
96
  into: [approuter, 'requires', 'name'],
97
+ }, {
98
+ insert: [html5RepoHost, 'name'],
99
+ into: [approuter, 'requires', 'name'],
97
100
  })
98
101
  }
99
102
  if (hasMultitenancy) {
@@ -57,10 +57,10 @@ resources:
57
57
  service-plan: application
58
58
  config:
59
59
  display-name: {{appName}}
60
- {{#hasApprouter}}
61
60
  oauth2-configuration:
62
61
  token-policy:
63
62
  access-token-format: "jwt"
63
+ {{#hasApprouter}}
64
64
  redirect-uris:
65
65
  - ~{app-api/app-protocol}://*.~{app-api/app-uri}/login/callback
66
66
  - ~{app-api/app-protocol}://~{app-api/app-uri}/login/callback
@@ -11,7 +11,7 @@ build-parameters:
11
11
  - builder: custom
12
12
  commands:
13
13
  - npm ci
14
- - npx cds build --production
14
+ - npx cds build --production{{#isMonorepoMicroservice}} --ws-pack{{/isMonorepoMicroservice}}
15
15
  {{/isNodejs}}
16
16
  modules:
17
17
  - name: {{appName}}-srv
@@ -91,7 +91,7 @@ resources:
91
91
  appName: {{appName}}-${org}-${space}
92
92
  appCallbacks:
93
93
  dependenciesCallbacks:
94
- url: {{#isJava}}~{srv-api/srv-cert-url}/mt/sms/subscriptions/tenants/{app_tid}/dependencies{{/isJava}}{{#isNodejs}}~{mtx-api/mtx-cert-url}/-/cds/sms-provisioning/dependencies/{app_tid}{{/isNodejs}}
94
+ url: {{#isJava}}~{srv-api/srv-cert-url}/mt/sms/subscriptions/tenants/{app_tid}/dependencies{{/isJava}}{{#isNodejs}}~{mtx-api/mtx-cert-url}/-/cds/sms-provisioning/dependencies{{/isNodejs}}
95
95
  subscriptionCallbacks:
96
96
  url: {{#isJava}}~{srv-api/srv-cert-url}/mt/sms/subscriptions/tenants/{app_tid}{{/isJava}}{{#isNodejs}}~{mtx-api/mtx-cert-url}/-/cds/sms-provisioning/tenant/{app_tid}{{/isNodejs}}
97
97
  async:
@@ -50,7 +50,7 @@ subscription-manager:
50
50
  parameters:
51
51
  appCallbacks:
52
52
  dependenciesCallbacks:
53
- {{#literal}}url: https://{{ .Release.Name }}-sidecar-{{ .Release.Namespace }}.cert.{{ .Values.global.domain }}/-/cds/sms-provisioning/dependencies/{app_tid}{{/literal}}
53
+ {{#literal}}url: https://{{ .Release.Name }}-sidecar-{{ .Release.Namespace }}.cert.{{ .Values.global.domain }}/-/cds/sms-provisioning/dependencies{{/literal}}
54
54
  subscriptionCallbacks:
55
55
  {{#literal}}url: https://{{ .Release.Name }}-sidecar-{{ .Release.Namespace }}.cert.{{ .Values.global.domain }}/-/cds/sms-provisioning/tenant/{app_tid}{{/literal}}
56
56
  appName: {{appName}}
@@ -24,11 +24,12 @@ resources:
24
24
  config:
25
25
  xsappname: {{appName}}-${org}-${space}
26
26
  tenant-mode: {{#hasMultitenancy}}shared{{/hasMultitenancy}}{{^hasMultitenancy}}dedicated{{/hasMultitenancy}}
27
- {{#hasRoles}}
27
+ {{#hasRoles}}{{^hasCustomRoleCollections}}
28
28
  role-collections:
29
29
  {{#roles}}
30
30
  - name: '{{name}} ({{appName}} ${org}-${space})'
31
31
  description: 'generated'
32
32
  role-template-references: ['$XSAPPNAME.{{name}}']
33
33
  {{/roles}}
34
+ {{/hasCustomRoleCollections}}
34
35
  {{/hasRoles}}
@@ -67,11 +67,13 @@ module.exports = class XsuaaTemplate extends require('../../plugin') {
67
67
  project.hasRoles = xsSecurity['role-templates'].length > 0
68
68
  project.roles = xsSecurity['role-templates'].map(role => role)
69
69
 
70
- for (const role of xsSecurity['role-templates']) {
71
- additions.push({
72
- in: [xsuaa, 'parameters.role-collections'],
73
- where: { 'role-template-references': ['XSAPPNAME'+role.name] }
74
- })
70
+ if (!project.hasCustomRoleCollections) {
71
+ for (const role of xsSecurity['role-templates']) {
72
+ additions.push({
73
+ in: [xsuaa, 'parameters.role-collections'],
74
+ where: { 'role-template-references': ['XSAPPNAME'+role.name] }
75
+ })
76
+ }
75
77
  }
76
78
 
77
79
  await merge(__dirname, 'files/mta.yaml.hbs').into('mta.yaml', { project, additions, overwrites, relationships })
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "9.34.0",
2
+ "version": "9.35.0",
3
3
  "help": "\n# SYNOPSIS\n\n *cds lint* [options] file.js [file.js] [dir]\n\n Runs environment checks and/or checks the specified models\n based on the ESLint framework\n\n# OPTIONS\n \n Basic configuration:\n --no-config-lookup Disable look up for eslint.config.js\n -c, --config path::String Use this configuration instead of eslint.config.js, eslint.config.mjs, or eslint.config.cjs\n --inspect-config Open the config inspector with the current configuration\n --ext [String] Specify additional file extensions to lint\n --global [String] Define global variables\n --parser String Specify the parser to be used\n --parser-options Object Specify parser options\n \n Specify Rules and Plugins:\n --plugin [String] Specify plugins\n --rule Object Specify rules\n \n Fix Problems:\n --fix Automatically fix problems\n --fix-dry-run Automatically fix problems without saving the changes to the file system\n --fix-type Array Specify the types of fixes to apply (directive, problem, suggestion, layout)\n \n Ignore Files:\n --no-ignore Disable use of ignore files and patterns\n --ignore-pattern [String] Patterns of files to ignore\n \n Use stdin:\n --stdin Lint code provided on <STDIN> - default: false\n --stdin-filename String Specify filename to process STDIN as\n \n Handle Warnings:\n --quiet Report errors only - default: false\n --max-warnings Int Number of warnings to trigger nonzero exit code - default: -1\n \n Output:\n -o, --output-file path::String Specify file to write report to\n -f, --format String Use a specific output format - default: stylish\n --color, --no-color Force enabling/disabling of color\n \n Inline configuration comments:\n --no-inline-config Prevent comments from changing config or rules\n --report-unused-disable-directives Adds reported errors for unused eslint-disable and eslint-enable directives\n --report-unused-disable-directives-severity String Chooses severity level for reporting unused eslint-disable and eslint-enable directives - either: off, warn, error, 0, 1, or 2\n --report-unused-inline-configs String Adds reported errors for unused eslint inline config comments - either: off, warn, error, 0, 1, or 2\n \n Caching:\n --cache Only check changed files - default: false\n --cache-file path::String Path to the cache file. Deprecated: use --cache-location - default: .eslintcache\n --cache-location path::String Path to the cache file or directory\n --cache-strategy String Strategy to use for detecting changed files in the cache - either: metadata or content - default: metadata\n \n Suppressing Violations:\n --suppress-all Suppress all violations - default: false\n --suppress-rule [String] Suppress specific rules\n --suppressions-location path::String Specify the location of the suppressions file\n --prune-suppressions Prune unused suppressions - default: false\n --pass-on-unpruned-suppressions Ignore unused suppressions - default: false\n \n Miscellaneous:\n --init Run config initialization wizard - default: false\n --env-info Output execution environment information - default: false\n --no-error-on-unmatched-pattern Prevent errors when pattern is unmatched\n --exit-on-fatal-error Exit with exit code 2 in case of fatal error - default: false\n --no-warn-ignored Suppress warnings when the file list includes ignored files\n --pass-on-no-patterns Exit with exit code 0 in case no file patterns are passed\n --debug Output debugging information\n -h, --help Show help\n -v, --version Output the version number\n --print-config path::String Print the configuration for the given file\n --stats Add statistics to the lint report - default: false\n --flag [String] Enable a feature flag\n --mcp Start the ESLint MCP server\n --concurrency Int|String Number of linting threads, auto to choose automatically, off for no multithreading - default: off\n \n",
4
4
  "options": [
5
5
  "--config",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@sap/cds-dk",
3
- "version": "9.3.0",
3
+ "version": "9.3.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@sap/cds-dk",
9
- "version": "9.3.0",
9
+ "version": "9.3.1",
10
10
  "license": "SEE LICENSE IN LICENSE",
11
11
  "dependencies": {
12
12
  "@cap-js/asyncapi": "^1.0.0",
@@ -78,8 +78,8 @@
78
78
  }
79
79
  },
80
80
  "node_modules/@eslint/js": {
81
- "version": "9.34.0",
82
- "integrity": "sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw==",
81
+ "version": "9.35.0",
82
+ "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==",
83
83
  "license": "MIT",
84
84
  "peer": true,
85
85
  "engines": {
@@ -90,8 +90,8 @@
90
90
  }
91
91
  },
92
92
  "node_modules/@sap/cds": {
93
- "version": "9.3.0",
94
- "integrity": "sha512-2JaY4AlYvDP88DpZj5vo7B+9+r2ICmY5ktcCxHpnPoC9cmauYmXQtSn6gfuDwuBAWnFMSQEMu6qXz+7Yt8o7mQ==",
93
+ "version": "9.3.1",
94
+ "integrity": "sha512-xA9EN29X8HKaz83Aod1e3Bs6LRvqcCVoaTvCtyOup5rMYDQumcoZ7UOKH6NIUTeO0zOtafUiMHucMG+dBnq5XQ==",
95
95
  "license": "SEE LICENSE IN LICENSE",
96
96
  "dependencies": {
97
97
  "@sap/cds-compiler": "^6.1",
@@ -142,8 +142,8 @@
142
142
  }
143
143
  },
144
144
  "node_modules/@sap/cds-mtxs": {
145
- "version": "3.3.0",
146
- "integrity": "sha512-udIzKk+qUoYWLJKbGUJm0csuZP5r54msnTNy11bFDsuESio07ppgDkCIk+oGXCjsJLeoLZULCGgFvifLRi0ATg==",
145
+ "version": "3.3.1",
146
+ "integrity": "sha512-66yWxkVlqu5FsOHxDF8w2JJSlcbgtT2PTegBSECEq9+fjMOaqlxnBHpXXTODCUgK762Ad3kyCUZqW///gmpuMA==",
147
147
  "license": "SEE LICENSE IN LICENSE",
148
148
  "dependencies": {
149
149
  "@sap/hdi-deploy": "^5"
@@ -1213,8 +1213,8 @@
1213
1213
  "license": "MIT"
1214
1214
  },
1215
1215
  "node_modules/node-abi": {
1216
- "version": "3.75.0",
1217
- "integrity": "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==",
1216
+ "version": "3.77.0",
1217
+ "integrity": "sha512-DSmt0OEcLoK4i3NuscSbGjOf3bqiDEutejqENSplMSFA/gmB8mkED9G4pKWnPl7MDU4rSHebKPHeitpDfyH0cQ==",
1218
1218
  "license": "MIT",
1219
1219
  "optional": true,
1220
1220
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-dk",
3
- "version": "9.3.0",
3
+ "version": "9.3.1",
4
4
  "description": "Command line client and development toolkit for the SAP Cloud Application Programming Model",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "keywords": [
@@ -1,50 +0,0 @@
1
- name: GitHub Deployment for Cloud Foundry
2
- description: "Creates a GitHub deployment for your Cloud Foundry app"
3
-
4
- inputs:
5
- app-name:
6
- description: "Base name of the deployed CAP app"
7
- required: true
8
- environment:
9
- description: "Deployment environment name"
10
- required: true
11
-
12
- runs:
13
- using: "composite"
14
- steps:
15
- - name: Get deployed server URL
16
- id: get-url
17
- shell: bash
18
- run: |
19
- raw=$(cf app "${{ inputs.app-name }}" | awk '/routes:/ {print $2}')
20
- raw=$(echo "$raw" | sed -E 's#^https?://##')
21
- echo "url=https://$raw" >> "$GITHUB_OUTPUT"
22
-
23
- - name: Create GitHub Deployment
24
- uses: actions/github-script@v7
25
- env:
26
- URL: ${{ steps.get-url.outputs.url }}
27
- ENVIRONMENT: ${{ inputs.environment }}
28
- with:
29
- script: |
30
- const { owner, repo } = context.repo
31
- const ref = context.ref
32
- const url = process.env.URL
33
- const environment = process.env.ENVIRONMENT
34
-
35
- const deployment = await github.rest.repos.createDeployment({
36
- owner,
37
- repo,
38
- ref,
39
- required_contexts: [],
40
- environment
41
- })
42
-
43
- await github.rest.repos.createDeploymentStatus({
44
- owner,
45
- repo,
46
- deployment_id: deployment.data.id,
47
- state: 'success',
48
- environment_url: url,
49
- log_url: `https://github.com/${owner}/${repo}/actions/runs/${context.runId}`
50
- })