@sap/cds-dk 9.2.0 → 9.2.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 +17 -0
- package/bin/bind.js +2 -0
- package/bin/up.js +1 -1
- package/lib/bind/shared.js +4 -2
- package/lib/compile/to-xsuaa.js +11 -2
- package/lib/deploy/to-hana/hana.js +1 -1
- package/lib/deploy/to-hana/hdiDeployUtil.js +1 -1
- package/lib/init/projectReader.js +3 -1
- package/lib/init/template/attachments/index.js +1 -1
- package/lib/init/template/audit-logging/index.js +1 -1
- package/lib/init/template/github-actions/files/workflows/cf.yaml.hbs +4 -0
- package/lib/init/template/github-actions/index.js +0 -4
- package/lib/init/template/lint/index.js +6 -11
- package/lib/init/template/nodejs/files/.vscode/settings.json +2 -2
- package/lib/init/template/notifications/index.js +1 -1
- package/lib/init/template/postgres/index.js +1 -1
- package/lib/init/template/workzone-standard/index.js +1 -1
- package/lib/util/cf.js +7 -7
- package/npm-shrinkwrap.json +10 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,23 @@ 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.2.1 - 2025-08-22
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- `cds add github-actions` adds `if: always()` to the scripts retrieving Cloud Foundry logs.
|
|
14
|
+
- `cds up` uses a default timeout of 10 minutes for Helm upgrades.
|
|
15
|
+
- `cds bind` works out-of-the-box for PostgreSQL databases.
|
|
16
|
+
- `cds bind -a` gives warning if no services are bound to the targeted app.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- `cds add github-actions` won't try to merge a `cf-info` action if there's an existing `mta.yaml`.
|
|
21
|
+
- `cds add workzone` with missing `sap.app` config in `manifest.json` does not throw a `TypeError`.
|
|
22
|
+
- `cds compile --to xsuaa` generates roles for `@requires` in bound actions.
|
|
23
|
+
- `cds add lint` now adds proper configuration to enable linting of JavaScript and TypeScript files in VS Code.
|
|
24
|
+
- `cds add mta` does no longer adds services in `mta.yaml` for plugins coming from `devDependencies`.
|
|
25
|
+
|
|
9
26
|
## Version 9.2.0 - 2025-07-31
|
|
10
27
|
|
|
11
28
|
### Added
|
package/bin/bind.js
CHANGED
|
@@ -159,6 +159,8 @@ async function cds_bind(args, options) {
|
|
|
159
159
|
const resolvedServices = [], unresolvedServices = {}
|
|
160
160
|
const services = (await require('../lib/util/cf').services(app)).filter(s => Object.keys(s.credentials).length > 0)
|
|
161
161
|
|
|
162
|
+
if (!services) console.warn(`no services bound to app ${app} - nothing to bind`)
|
|
163
|
+
|
|
162
164
|
services.forEach(service => {
|
|
163
165
|
const type = service.label || service.type;
|
|
164
166
|
const requiredServiceEntry = Object.entries(cds.env.requires).find(([, requiredService]) => requiredService.kind === type && requiredService?.vcap?.name === service.name)
|
package/bin/up.js
CHANGED
|
@@ -116,7 +116,7 @@ async function up() {
|
|
|
116
116
|
|
|
117
117
|
run('npm i --package-lock')
|
|
118
118
|
await runDetectingError('ctz containerize.yaml --log --push', /^\[?ERROR\]?.*/m)
|
|
119
|
-
let helmUpgrade = `helm upgrade --install ${appName} ./gen/chart ${nsHelm} --wait --wait-for-jobs`
|
|
119
|
+
let helmUpgrade = `helm upgrade --install ${appName} ./gen/chart ${nsHelm} --wait --wait-for-jobs --timeout=10m`
|
|
120
120
|
if (hasXsuaa) helmUpgrade += ' --set-file xsuaa.jsonParameters=xs-security.json'
|
|
121
121
|
run(helmUpgrade)
|
|
122
122
|
run(`kubectl rollout status deployment ${appName}-srv ${nsKubectl} --timeout=8m`)
|
package/lib/bind/shared.js
CHANGED
|
@@ -23,7 +23,8 @@ const KindToRequiresNameMap = {
|
|
|
23
23
|
'enterprise-messaging-shared': 'messaging',
|
|
24
24
|
'redis-messaging': 'messaging',
|
|
25
25
|
'multitenancy': 'multitenancy',
|
|
26
|
-
'portal': 'portal'
|
|
26
|
+
'portal': 'portal',
|
|
27
|
+
'postgres': 'db'
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
const PreferredKinds = {
|
|
@@ -77,7 +78,8 @@ async function bind(options = { on: 'cf' }) {
|
|
|
77
78
|
resolved.name = options.serviceArg
|
|
78
79
|
} else if (kind) {
|
|
79
80
|
const requiresName = KindToRequiresNameMap[kind]
|
|
80
|
-
|
|
81
|
+
|
|
82
|
+
if (!requiresName) throw `unknown CDS service name for service ${bold(instance)} of kind ${bold(kind)} – please specify as argument for ${bold('cds bind')}`
|
|
81
83
|
resolved.name = requiresName
|
|
82
84
|
}
|
|
83
85
|
resolved.name ??= `custom-service:${instance || secret}`
|
package/lib/compile/to-xsuaa.js
CHANGED
|
@@ -60,8 +60,10 @@ module.exports = function compile_to_xsuaa (model, options) {
|
|
|
60
60
|
return findUserAttrInExpression(expr)
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
const authAnnotations = def => {
|
|
64
|
+
if (!def) return
|
|
65
|
+
|
|
66
|
+
let reqAnnotations = def['@requires']
|
|
65
67
|
if(!Array.isArray(reqAnnotations)) reqAnnotations=[reqAnnotations]
|
|
66
68
|
|
|
67
69
|
reqAnnotations.forEach(scope => {
|
|
@@ -84,7 +86,14 @@ module.exports = function compile_to_xsuaa (model, options) {
|
|
|
84
86
|
lattributes.forEach(attr => attributes[attr] = true)
|
|
85
87
|
})
|
|
86
88
|
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
cds.reflect(model).foreach(def => {
|
|
92
|
+
authAnnotations(def)
|
|
93
|
+
if (def.actions) Object.values(def.actions).forEach(authAnnotations)
|
|
94
|
+
if (def.functions) Object.values(def.functions).forEach(authAnnotations)
|
|
87
95
|
})
|
|
96
|
+
|
|
88
97
|
const roleTemplates = Object.keys(scopes).map((s) => {
|
|
89
98
|
return {
|
|
90
99
|
name: s,
|
|
@@ -250,7 +250,7 @@ spec:
|
|
|
250
250
|
if (/[^\w-_]+/g.exec(cfServiceInstanceName)) {
|
|
251
251
|
throw `Service name ${cfServiceInstanceName} must only contain alpha-numeric, hyphens, and underscores.`;
|
|
252
252
|
}
|
|
253
|
-
console.log(`
|
|
253
|
+
console.log(`using container ${bold(cfServiceInstanceName)}`);
|
|
254
254
|
|
|
255
255
|
const cfConfig = cfServiceInstanceMta?.parameters?.config;
|
|
256
256
|
const serviceInstance = await cfUtil.getOrCreateService('hana', 'hdi-shared', cfServiceInstanceName, cfConfig);
|
|
@@ -6,7 +6,7 @@ const HDI_DEPLOY_LIB = '@sap/hdi-deploy';
|
|
|
6
6
|
module.exports = new class HdiDeployUtil {
|
|
7
7
|
|
|
8
8
|
async deploy(dbDir, vcapEnv = {}, { autoUndeploy, parameter={} } = {}) {
|
|
9
|
-
console.log(`
|
|
9
|
+
console.log(`deploying to HANA from ${dbDir}`);
|
|
10
10
|
|
|
11
11
|
const { clean_env, deploy } = this._loadHdiDeployLib(dbDir);
|
|
12
12
|
|
|
@@ -47,12 +47,14 @@ module.exports = new class ProjectReader {
|
|
|
47
47
|
* Returns cds.env using 'production' profile by default as mta deployment is executed with having production profile set.
|
|
48
48
|
*/
|
|
49
49
|
env4(profile = 'production') {
|
|
50
|
+
const nodeEnv = process.env.NODE_ENV
|
|
50
51
|
const cdsEnv = process.env.CDS_ENV
|
|
51
|
-
process.env.CDS_ENV = profile
|
|
52
|
+
process.env.CDS_ENV = process.env.NODE_ENV = profile
|
|
52
53
|
try {
|
|
53
54
|
return cds.env.for('cds')
|
|
54
55
|
} finally {
|
|
55
56
|
cdsEnv ? process.env.CDS_ENV = cdsEnv : delete process.env.CDS_ENV
|
|
57
|
+
nodeEnv ? process.env.NODE_ENV = nodeEnv : delete process.env.NODE_ENV
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
|
|
@@ -13,7 +13,7 @@ module.exports = class AttachmentsTemplate extends require('../../plugin') {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
static hasInProduction(env) {
|
|
16
|
-
return !!env.requires?.attachments
|
|
16
|
+
return !!env.requires?.attachments || readProject().dependencies?.['@cap-js/attachments']
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
async canRun() {
|
|
@@ -12,7 +12,7 @@ module.exports = class AuditLoggingTemplate extends require('../../plugin') {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
static hasInProduction(env) {
|
|
15
|
-
return env.requires?.['audit-log']
|
|
15
|
+
return env.requires?.['audit-log'] || readProject().dependencies?.['@cap-js/audit-logging']
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
options() {
|
|
@@ -38,11 +38,15 @@ jobs:
|
|
|
38
38
|
|
|
39
39
|
{{#hasApprouter}}
|
|
40
40
|
- run: cf logs "${{ env.APP_NAME }}" --recent
|
|
41
|
+
if: always()
|
|
41
42
|
{{/hasApprouter}}
|
|
42
43
|
- run: cf logs "${{ env.APP_NAME }}-srv" --recent
|
|
44
|
+
if: always()
|
|
43
45
|
{{^hasMultitenancy}}
|
|
44
46
|
- run: cf logs "${{ env.APP_NAME }}-db-deployer" --recent
|
|
47
|
+
if: always()
|
|
45
48
|
{{/hasMultitenancy}}
|
|
46
49
|
{{#hasMultitenancy}}
|
|
47
50
|
- run: cf logs "${{ env.APP_NAME }}-mtx" --recent
|
|
51
|
+
if: always()
|
|
48
52
|
{{/hasMultitenancy}}
|
|
@@ -49,10 +49,6 @@ module.exports = class GitHubActionTemplate extends require('../../plugin') {
|
|
|
49
49
|
if (!exists(cfGithub) || force) {
|
|
50
50
|
await copy(path.join(__dirname, 'files/cf-github-deploy'), cfGithub)
|
|
51
51
|
}
|
|
52
|
-
const cfInfo = '.github/actions/cf-info'
|
|
53
|
-
if (!exists(cfInfo) || force) {
|
|
54
|
-
await copy(path.join(__dirname, 'files/cf-info'), cfInfo)
|
|
55
|
-
}
|
|
56
52
|
}
|
|
57
53
|
if (hasHelm) {
|
|
58
54
|
const kyma = '.github/workflows/kyma.yaml'
|
|
@@ -5,8 +5,11 @@ const cds = require('../../../cds')
|
|
|
5
5
|
const { merge } = require('../../merge')
|
|
6
6
|
const { dim, bold } = require('../../../util/term')
|
|
7
7
|
|
|
8
|
-
const
|
|
9
|
-
|
|
8
|
+
const ESLINT_LANGS_FOR_FILE_TYPE = {
|
|
9
|
+
cds: ['cds', 'csn'],
|
|
10
|
+
csv: ['csv', 'csv (semicolon)', 'tsv', 'tab'],
|
|
11
|
+
js: ['javascript'],
|
|
12
|
+
ts: ['typescript']
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
/**
|
|
@@ -54,15 +57,7 @@ module.exports = class LintTemplate extends require('../../plugin') {
|
|
|
54
57
|
await this.#addEslintPluginConfig()
|
|
55
58
|
|
|
56
59
|
// Generate VS Code extension settings
|
|
57
|
-
const
|
|
58
|
-
const extensions = new Set(ALLOWED_FILE_EXTENSIONS.map((ext) => path.extname(ext).replace('.', '')))
|
|
59
|
-
for (const ext of extensions) {
|
|
60
|
-
if (ext in VSCODE_FILE_ASSOCIATIONS) {
|
|
61
|
-
for (const assoc of VSCODE_FILE_ASSOCIATIONS[ext]) {
|
|
62
|
-
extensions.add(assoc)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
60
|
+
const extensions = new Set(Object.values(ESLINT_LANGS_FOR_FILE_TYPE).flat())
|
|
66
61
|
await io.sanitizeVscodeSettings(
|
|
67
62
|
path.join(cds.root, '.vscode/settings.json'),
|
|
68
63
|
Array.from(extensions),
|
|
@@ -15,7 +15,7 @@ module.exports = class NotificationsTemplate extends require('../../plugin') {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
static hasInProduction(env) {
|
|
18
|
-
return !!env.requires?.notifications
|
|
18
|
+
return !!env.requires?.notifications || readProject().dependencies?.['@cap-js/notifications']
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
async canRun() {
|
|
@@ -18,7 +18,7 @@ module.exports = class PostgresTemplate extends require('../../plugin') {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
static hasInProduction(env) {
|
|
21
|
-
return env.requires?.db?.kind === 'postgres'
|
|
21
|
+
return env.requires?.db?.kind === 'postgres' || readProject().dependencies?.['@cap-js/postgres']
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
async run() {
|
|
@@ -46,7 +46,7 @@ module.exports = class extends require('../../plugin') {
|
|
|
46
46
|
project.uiApp = p
|
|
47
47
|
const manifestPath = join(appPath, p, 'webapp/manifest.json')
|
|
48
48
|
const manifest = exists(manifestPath) ? await read(manifestPath) : {}
|
|
49
|
-
if (!manifest['sap.app']
|
|
49
|
+
if (!manifest['sap.app']?.crossNavigation?.inbounds) {
|
|
50
50
|
return merge(__dirname, 'files/manifest.json.hbs').into(join(appPath, p, 'webapp/manifest.json'), { project })
|
|
51
51
|
} else {
|
|
52
52
|
return merge({ 'sap.cloud': {
|
package/lib/util/cf.js
CHANGED
|
@@ -223,7 +223,7 @@ module.exports = new class CfUtil {
|
|
|
223
223
|
async env(app) {
|
|
224
224
|
const { spaceGuid: space_guids, orgGuid: organization_guids } = await this.target();
|
|
225
225
|
const apps = await this.curl('/v3/apps', { space_guids, organization_guids, names: app });
|
|
226
|
-
if (apps.resources.length < 1) throw `
|
|
226
|
+
if (apps.resources.length < 1) throw `cannot find app with name '${app}'`
|
|
227
227
|
const guid = apps.resources[0].guid;
|
|
228
228
|
return await this.curl('/v3/apps/' + guid + '/env', { space_guids, organization_guids, names: app });
|
|
229
229
|
}
|
|
@@ -257,15 +257,15 @@ module.exports = new class CfUtil {
|
|
|
257
257
|
if (!LOG._debug && serviceInstance?.last_operation?.description) {
|
|
258
258
|
throw serviceInstance.last_operation.description;
|
|
259
259
|
}
|
|
260
|
-
throw `
|
|
260
|
+
throw `the returned service reported state '${OPERATION_STATE_FAILED}'.\n${JSON.stringify(serviceInstance, null, 4)}`;
|
|
261
261
|
|
|
262
262
|
default:
|
|
263
|
-
console.error(`
|
|
263
|
+
console.error(`unsupported server response state '${serviceInstance?.last_operation?.state}' – waiting for next response`);
|
|
264
264
|
break;
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
-
throw `
|
|
268
|
+
throw `timeout occurred while getting service ${bold(serviceName)}`;
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
async getOrCreateService(serviceOfferingName, planName, serviceName, options) {
|
|
@@ -275,7 +275,7 @@ module.exports = new class CfUtil {
|
|
|
275
275
|
return probeService;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
console.log(`
|
|
278
|
+
console.log(`creating service ${bold(serviceName)} - please be patient...`);
|
|
279
279
|
|
|
280
280
|
const target = await this.target();
|
|
281
281
|
|
|
@@ -287,7 +287,7 @@ module.exports = new class CfUtil {
|
|
|
287
287
|
});
|
|
288
288
|
|
|
289
289
|
if (!servicePlan?.resources?.length) {
|
|
290
|
-
throw `
|
|
290
|
+
throw `no service plans found for ${planName} in service offering ${serviceOfferingName}`;
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
const body = {
|
|
@@ -353,7 +353,7 @@ module.exports = new class CfUtil {
|
|
|
353
353
|
throw `The returned binding reported state '${OPERATION_STATE_FAILED}'.\n${JSON.stringify(binding, null, 4)}`;
|
|
354
354
|
|
|
355
355
|
default:
|
|
356
|
-
console.error(`
|
|
356
|
+
console.error(`unsupported server response state '${binding?.last_operation?.state}'. Waiting for next response.`);
|
|
357
357
|
break;
|
|
358
358
|
}
|
|
359
359
|
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds-dk",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@sap/cds-dk",
|
|
9
|
-
"version": "9.2.
|
|
9
|
+
"version": "9.2.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.
|
|
82
|
-
"integrity": "sha512-
|
|
81
|
+
"version": "9.33.0",
|
|
82
|
+
"integrity": "sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==",
|
|
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.2.
|
|
94
|
-
"integrity": "sha512-
|
|
93
|
+
"version": "9.2.1",
|
|
94
|
+
"integrity": "sha512-0zjjZGlBvcJMyVj48hTs6Q22/w9hNnJR6O88rGoEj4R87uaP4uM5gFLf3PDnPDUwkAeveVHgJRnWPqDGqIMgvA==",
|
|
95
95
|
"license": "SEE LICENSE IN LICENSE",
|
|
96
96
|
"dependencies": {
|
|
97
97
|
"@sap/cds-compiler": "^6",
|
|
@@ -789,8 +789,8 @@
|
|
|
789
789
|
"license": "MIT"
|
|
790
790
|
},
|
|
791
791
|
"node_modules/follow-redirects": {
|
|
792
|
-
"version": "1.15.
|
|
793
|
-
"integrity": "sha512-
|
|
792
|
+
"version": "1.15.11",
|
|
793
|
+
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
|
794
794
|
"funding": [
|
|
795
795
|
{
|
|
796
796
|
"type": "individual",
|
|
@@ -1833,8 +1833,8 @@
|
|
|
1833
1833
|
}
|
|
1834
1834
|
},
|
|
1835
1835
|
"node_modules/yaml": {
|
|
1836
|
-
"version": "2.8.
|
|
1837
|
-
"integrity": "sha512-
|
|
1836
|
+
"version": "2.8.1",
|
|
1837
|
+
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
|
|
1838
1838
|
"license": "ISC",
|
|
1839
1839
|
"bin": {
|
|
1840
1840
|
"yaml": "bin.mjs"
|